mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 18:31:52 +00:00
* add documentation for ai agents * docs: consolidate CLAUDE.md and CONTRIBUTING.md, add style guidelines - Refactor CLAUDE.md to reference CONTRIBUTING.md for build/test/format info - Expand CONTRIBUTING.md with comprehensive build targets, env vars, and testing - Add code style guidelines section with conventional commits - Standardize SDK prettier config to use single quotes (matching web) - Add project-level Claude Code settings to disable co-author attribution * style(sdk): apply prettier with single quotes Run prettier across sdk/base and sdk/package to apply the standardized quote style (single quotes matching web). * docs: add USER.md for per-developer TODO filtering - Add agents/USER.md to .gitignore (contains user identifier) - Document session startup flow in CLAUDE.md: - Create USER.md if missing, prompting for identifier - Filter TODOs by @username tags - Offer relevant TODOs on session start * docs: add i18n documentation task to agent TODOs * docs: document i18n ID patterns in core/ Add agents/i18n-patterns.md covering rust-i18n setup, translation file format, t!() macro usage, key naming conventions, and locale selection. Remove completed TODO item and add reference in CLAUDE.md. * chore: clarify that all builds work on any OS with Docker
149 lines
4.6 KiB
TypeScript
149 lines
4.6 KiB
TypeScript
import { inputSpecSpec, InputSpecSpec } from './output'
|
|
import * as _I from '../index'
|
|
import { camelCase } from '../../scripts/oldSpecToBuilder'
|
|
import { deepMerge } from '../../../base/lib/util'
|
|
|
|
export type IfEquals<T, U, Y = unknown, N = never> =
|
|
(<G>() => G extends T ? 1 : 2) extends <G>() => G extends U ? 1 : 2 ? Y : N
|
|
export function testOutput<A, B>(): (c: IfEquals<A, B>) => null {
|
|
return () => null
|
|
}
|
|
|
|
/// Testing the types of the input spec
|
|
testOutput<InputSpecSpec['rpc']['enable'], boolean>()(null)
|
|
testOutput<InputSpecSpec['rpc']['username'], string>()(null)
|
|
testOutput<InputSpecSpec['rpc']['username'], string>()(null)
|
|
|
|
testOutput<InputSpecSpec['rpc']['advanced']['auth'], string[]>()(null)
|
|
testOutput<
|
|
InputSpecSpec['rpc']['advanced']['serialversion'],
|
|
'segwit' | 'non-segwit'
|
|
>()(null)
|
|
testOutput<InputSpecSpec['rpc']['advanced']['servertimeout'], number>()(null)
|
|
testOutput<
|
|
InputSpecSpec['advanced']['peers']['addnode'][0]['hostname'],
|
|
string | null
|
|
>()(null)
|
|
testOutput<
|
|
InputSpecSpec['testListUnion'][0]['union']['value']['name'],
|
|
string
|
|
>()(null)
|
|
testOutput<InputSpecSpec['testListUnion'][0]['union']['selection'], 'lnd'>()(
|
|
null,
|
|
)
|
|
testOutput<InputSpecSpec['mediasources'], Array<'filebrowser' | 'nextcloud'>>()(
|
|
null,
|
|
)
|
|
|
|
// @ts-expect-error Because enable should be a boolean
|
|
testOutput<InputSpecSpec['rpc']['enable'], string>()(null)
|
|
// prettier-ignore
|
|
// @ts-expect-error Expect that the string is the one above
|
|
testOutput<InputSpecSpec["testListUnion"][0]['selection']['selection'], "selection">()(null);
|
|
|
|
/// Here we test the output of the matchInputSpecSpec function
|
|
describe('Inputs', () => {
|
|
const validInput: InputSpecSpec = {
|
|
mediasources: ['filebrowser'],
|
|
testListUnion: [
|
|
{
|
|
union: { selection: 'lnd', value: { name: 'string' } },
|
|
},
|
|
],
|
|
rpc: {
|
|
enable: true,
|
|
bio: 'This is a bio',
|
|
username: 'test',
|
|
password: 'test',
|
|
advanced: {
|
|
auth: ['test'],
|
|
serialversion: 'segwit',
|
|
servertimeout: 6,
|
|
threads: 3,
|
|
workqueue: 9,
|
|
},
|
|
},
|
|
'zmq-enabled': false,
|
|
txindex: false,
|
|
wallet: { enable: false, avoidpartialspends: false, discardfee: 0.0001 },
|
|
advanced: {
|
|
mempool: {
|
|
maxmempool: 1,
|
|
persistmempool: true,
|
|
mempoolexpiry: 23,
|
|
mempoolfullrbf: true,
|
|
},
|
|
peers: {
|
|
listen: true,
|
|
onlyconnect: true,
|
|
onlyonion: true,
|
|
addnode: [
|
|
{
|
|
hostname: 'test',
|
|
port: 1,
|
|
},
|
|
],
|
|
},
|
|
dbcache: 5,
|
|
pruning: {
|
|
selection: 'disabled',
|
|
value: { disabled: {} },
|
|
},
|
|
blockfilters: {
|
|
blockfilterindex: false,
|
|
peerblockfilters: false,
|
|
},
|
|
bloomfilters: { peerbloomfilters: false },
|
|
},
|
|
}
|
|
|
|
test('test valid input', async () => {
|
|
const { validator } = await inputSpecSpec.build({} as any)
|
|
const output = validator.unsafeCast(validInput)
|
|
expect(output).toEqual(validInput)
|
|
})
|
|
test('test no longer care about the conversion of min/max and validating', async () => {
|
|
const { validator } = await inputSpecSpec.build({} as any)
|
|
validator.unsafeCast(
|
|
deepMerge({}, validInput, { rpc: { advanced: { threads: 0 } } }),
|
|
)
|
|
})
|
|
test('test errors should throw for number in string', async () => {
|
|
const { validator } = await inputSpecSpec.build({} as any)
|
|
expect(() =>
|
|
validator.unsafeCast(deepMerge({}, validInput, { rpc: { enable: 2 } })),
|
|
).toThrowError()
|
|
})
|
|
test('Test that we set serialversion to something not segwit or non-segwit', async () => {
|
|
const { validator } = await inputSpecSpec.build({} as any)
|
|
expect(() =>
|
|
validator.unsafeCast(
|
|
deepMerge({}, validInput, {
|
|
rpc: { advanced: { serialversion: 'testing' } },
|
|
}),
|
|
),
|
|
).toThrowError()
|
|
})
|
|
})
|
|
|
|
describe('camelCase', () => {
|
|
test("'EquipmentClass name'", () => {
|
|
expect(camelCase('EquipmentClass name')).toEqual('equipmentClassName')
|
|
})
|
|
test("'Equipment className'", () => {
|
|
expect(camelCase('Equipment className')).toEqual('equipmentClassName')
|
|
})
|
|
test("'equipment class name'", () => {
|
|
expect(camelCase('equipment class name')).toEqual('equipmentClassName')
|
|
})
|
|
test("'Equipment Class Name'", () => {
|
|
expect(camelCase('Equipment Class Name')).toEqual('equipmentClassName')
|
|
})
|
|
test("'hyphen-name-format'", () => {
|
|
expect(camelCase('hyphen-name-format')).toEqual('hyphenNameFormat')
|
|
})
|
|
test("'underscore_name_format'", () => {
|
|
expect(camelCase('underscore_name_format')).toEqual('underscoreNameFormat')
|
|
})
|
|
})
|