@voxgig/sdkgen 4.15.0 → 4.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/bin/voxgig-sdkgen +2 -2
- package/dist/action/action.js +2 -2
- package/dist/action/action.js.map +1 -1
- package/dist/action/check.js +9 -8
- package/dist/action/check.js.map +1 -1
- package/dist/action/dispatch.js +4 -4
- package/dist/action/dispatch.js.map +1 -1
- package/dist/action/doctor.js +16 -15
- package/dist/action/doctor.js.map +1 -1
- package/dist/action/edition.d.ts +4 -0
- package/dist/action/{docs.js → edition.js} +57 -54
- package/dist/action/edition.js.map +1 -0
- package/dist/action/kind.d.ts +1 -2
- package/dist/action/kind.js +22 -38
- package/dist/action/kind.js.map +1 -1
- package/dist/action/package.js +17 -16
- package/dist/action/package.js.map +1 -1
- package/dist/action/resolve.d.ts +3 -1
- package/dist/action/resolve.js +29 -11
- package/dist/action/resolve.js.map +1 -1
- package/dist/admin/status.d.ts +43 -0
- package/dist/admin/status.js +161 -0
- package/dist/admin/status.js.map +1 -0
- package/dist/cmp/Test.js +11 -0
- package/dist/cmp/Test.js.map +1 -1
- package/dist/helpers/kindCollection.d.ts +1 -0
- package/dist/helpers/kindCollection.js +14 -0
- package/dist/helpers/kindCollection.js.map +1 -0
- package/dist/helpers/modelcheck.d.ts +1 -1
- package/dist/helpers/modelcheck.js +13 -3
- package/dist/helpers/modelcheck.js.map +1 -1
- package/dist/helpers/shipped.js +2 -3
- package/dist/helpers/shipped.js.map +1 -1
- package/dist/helpers/testPolicy.d.ts +1 -1
- package/dist/helpers/testPolicy.js +6 -37
- package/dist/helpers/testPolicy.js.map +1 -1
- package/dist/sdkgen.d.ts +7 -1
- package/dist/sdkgen.js +146 -89
- package/dist/sdkgen.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utility.js +9 -1
- package/dist/utility.js.map +1 -1
- package/model/sdkgen.aon +5 -52
- package/package.json +1 -1
- package/project/.sdk/src/cmp/go/Config_go.ts +4 -4
- package/project/.sdk/src/cmp/go/utility_go.ts +10 -2
- package/project/.sdk/src/cmp/js/Package_js.ts +5 -1
- package/project/.sdk/src/cmp/js/TestDirect_js.ts +11 -7
- package/project/.sdk/src/cmp/js/TestEntity_js.ts +16 -2
- package/project/.sdk/src/cmp/js/TestLive_js.ts +32 -0
- package/project/.sdk/src/cmp/js/Test_js.ts +2 -0
- package/project/.sdk/src/cmp/js/fragment/Direct.test.fragment.js +1 -1
- package/project/.sdk/src/cmp/js/fragment/Entity.test.fragment.js +4 -2
- package/project/.sdk/src/cmp/php/ReadmeExamplesTest_php.ts +30 -9
- package/project/.sdk/src/cmp/php/ReadmeHowto_php.ts +8 -3
- package/project/.sdk/src/cmp/php/ReadmeQuick_php.ts +5 -4
- package/project/.sdk/src/cmp/php/ReadmeTopQuick_php.ts +2 -2
- package/project/.sdk/src/cmp/ts/Package_ts.ts +5 -1
- package/project/.sdk/src/cmp/ts/ReadmeHowto_ts.ts +5 -0
- package/project/.sdk/src/cmp/ts/TestDirect_ts.ts +15 -11
- package/project/.sdk/src/cmp/ts/TestEntity_ts.ts +13 -16
- package/project/.sdk/src/cmp/ts/TestLive_ts.ts +32 -0
- package/project/.sdk/src/cmp/ts/Test_ts.ts +2 -0
- package/project/.sdk/src/cmp/ts/fragment/Direct.test.fragment.ts +1 -0
- package/project/.sdk/src/cmp/ts/fragment/Entity.test.fragment.ts +2 -0
- package/project/.sdk/tm/csharp/test/feature/secrets/SecretsFeatureTest.cs +9 -2
- package/project/.sdk/tm/js/test/live-contract.js +183 -0
- package/project/.sdk/tm/js/test/live-entity.js +169 -0
- package/project/.sdk/tm/js/test/live-runner.js +129 -0
- package/project/.sdk/tm/js/test/live-scenarios.js +142 -0
- package/project/.sdk/tm/js/test/utility.js +84 -0
- package/project/.sdk/tm/ts/test/live-contract.ts +104 -0
- package/project/.sdk/tm/ts/test/live-entity.ts +142 -0
- package/project/.sdk/tm/ts/test/live-runner.ts +166 -0
- package/project/.sdk/tm/ts/test/live-scenarios.ts +112 -0
- package/project/.sdk/tm/ts/test/utility.ts +1 -2
- package/project/sdkgen-package.json +1 -1
- package/src/action/action.ts +2 -2
- package/src/action/check.ts +3 -2
- package/src/action/dispatch.ts +4 -4
- package/src/action/doctor.ts +10 -9
- package/src/action/{docs.ts → edition.ts} +56 -53
- package/src/action/kind.ts +12 -33
- package/src/action/package.ts +4 -3
- package/src/action/resolve.ts +26 -2
- package/src/admin/status.ts +124 -0
- package/src/cmp/Test.ts +13 -1
- package/src/helpers/kindCollection.ts +11 -0
- package/src/helpers/modelcheck.ts +10 -3
- package/src/helpers/shipped.ts +2 -3
- package/src/helpers/testPolicy.ts +7 -45
- package/src/sdkgen.ts +189 -93
- package/src/utility.ts +8 -2
- package/dist/action/docs.d.ts +0 -4
- package/dist/action/docs.js.map +0 -1
- package/dist/cmp/Docs.d.ts +0 -4
- package/dist/cmp/Docs.js +0 -98
- package/dist/cmp/Docs.js.map +0 -1
- package/dist/cmp/ExternalDocs.d.ts +0 -2
- package/dist/cmp/ExternalDocs.js +0 -43
- package/dist/cmp/ExternalDocs.js.map +0 -1
- package/src/cmp/Docs.ts +0 -125
- package/src/cmp/ExternalDocs.ts +0 -54
package/src/action/package.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { kindCollection } from '../helpers/kindCollection'
|
|
1
2
|
// `package add` / `package list` — the whole-package verbs.
|
|
2
3
|
//
|
|
3
4
|
// See docs/design/sdkgen-packages.md §9.
|
|
@@ -78,7 +79,7 @@ const CMD_MAP: any = Object.assign(Object.create(null), {
|
|
|
78
79
|
// reads them at generate time rather than at add time, installing it last
|
|
79
80
|
// keeps the add log in the order a reader would expect and leaves the model
|
|
80
81
|
// complete before anything reads it.
|
|
81
|
-
const ADD_ORDER = ['target', 'feature', '
|
|
82
|
+
const ADD_ORDER = ['target', 'feature', 'edition']
|
|
82
83
|
|
|
83
84
|
|
|
84
85
|
async function action_package(
|
|
@@ -663,7 +664,7 @@ function installedFrom(pkgname: string, actx: ActionContext): Installed[] {
|
|
|
663
664
|
const found: Installed[] = []
|
|
664
665
|
|
|
665
666
|
for (const kind of Object.keys(KINDS).sort()) {
|
|
666
|
-
const items =
|
|
667
|
+
const items = kindCollection({ main: { [KIT]: kit } }, kind)
|
|
667
668
|
|
|
668
669
|
for (const name of Object.keys(items).sort()) {
|
|
669
670
|
const item = items[name]
|
|
@@ -1078,7 +1079,7 @@ async function cmd_package_list(
|
|
|
1078
1079
|
const groups: Record<string, any[]> = Object.create(null)
|
|
1079
1080
|
|
|
1080
1081
|
for (const kind of Object.keys(KINDS).sort()) {
|
|
1081
|
-
const items =
|
|
1082
|
+
const items = kindCollection({ main: { [KIT]: kit } }, kind)
|
|
1082
1083
|
|
|
1083
1084
|
for (const name of Object.keys(items).sort()) {
|
|
1084
1085
|
const item = items[name]
|
package/src/action/resolve.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { kindCollection } from '../helpers/kindCollection'
|
|
1
2
|
// Where a `<kind> add <ref>` gets its definition from.
|
|
2
3
|
//
|
|
3
4
|
// One resolver for every KIND of thing an add can install — targets today,
|
|
@@ -59,6 +60,9 @@ function lastSegment(ref: string): string {
|
|
|
59
60
|
|
|
60
61
|
|
|
61
62
|
function resolveSource(ref: string, kind: string, ctx$: any): Source {
|
|
63
|
+
// Registration and copying must resolve a bare resync name identically.
|
|
64
|
+
const declared = kindCollection(ctx$.model, kind)?.[ref]
|
|
65
|
+
ref = (isBare(ref) && recordedRef(declared, ref)) || ref
|
|
62
66
|
const root = ctx$.folder
|
|
63
67
|
const fs = ctx$.fs()
|
|
64
68
|
|
|
@@ -275,7 +279,7 @@ function registerInstalled(kind: string, refs: string[], ctx$: any) {
|
|
|
275
279
|
return
|
|
276
280
|
}
|
|
277
281
|
|
|
278
|
-
const items =
|
|
282
|
+
const items = kindCollection(ctx$.model, kind, true)
|
|
279
283
|
|
|
280
284
|
for (const ref of refs) {
|
|
281
285
|
let source: Source
|
|
@@ -317,7 +321,7 @@ function registerInstalled(kind: string, refs: string[], ctx$: any) {
|
|
|
317
321
|
function nameConflict(
|
|
318
322
|
kind: string, source: Source, ctx$: any,
|
|
319
323
|
): { package?: string, base?: string } | undefined {
|
|
320
|
-
const declared: any = ctx$.model
|
|
324
|
+
const declared: any = kindCollection(ctx$.model, kind)?.[source.name]
|
|
321
325
|
|
|
322
326
|
if (null == declared || 'object' !== typeof declared) {
|
|
323
327
|
return undefined
|
|
@@ -423,6 +427,24 @@ function providesStill(
|
|
|
423
427
|
}
|
|
424
428
|
|
|
425
429
|
|
|
430
|
+
function recordedRef(declared: any, name: string): string | undefined {
|
|
431
|
+
if (null == declared?.base || '' === declared.base) {
|
|
432
|
+
return undefined
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const origname = declared.origname || name
|
|
436
|
+
|
|
437
|
+
return Path.join(declared.base, '..', origname) +
|
|
438
|
+
(origname === name ? '' : '~' + name)
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
// A bare NAME, as opposed to a ref that locates a source.
|
|
443
|
+
function isBare(ref: string): boolean {
|
|
444
|
+
return !ref.includes('/') && !ref.includes(Path.sep)
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
|
|
426
448
|
function normaliseBase(base: string): string {
|
|
427
449
|
return Path.normalize(String(base ?? '')).split(Path.sep).join('/')
|
|
428
450
|
}
|
|
@@ -439,6 +461,8 @@ export type {
|
|
|
439
461
|
|
|
440
462
|
export {
|
|
441
463
|
resolveSource,
|
|
464
|
+
recordedRef,
|
|
465
|
+
isBare,
|
|
442
466
|
registerInstalled,
|
|
443
467
|
nameConflict,
|
|
444
468
|
lastSegment,
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import Fs from 'node:fs'
|
|
2
|
+
import Path from 'node:path'
|
|
3
|
+
import { spawnSync } from 'node:child_process'
|
|
4
|
+
|
|
5
|
+
function command(cwd: string, bin: string, args: string[]) {
|
|
6
|
+
return spawnSync(bin, args, { cwd, encoding: 'utf8', timeout: 15000, windowsHide: true, env: { ...process.env, GIT_OPTIONAL_LOCKS: '0' } })
|
|
7
|
+
}
|
|
8
|
+
function git(cwd: string, args: string[]): string | null {
|
|
9
|
+
const result = command(cwd, 'git', args)
|
|
10
|
+
return result.status === 0 ? result.stdout.trim() : null
|
|
11
|
+
}
|
|
12
|
+
function directory(path: string): boolean {
|
|
13
|
+
return Fs.existsSync(path) && Fs.statSync(path).isDirectory()
|
|
14
|
+
}
|
|
15
|
+
function entries(value: any): [string, any][] {
|
|
16
|
+
return Object.entries(value || {}).filter(([name]) => !name.includes('$')).sort(([a], [b]) => a.localeCompare(b))
|
|
17
|
+
}
|
|
18
|
+
function workingTree(folder: string) {
|
|
19
|
+
if (!directory(folder)) return 'missing'
|
|
20
|
+
const state = git(folder, ['status', '--porcelain=v1', '--untracked-files=normal', '--', '.'])
|
|
21
|
+
return state === null ? 'not a git repository' : state ? 'modified' : 'clean'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Read the compiled model and working trees. Never fetch, build, test, or publish.
|
|
25
|
+
export function repositoryStatus(root: string) {
|
|
26
|
+
root = Path.resolve(root)
|
|
27
|
+
const sdk = Path.join(root, '.sdk')
|
|
28
|
+
if (!directory(sdk)) throw new Error('Expected an SDK repository containing .sdk: ' + root)
|
|
29
|
+
const file = Path.join(sdk, 'model/sdk.json')
|
|
30
|
+
let model: any, modelError: string | undefined
|
|
31
|
+
if (Fs.existsSync(file)) {
|
|
32
|
+
try {
|
|
33
|
+
model = JSON.parse(Fs.readFileSync(file, 'utf8'))
|
|
34
|
+
if (!model?.main?.kit) throw new Error('missing main.kit')
|
|
35
|
+
} catch (err: any) { modelError = 'Invalid compiled model: ' + err.message }
|
|
36
|
+
}
|
|
37
|
+
const kit = model?.main?.kit || {}
|
|
38
|
+
const upstream = git(root, ['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{upstream}'])
|
|
39
|
+
const counts = upstream && git(root, ['rev-list', '--left-right', '--count', 'HEAD...@{upstream}'])
|
|
40
|
+
const [ahead, behind] = counts ? counts.split(/\s+/).map(Number) : [null, null]
|
|
41
|
+
const packages = ['sdkgen', 'apidef', 'model', 'docgen'].map(name => {
|
|
42
|
+
const file = Path.join(sdk, 'node_modules/@voxgig', name, 'package.json')
|
|
43
|
+
try { return { name: '@voxgig/' + name, version: JSON.parse(Fs.readFileSync(file, 'utf8')).version } }
|
|
44
|
+
catch { return { name: '@voxgig/' + name, version: 'not installed' } }
|
|
45
|
+
})
|
|
46
|
+
return {
|
|
47
|
+
root, name: model?.name || Path.basename(root),
|
|
48
|
+
repository: {
|
|
49
|
+
branch: git(root, ['branch', '--show-current']) || 'detached or not initialised',
|
|
50
|
+
commit: git(root, ['rev-parse', '--short', 'HEAD']), state: workingTree(root), upstream, ahead, behind,
|
|
51
|
+
},
|
|
52
|
+
model: { path: file, compiled: !!model && !modelError, error: modelError,
|
|
53
|
+
generatedAt: Fs.existsSync(file) ? Fs.statSync(file).mtime.toISOString() : null },
|
|
54
|
+
toolchain: { node: process.version, packages },
|
|
55
|
+
targets: entries(kit.target).map(([name, target]) => {
|
|
56
|
+
const folder = Path.resolve(root, target.output?.path || name)
|
|
57
|
+
const present = directory(folder)
|
|
58
|
+
return { name, active: target.active !== false, path: folder, present,
|
|
59
|
+
state: workingTree(folder), readme: Fs.existsSync(Path.join(folder, 'README.md')),
|
|
60
|
+
version: target.publish?.version || null,
|
|
61
|
+
publication: target.publish?.registry?.state || 'not recorded',
|
|
62
|
+
}
|
|
63
|
+
}),
|
|
64
|
+
editions: entries(kit.doc?.edition).map(([name, edition]) => ({ name,
|
|
65
|
+
active: kit.doc?.active !== false && edition.active !== false, kind: edition.kind,
|
|
66
|
+
path: edition.output?.path || null,
|
|
67
|
+
present: !!edition.output?.path && Fs.existsSync(Path.resolve(root, edition.output.path)),
|
|
68
|
+
})),
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function githubStatus(root: string) {
|
|
73
|
+
const run = (args: string[]) => {
|
|
74
|
+
const result = command(root, 'gh', args)
|
|
75
|
+
if (result.status !== 0) throw new Error(result.error?.message || result.stderr.trim() || 'GitHub query failed')
|
|
76
|
+
return JSON.parse(result.stdout)
|
|
77
|
+
}
|
|
78
|
+
const repository = run(['repo', 'view', '--json', 'nameWithOwner,url'])
|
|
79
|
+
const host = new URL(repository.url).hostname
|
|
80
|
+
const pages = command(root, 'gh', ['api', '--hostname', host, 'repos/' + repository.nameWithOwner + '/pages'])
|
|
81
|
+
let site: any
|
|
82
|
+
try { site = JSON.parse(pages.stdout || '{}') } catch { site = {} }
|
|
83
|
+
if (pages.status !== 0 && String(site.status) !== '404') throw new Error(pages.error?.message || pages.stderr.trim() || 'Pages query failed')
|
|
84
|
+
return { repository: repository.nameWithOwner,
|
|
85
|
+
pages: pages.status === 0 ? { url: site.html_url, status: site.status, buildType: site.build_type } : { status: 'not configured' },
|
|
86
|
+
runs: run(['run', 'list', '--limit', '5', '--json', 'workflowName,status,conclusion,headBranch,url']),
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function main(args = process.argv.slice(2)): number {
|
|
91
|
+
const root = args.shift()
|
|
92
|
+
if (args.includes('--help') || root === '--help') {
|
|
93
|
+
console.log('Usage: .sdk/admin/status.sh [--json] [--github]\nRead local repository, SDK, and documentation status. --github also reads Pages and recent CI runs.\nBuild and test results are not inferred from generated files. No commands that change the repository are run.')
|
|
94
|
+
return 0
|
|
95
|
+
}
|
|
96
|
+
if (!root || args.some(arg => !['--json', '--github'].includes(arg))) throw new Error('Usage: status.sh [--json] [--github]')
|
|
97
|
+
const report: any = repositoryStatus(root)
|
|
98
|
+
let failed = !!report.model.error
|
|
99
|
+
if (args.includes('--github')) {
|
|
100
|
+
try { report.github = githubStatus(report.root) }
|
|
101
|
+
catch (err: any) { report.github = { error: err.message }; failed = true }
|
|
102
|
+
}
|
|
103
|
+
if (args.includes('--json')) console.log(JSON.stringify(report, null, 2))
|
|
104
|
+
else {
|
|
105
|
+
console.log('Repository: ' + report.root)
|
|
106
|
+
console.log('Git: ' + report.repository.branch + ' | ' + report.repository.state + ' | ' + (report.repository.commit || 'no commits'))
|
|
107
|
+
console.log('Upstream: ' + (report.repository.upstream ? report.repository.upstream + ' | ahead ' + report.repository.ahead + ', behind ' + report.repository.behind + ' (local tracking refs)' : 'not configured'))
|
|
108
|
+
console.log('Model: ' + (report.model.error || (report.model.compiled ? 'compiled ' + report.model.generatedAt : 'not generated; run npm run generate from .sdk')))
|
|
109
|
+
console.log('Toolchain: Node ' + report.toolchain.node + '; ' + report.toolchain.packages.map((p: any) => p.name + ' ' + p.version).join('; '))
|
|
110
|
+
console.log('\nSDKs and tools (publication state comes from the model):')
|
|
111
|
+
for (const t of report.targets) console.log(' ' + t.name + ' | ' + (t.active ? 'active' : 'inactive') + ' | ' + t.state + ' | version ' + (t.version || 'not recorded') + ' | ' + t.publication + ' | ' + t.path)
|
|
112
|
+
if (!report.targets.length) console.log(' No targets in the compiled model.')
|
|
113
|
+
console.log('\nDocumentation:')
|
|
114
|
+
for (const e of report.editions) console.log(' ' + e.name + ' | ' + (e.active ? 'active' : 'inactive') + ' | ' + (e.present ? 'present' : 'missing') + ' | ' + (e.path || 'no output path'))
|
|
115
|
+
if (!report.editions.length) console.log(' No editions in the compiled model.')
|
|
116
|
+
console.log('\nLocal status does not run builds/tests or check registries. Use --github for remote CI and Pages status.')
|
|
117
|
+
if (report.github) console.log('\nGitHub:\n' + JSON.stringify(report.github, null, 2))
|
|
118
|
+
}
|
|
119
|
+
return failed ? 1 : 0
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (require.main === module) {
|
|
123
|
+
try { process.exitCode = main() } catch (err: any) { console.error(err.message); process.exitCode = 1 }
|
|
124
|
+
}
|
package/src/cmp/Test.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
import {
|
|
3
|
-
cmp,
|
|
3
|
+
cmp, File, Content,
|
|
4
4
|
} from 'jostraca'
|
|
5
5
|
|
|
6
6
|
import { requirePath } from '../utility'
|
|
@@ -19,6 +19,18 @@ const Test = cmp(function Test(props: any) {
|
|
|
19
19
|
const { model, log } = ctx$
|
|
20
20
|
const stdrep = ensureStdrep(ctx$)
|
|
21
21
|
|
|
22
|
+
const points = Object.values(model.main.kit.entity || {}).flatMap((entity: any) =>
|
|
23
|
+
Object.values(entity.op || {}).flatMap((op: any) => op.points || [])) as any[]
|
|
24
|
+
if (points.some(point => point.contract && JSON.parse(point.contract.json).live)) {
|
|
25
|
+
const supported = ['ts', 'js'].includes(target.name)
|
|
26
|
+
File({ name: 'live-coverage.json' }, () => Content(JSON.stringify({
|
|
27
|
+
version: 1, target: target.name, scenarios: supported ? 'supported' : 'unsupported',
|
|
28
|
+
points: points.map(point => point.contract?.id || point.method + ' ' + point.orig),
|
|
29
|
+
...(!supported ? { reason: 'This target does not yet execute declarative live recipes. Its existing tests do not establish full operation coverage.' } : {}),
|
|
30
|
+
}, null, 2)))
|
|
31
|
+
if (!supported) log.warn({ point: 'live-scenarios-unsupported', note: 'Declarative live recipes are not executed by target ' + target.name })
|
|
32
|
+
}
|
|
33
|
+
|
|
22
34
|
const Test_sdk = requirePath(ctx$, `./cmp/${target.name}/Test_${target.name}`)
|
|
23
35
|
Test_sdk['Test']({ model, target, stdrep })
|
|
24
36
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { KIT } from '../types'
|
|
2
|
+
|
|
3
|
+
// Physical kind names and model namespaces are independent.
|
|
4
|
+
export function kindCollection(model: any, kind: string, create = false): any {
|
|
5
|
+
const kit = create ? (model.main ??= {})[KIT] ??= {} : model?.main?.[KIT]
|
|
6
|
+
if (kind === 'edition') {
|
|
7
|
+
const doc = create ? kit.doc ??= {} : kit?.doc
|
|
8
|
+
return create ? doc.edition ??= {} : doc?.edition ?? {}
|
|
9
|
+
}
|
|
10
|
+
return create ? kit[kind] ??= {} : kit?.[kind] ?? {}
|
|
11
|
+
}
|
|
@@ -33,6 +33,8 @@
|
|
|
33
33
|
// project's own file, not the package's.
|
|
34
34
|
|
|
35
35
|
import { Aontu } from 'aontu'
|
|
36
|
+
import { createRequire } from 'node:module'
|
|
37
|
+
import Path from 'node:path'
|
|
36
38
|
|
|
37
39
|
import { schemaFile } from './shipped'
|
|
38
40
|
|
|
@@ -112,8 +114,8 @@ function slashComments(text: string): { line: number, text: string }[] {
|
|
|
112
114
|
// A FRESH INSTANCE each time: the option call mutates the instance's jsonic,
|
|
113
115
|
// so a cached one would leak its configuration into the bare compile that is
|
|
114
116
|
// deliberately paired with it.
|
|
115
|
-
function strictAontu(): any {
|
|
116
|
-
const aontu: any = new Aontu()
|
|
117
|
+
function strictAontu(options?: any): any {
|
|
118
|
+
const aontu: any = new Aontu(options)
|
|
117
119
|
aontu.lang.jsonic.options({ comment: { def: { slash: null, multi: null } } })
|
|
118
120
|
return aontu
|
|
119
121
|
}
|
|
@@ -186,7 +188,12 @@ function compileModel(
|
|
|
186
188
|
includeLine(schemaFile()) + '\n' + src : src
|
|
187
189
|
|
|
188
190
|
try {
|
|
189
|
-
|
|
191
|
+
// Resolve package includes from the model being checked, including native
|
|
192
|
+
// package self-references. The SDK toolchain's dependencies are unrelated.
|
|
193
|
+
const localRequire = Object.assign(createRequire(Path.resolve(path)), { main: require.main })
|
|
194
|
+
// Aontu forwards this runtime resolver option to Lang; its public type omits it.
|
|
195
|
+
const options: any = { require: localRequire }
|
|
196
|
+
const aontu = false === opts?.strict ? new Aontu(options) : strictAontu(options)
|
|
190
197
|
const model = aontu.generate(text, { path, errs })
|
|
191
198
|
|
|
192
199
|
return {
|
package/src/helpers/shipped.ts
CHANGED
|
@@ -9,9 +9,8 @@
|
|
|
9
9
|
// installation doing the checking, which is this one.
|
|
10
10
|
//
|
|
11
11
|
// `__dirname` is `dist/helpers` in the shipped package, so the package root is
|
|
12
|
-
// two levels up.
|
|
13
|
-
//
|
|
14
|
-
// fails on drift).
|
|
12
|
+
// two levels up. The authoritative schema lives directly in its model/
|
|
13
|
+
// directory, in both a checkout and an installed package.
|
|
15
14
|
|
|
16
15
|
import Path from 'node:path'
|
|
17
16
|
|
|
@@ -1,52 +1,14 @@
|
|
|
1
|
-
// How strict the generated LIVE tests are.
|
|
2
|
-
//
|
|
3
|
-
// WHY THIS IS A MODEL DECISION
|
|
4
|
-
//
|
|
5
|
-
// The generated direct tests are deliberately lenient in live mode:
|
|
6
|
-
//
|
|
7
|
-
// if (setup.live) {
|
|
8
|
-
// // Live mode is lenient: synthetic IDs frequently 4xx.
|
|
9
|
-
// if (!result.ok || result.status < 200 || result.status >= 300) {
|
|
10
|
-
// return // <-- passes
|
|
11
|
-
// }
|
|
12
|
-
// } else {
|
|
13
|
-
// assert(result.ok === true)
|
|
14
|
-
// ...
|
|
15
|
-
// }
|
|
16
|
-
//
|
|
17
|
-
// That is CORRECT for sdkgen's default case — a fleet SDK generated against
|
|
18
|
-
// an arbitrary third-party public API, where synthetic IDs 4xx constantly and
|
|
19
|
-
// list response shapes vary wildly. Asserting there would mean permanent red.
|
|
20
|
-
//
|
|
21
|
-
// It is WRONG for a project that owns the server it tests against, and those
|
|
22
|
-
// projects had no way to say so. Measured on voxgig-solardemo-sdk: the live
|
|
23
|
-
// TypeScript suite reports 186 pass / 0 fail against the local test app —
|
|
24
|
-
// and 184 pass / 2 fail with the server STOPPED. Only the two entity `basic`
|
|
25
|
-
// flows noticed. A green live run said almost nothing.
|
|
26
|
-
//
|
|
27
|
-
// Gaps that announce themselves as a passing test suite are worse than the
|
|
28
|
-
// ones that break a build.
|
|
29
|
-
|
|
30
1
|
import { KIT } from '../types'
|
|
31
2
|
|
|
32
|
-
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
// main: kit: test: live: strict: true
|
|
37
|
-
// main: kit: target: go: test: live: strict: true
|
|
3
|
+
// Live requests assert success by default. This never enables fail-fast:
|
|
4
|
+
// independent tests continue and their framework aggregates the failures.
|
|
5
|
+
// An explicit false preserves the legacy exploratory policy for callers
|
|
6
|
+
// migrating a fleet; it must not be confused with full live verification.
|
|
38
7
|
function liveStrict(model: any, target?: string): boolean {
|
|
39
8
|
const perTarget = null == target ? undefined :
|
|
40
9
|
model?.main?.[KIT]?.target?.[target]?.test?.live?.strict
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return true === perTarget
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return true === model?.main?.[KIT]?.test?.live?.strict
|
|
10
|
+
const configured = perTarget ?? model?.main?.[KIT]?.test?.live?.strict
|
|
11
|
+
return false !== configured
|
|
47
12
|
}
|
|
48
13
|
|
|
49
|
-
|
|
50
|
-
export {
|
|
51
|
-
liveStrict,
|
|
52
|
-
}
|
|
14
|
+
export { liveStrict }
|