@voxgig/sdkgen 4.24.2 → 4.25.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.
Files changed (132) hide show
  1. package/bin/voxgig-sdkgen +1 -1
  2. package/dist/action/action.js +9 -5
  3. package/dist/action/action.js.map +1 -1
  4. package/dist/action/check.js +36 -7
  5. package/dist/action/check.js.map +1 -1
  6. package/dist/action/doctor.js +8 -9
  7. package/dist/action/doctor.js.map +1 -1
  8. package/dist/action/feature.js +1 -1
  9. package/dist/action/feature.js.map +1 -1
  10. package/dist/action/kind.d.ts +2 -1
  11. package/dist/action/kind.js +21 -23
  12. package/dist/action/kind.js.map +1 -1
  13. package/dist/action/package.js +1 -1
  14. package/dist/action/package.js.map +1 -1
  15. package/dist/action/remove.js +6 -5
  16. package/dist/action/remove.js.map +1 -1
  17. package/dist/action/resolve.js +2 -2
  18. package/dist/action/resolve.js.map +1 -1
  19. package/dist/action/target.js +4 -2
  20. package/dist/action/target.js.map +1 -1
  21. package/dist/cmp/AgentGuide.js +2 -2
  22. package/dist/cmp/AgentGuideContent.js +9 -9
  23. package/dist/cmp/AgentGuideFeature.js +3 -3
  24. package/dist/cmp/AgentGuideFeature.js.map +1 -1
  25. package/dist/cmp/AgentGuideTop.js +1 -1
  26. package/dist/cmp/Deploy.js +2 -2
  27. package/dist/helpers/definition.d.ts +8 -1
  28. package/dist/helpers/definition.js +115 -10
  29. package/dist/helpers/definition.js.map +1 -1
  30. package/dist/helpers/manifest.js +4 -3
  31. package/dist/helpers/manifest.js.map +1 -1
  32. package/dist/helpers/modelcheck.d.ts +1 -0
  33. package/dist/helpers/modelcheck.js +9 -1
  34. package/dist/helpers/modelcheck.js.map +1 -1
  35. package/dist/helpers/shipped.js +1 -1
  36. package/dist/helpers/shipped.js.map +1 -1
  37. package/dist/sdkgen.js +6 -2
  38. package/dist/sdkgen.js.map +1 -1
  39. package/dist/testkit.js +6 -6
  40. package/dist/testkit.js.map +1 -1
  41. package/dist/tsconfig.tsbuildinfo +1 -1
  42. package/package.json +5 -5
  43. package/project/.sdk/model/feature/feature-index.aontu +27 -0
  44. package/project/.sdk/src/cmp/zig/fragment/Root.fragment.zig +1 -1
  45. package/project/.sdk/tm/c/Makefile +1 -1
  46. package/project/.sdk/tm/c/feature/secrets.h +2 -2
  47. package/project/.sdk/tm/c/feature/validate.h +2 -2
  48. package/project/.sdk/tm/clojure/src/sdk/features.clj +1 -1
  49. package/project/.sdk/tm/cpp/Makefile +1 -1
  50. package/project/.sdk/tm/cpp/test/primary_utility_test.cpp +1 -1
  51. package/project/.sdk/tm/csharp/Makefile +1 -1
  52. package/project/.sdk/tm/csharp/test/PrimaryUtilityTest.cs +1 -1
  53. package/project/.sdk/tm/java/test/PrimaryUtilityTest.java +1 -1
  54. package/project/.sdk/tm/kotlin/test/PrimaryUtilityTest.kt +1 -1
  55. package/project/.sdk/tm/lua/test/primary_utility_test.lua +1 -1
  56. package/project/.sdk/tm/ocaml/sdk_features.ml +1 -1
  57. package/project/.sdk/tm/perl/t/primary_utility.t +1 -1
  58. package/project/.sdk/tm/php/test/PrimaryUtilityTest.php +1 -1
  59. package/project/.sdk/tm/py/test/test_primary_utility.py +1 -1
  60. package/project/.sdk/tm/rb/test/primary_utility_test.rb +1 -1
  61. package/project/.sdk/tm/scala/sdktest/OmniSmoke.scala +1 -1
  62. package/project/.sdk/tm/scala/sdktest/feature/secrets/SecretsTestMain.scala +1 -1
  63. package/project/.sdk/tm/swift/Makefile +1 -1
  64. package/project/.sdk/tm/swift/Tests/ProjectNameSDKTests/PrimaryUtilityTest.swift +1 -1
  65. package/project/.sdk/tm/ts/test/utility/Corpus.test.ts +1 -1
  66. package/project/sdkgen-package.json +1 -1
  67. package/src/action/action.ts +13 -5
  68. package/src/action/check.ts +52 -8
  69. package/src/action/doctor.ts +12 -12
  70. package/src/action/feature.ts +1 -1
  71. package/src/action/kind.ts +32 -30
  72. package/src/action/package.ts +1 -1
  73. package/src/action/remove.ts +10 -6
  74. package/src/action/resolve.ts +3 -3
  75. package/src/action/target.ts +5 -2
  76. package/src/cmp/AgentGuide.ts +2 -2
  77. package/src/cmp/AgentGuideContent.ts +9 -9
  78. package/src/cmp/AgentGuideFeature.ts +3 -3
  79. package/src/cmp/AgentGuideTop.ts +1 -1
  80. package/src/cmp/Deploy.ts +2 -2
  81. package/src/helpers/definition.ts +163 -10
  82. package/src/helpers/manifest.ts +5 -4
  83. package/src/helpers/modelcheck.ts +15 -1
  84. package/src/helpers/shipped.ts +1 -1
  85. package/src/sdkgen.ts +8 -2
  86. package/src/testkit.ts +6 -6
  87. package/testkit.js +1 -1
  88. package/project/.sdk/model/feature/feature-index.aon +0 -27
  89. /package/model/{sdkgen.aon → sdkgen.aontu} +0 -0
  90. /package/project/.sdk/model/feature/{audit.aon → audit.aontu} +0 -0
  91. /package/project/.sdk/model/feature/{cache.aon → cache.aontu} +0 -0
  92. /package/project/.sdk/model/feature/{clienttrack.aon → clienttrack.aontu} +0 -0
  93. /package/project/.sdk/model/feature/{cost.aon → cost.aontu} +0 -0
  94. /package/project/.sdk/model/feature/{debug.aon → debug.aontu} +0 -0
  95. /package/project/.sdk/model/feature/{idempotency.aon → idempotency.aontu} +0 -0
  96. /package/project/.sdk/model/feature/{log.aon → log.aontu} +0 -0
  97. /package/project/.sdk/model/feature/{metrics.aon → metrics.aontu} +0 -0
  98. /package/project/.sdk/model/feature/{netsim.aon → netsim.aontu} +0 -0
  99. /package/project/.sdk/model/feature/{paging.aon → paging.aontu} +0 -0
  100. /package/project/.sdk/model/feature/{proxy.aon → proxy.aontu} +0 -0
  101. /package/project/.sdk/model/feature/{ratelimit.aon → ratelimit.aontu} +0 -0
  102. /package/project/.sdk/model/feature/{rbac.aon → rbac.aontu} +0 -0
  103. /package/project/.sdk/model/feature/{retry.aon → retry.aontu} +0 -0
  104. /package/project/.sdk/model/feature/{secrets.aon → secrets.aontu} +0 -0
  105. /package/project/.sdk/model/feature/{streaming.aon → streaming.aontu} +0 -0
  106. /package/project/.sdk/model/feature/{telemetry.aon → telemetry.aontu} +0 -0
  107. /package/project/.sdk/model/feature/{test.aon → test.aontu} +0 -0
  108. /package/project/.sdk/model/feature/{timeout.aon → timeout.aontu} +0 -0
  109. /package/project/.sdk/model/feature/{validate.aon → validate.aontu} +0 -0
  110. /package/project/.sdk/model/target/{c.aon → c.aontu} +0 -0
  111. /package/project/.sdk/model/target/{clojure.aon → clojure.aontu} +0 -0
  112. /package/project/.sdk/model/target/{cpp.aon → cpp.aontu} +0 -0
  113. /package/project/.sdk/model/target/{csharp.aon → csharp.aontu} +0 -0
  114. /package/project/.sdk/model/target/{elixir.aon → elixir.aontu} +0 -0
  115. /package/project/.sdk/model/target/{go-cli.aon → go-cli.aontu} +0 -0
  116. /package/project/.sdk/model/target/{go-mcp.aon → go-mcp.aontu} +0 -0
  117. /package/project/.sdk/model/target/{go.aon → go.aontu} +0 -0
  118. /package/project/.sdk/model/target/{java.aon → java.aontu} +0 -0
  119. /package/project/.sdk/model/target/{js.aon → js.aontu} +0 -0
  120. /package/project/.sdk/model/target/{kotlin.aon → kotlin.aontu} +0 -0
  121. /package/project/.sdk/model/target/{lua.aon → lua.aontu} +0 -0
  122. /package/project/.sdk/model/target/{ocaml.aon → ocaml.aontu} +0 -0
  123. /package/project/.sdk/model/target/{perl.aon → perl.aontu} +0 -0
  124. /package/project/.sdk/model/target/{php.aon → php.aontu} +0 -0
  125. /package/project/.sdk/model/target/{py-data.aon → py-data.aontu} +0 -0
  126. /package/project/.sdk/model/target/{py.aon → py.aontu} +0 -0
  127. /package/project/.sdk/model/target/{rb.aon → rb.aontu} +0 -0
  128. /package/project/.sdk/model/target/{rust.aon → rust.aontu} +0 -0
  129. /package/project/.sdk/model/target/{scala.aon → scala.aontu} +0 -0
  130. /package/project/.sdk/model/target/{swift.aon → swift.aontu} +0 -0
  131. /package/project/.sdk/model/target/{ts.aon → ts.aontu} +0 -0
  132. /package/project/.sdk/model/target/{zig.aon → zig.aontu} +0 -0
@@ -11,7 +11,9 @@ import type {
11
11
 
12
12
  import { SdkGenError } from '../utility'
13
13
 
14
- import { definitionPath, definitionFolder, indexName } from '../helpers/definition'
14
+ import {
15
+ assertMigrated, definitionPathAny, indexName, indexPath,
16
+ } from '../helpers/definition'
15
17
 
16
18
  import { findFeatureSources, BASE_FEATURE } from '../helpers/featureSource'
17
19
 
@@ -158,8 +160,10 @@ async function planRemove(
158
160
  '\n a name matches ' + ITEM_NAME_RE.source + ' — it is not a path')
159
161
  }
160
162
 
163
+ assertMigrated(fs, [indexPath(root, kind)])
164
+
161
165
  const declared: any = kindCollection(model, kind)?.[name]
162
- const modelfile = definitionPath(root, kind, name)
166
+ const modelfile = definitionPathAny(fs, root, kind, name)
163
167
  const hasModel = fs.existsSync(modelfile)
164
168
 
165
169
  if (null == declared && !hasModel) {
@@ -213,7 +217,7 @@ async function planRemove(
213
217
  }
214
218
 
215
219
  if (hasModel) {
216
- plan.files.push('model/' + kind + '/' + name + '.aon')
220
+ plan.files.push('model/' + kind + '/' + Path.basename(modelfile))
217
221
  }
218
222
 
219
223
  const wanted = new Set(plan.files)
@@ -226,7 +230,7 @@ async function planRemove(
226
230
  }
227
231
  }
228
232
 
229
- const index = Path.join(definitionFolder(root, kind), indexName(kind))
233
+ const index = indexPath(root, kind)
230
234
  plan.indexed = fs.existsSync(index) &&
231
235
  removeIndexEntries(String(fs.readFileSync(index, 'utf8')), [name]) !==
232
236
  String(fs.readFileSync(index, 'utf8'))
@@ -353,7 +357,7 @@ function projectMentions(kind: string, name: string, actx: ActionContext): strin
353
357
 
354
358
  const out: string[] = []
355
359
  for (const r of walk(fs, modeldir)) {
356
- if (!r.endsWith('.aon') || r.startsWith(own)) {
360
+ if (!/\.(aontu|aon)$/.test(r) || r.startsWith(own)) {
357
361
  continue
358
362
  }
359
363
  let src = ''
@@ -404,7 +408,7 @@ function applyRemove(plan: RemovePlan, actx: ActionContext, dryrun: boolean): st
404
408
  }
405
409
 
406
410
  if (plan.indexed) {
407
- const index = Path.join(definitionFolder(root, kind), indexName(kind))
411
+ const index = indexPath(root, kind)
408
412
  say('model/' + kind + '/' + indexName(kind), 'the index entry for ' + name)
409
413
  if (!dryrun) {
410
414
  fs.writeFileSync(index,
@@ -6,7 +6,7 @@ import { getelem } from '@voxgig/struct'
6
6
 
7
7
  import { KIT } from '../types'
8
8
 
9
- import { definitionPath } from '../helpers/definition'
9
+ import { definitionPathAny } from '../helpers/definition'
10
10
  import { readManifest, checkShape, ITEM_NAME_RE } from '../helpers/manifest'
11
11
 
12
12
 
@@ -123,7 +123,7 @@ function resolveSource(ref: string, kind: string, ctx$: any): Source {
123
123
  // Path.join, not concatenation: an absolute Windows ref makes `folder`
124
124
  // backslash-separated, and appending '/model/...' produced a mixed-
125
125
  // separator path that some readers handle and others do not.
126
- model: definitionPath(folder, kind, origname),
126
+ model: definitionPathAny(fs, folder, kind, origname),
127
127
 
128
128
  package: sourcePackage(fs, folder, kind, origname, ctx$),
129
129
  }
@@ -276,7 +276,7 @@ function providesStill(
276
276
  // No manifest, or one too malformed to be believed: a bare `.sdk`-shaped
277
277
  // folder is a legal source, and its definition file is the only claim it
278
278
  // makes.
279
- return fs.existsSync(definitionPath(folder, kind, seek))
279
+ return fs.existsSync(definitionPathAny(fs, folder, kind, seek))
280
280
  }
281
281
 
282
282
 
@@ -20,6 +20,8 @@ import { templateReplacements, provenanceReplace } from '../helpers/stdrep'
20
20
 
21
21
  import { isJunk, copyOpts } from '../helpers/junk'
22
22
 
23
+ import { definitionPathAny, migrateIncludes } from '../helpers/definition'
24
+
23
25
  import { Aontu } from 'aontu'
24
26
 
25
27
  import {
@@ -496,11 +498,12 @@ function readTargetFeature(
496
498
  const { log } = ctx$
497
499
  const fs = ctx$.fs()
498
500
 
499
- const path = tfolder + '/model/target/' + torigname + '.aon'
501
+ const path = definitionPathAny(fs, tfolder, 'target', torigname)
500
502
 
501
503
  try {
502
504
  const errs: any[] = []
503
- const model = new Aontu().generate(fs.readFileSync(path, 'utf8'), { path, errs })
505
+ const src = migrateIncludes(fs.readFileSync(path, 'utf8'))
506
+ const model = new Aontu().generate(src, { path, errs })
504
507
 
505
508
  if (0 < errs.length) {
506
509
  throw new Error(errs.map((e: any) => e.msg || String(e)).join('\n'))
@@ -61,7 +61,7 @@ ${langCommandsBlock(lang)}
61
61
 
62
62
  | Source | Path | Edit when… |
63
63
  | --- | --- | --- |
64
- | Target definition | \`.sdk/model/target/${lang}.aon\` | deps, module, extension, phases change |
64
+ | Target definition | \`.sdk/model/target/${lang}.aontu\` | deps, module, extension, phases change |
65
65
  | Templates | \`.sdk/tm/${lang}/\` | the file is the **same for every API** (runtime, transport, base classes) — copied verbatim with placeholder substitution |
66
66
  | Components | \`.sdk/src/cmp/${lang}/\` | the file's shape **depends on the API** (entities, constructor, README, tests) — TypeScript that walks the model |
67
67
 
@@ -88,7 +88,7 @@ Each feature's runtime and its own guide live in \`src/feature/<name>/\`.
88
88
  }
89
89
  else {
90
90
  Content(`Each feature is a flat file in the \`feature/\` package. Its hooks and
91
- default activation come from \`.sdk/model/feature/<name>.aon\`; customise
91
+ default activation come from \`.sdk/model/feature/<name>.aontu\`; customise
92
92
  the runtime under \`.sdk/tm/${lang}/feature/\` and regenerate.
93
93
 
94
94
  | Feature | Runtime file | Active hooks |
@@ -196,11 +196,11 @@ npm run build && npm run generate
196
196
 
197
197
  To author a **new** feature:
198
198
 
199
- 1. Define its model at \`.sdk/model/feature/<name>.aon\` — \`name: key()\`,
199
+ 1. Define its model at \`.sdk/model/feature/<name>.aontu\` — \`name: key()\`,
200
200
  \`title\`, \`version\`, \`active\`, \`config.options.active\`, a \`hook\`
201
201
  map (\`<Stage>: active: true\`), and per-language \`deps\`.
202
- 2. Register it in \`.sdk/model/feature/feature-index.aon\` with
203
- \`@"<name>.aon"\`.
202
+ 2. Register it in \`.sdk/model/feature/feature-index.aontu\` with
203
+ \`@"<name>.aontu"\`.
204
204
  3. Provide the per-language runtime under that target's feature template dir
205
205
  (\`.sdk/tm/<lang>/src/feature/<name>/\` for ts/js, \`.sdk/tm/<lang>/feature/\`
206
206
  otherwise) — the \`FEATURE_Name\` / \`FEATURE_VERSION\` placeholders are
@@ -225,23 +225,23 @@ Each language target is generated from **two layers**:
225
225
 
226
226
  Placeholders substituted on copy: \`ProjectName\` (Pascal-case SDK name),
227
227
  \`GOMODULE\` (Go module path), \`FEATURE_Name\` / \`FEATURE_VERSION\`, and the
228
- \`$$path$$\` interpolation of a model value (such as the name) in \`.aon\`.
228
+ \`$$path$$\` interpolation of a model value (such as the name) in \`.aontu\`.
229
229
 
230
230
  Propagate a change: edit the template/component → \`npm run build\` (only
231
231
  needed if you touched a component) → \`npm run generate\`. Target shape and
232
- deps live in \`.sdk/model/target/<lang>.aon\`; features in
233
- \`.sdk/model/feature/<name>.aon\`.
232
+ deps live in \`.sdk/model/target/<lang>.aontu\`; features in
233
+ \`.sdk/model/feature/<name>.aontu\`.
234
234
  `
235
235
  }
236
236
 
237
237
 
238
238
  function aontuSection(): string {
239
- return `## The model language (aontu, \`.aon\` files)
239
+ return `## The model language (aontu, \`.aontu\` files)
240
240
 
241
241
  The model is one structured object assembled by **aontu** (a unification
242
242
  engine) from three sources: the API model (entities/operations, from the
243
243
  OpenAPI spec via \`@voxgig/apidef\`), the base schema, and the target/feature
244
- definitions in \`.sdk/model/\`. An \`.aon\` file is a relaxed JSON (jsonic
244
+ definitions in \`.sdk/model/\`. An \`.aontu\` file is a relaxed JSON (jsonic
245
245
  syntax) with unification semantics:
246
246
 
247
247
  | Syntax | Meaning |
@@ -251,7 +251,7 @@ syntax) with unification semantics:
251
251
  | \`*default \\| type\` | A default value unified against a type (e.g. \`*true \\| boolean\`). |
252
252
  | \`name: key()\` | Bind a field to its map key (so \`feature: log: {}\` gets \`name: 'log'\`). |
253
253
  | \`$$path$$\` | Interpolate a model value into a string — e.g. the SDK \`name\`. |
254
- | \`@"./file.aon"\` | Include another fragment (how the index files work). The \`./\` is required on a local path. |
254
+ | \`@"./file.aontu"\` | Include another fragment (how the index files work). The \`./\` is required on a local path. |
255
255
  | \`x: .y\` | Reference another path's value (e.g. \`deps: ts: .js\`). |
256
256
 
257
257
  For example, the schema for every feature entry:
@@ -65,8 +65,8 @@ later feature can override an earlier one.
65
65
 
66
66
  | Part | Path |
67
67
  | --- | --- |
68
- | Model definition | \`.sdk/model/feature/${name}.aon\` (name, title, version, \`config.options.active\`, the \`hook\` map, per-language \`deps\`) |
69
- | Registered in | \`.sdk/model/feature/feature-index.aon\` (\`@"${name}.aon"\`) |
68
+ | Model definition | \`.sdk/model/feature/${name}.aontu\` (name, title, version, \`config.options.active\`, the \`hook\` map, per-language \`deps\`) |
69
+ | Registered in | \`.sdk/model/feature/feature-index.aontu\` (\`@"${name}.aontu"\`) |
70
70
  | Runtime template | \`.sdk/tm/${lang}/src/feature/${name}/\` (copied here on \`generate\`; \`FEATURE_Name\`/\`FEATURE_VERSION\` substituted) |
71
71
 
72
72
  (Paths are relative to the **project root** — four levels up from here.)
@@ -74,7 +74,7 @@ later feature can override an earlier one.
74
74
  ## Customising this feature
75
75
 
76
76
  - **Turn hooks on/off**: edit the \`hook\` map in
77
- \`.sdk/model/feature/${name}.aon\` (\`<Stage>: active: true|false\`).
77
+ \`.sdk/model/feature/${name}.aontu\` (\`<Stage>: active: true|false\`).
78
78
  - **Change default activation**: set \`config.options.active\` in the same file.
79
79
  - **Dependencies**: edit \`deps.<lang>\` in the same file.
80
80
  - **Behaviour**: edit the runtime template under
@@ -111,7 +111,7 @@ target's feature container) for the generated adapter.
111
111
 
112
112
  \`\`\`
113
113
  .sdk/
114
- model/ the model: target/, feature/, and index .aon files
114
+ model/ the model: target/, feature/, and index .aontu files
115
115
  src/cmp/<lang>/ components — TypeScript that generates API-specific source
116
116
  tm/<lang>/ templates — verbatim source copied with placeholders
117
117
  dist/ compiled components (npm run build)
package/src/cmp/Deploy.ts CHANGED
@@ -151,7 +151,7 @@ deploy-dry-${t.name}:
151
151
 
152
152
  return `# ${model.Name} SDK deployment. GENERATED by @voxgig/sdkgen — regenerated
153
153
  # on every \`npm run generate\` in .sdk/; publication details live in the
154
- # model (.sdk/model/target/<target>.aon, \`publish\` section).
154
+ # model (.sdk/model/target/<target>.aontu, \`publish\` section).
155
155
  #
156
156
  # Every port gets a git release tag <target>/vX.Y.Z. Ports with an ACTIVE
157
157
  # registry also publish a package there. Credentials are injected at exec
@@ -188,7 +188,7 @@ TARGETS := ${targets.map((t: any) => t.name).join(' ')}
188
188
  deploy:
189
189
  \t@echo "Deployment is per-target — pick one (each upload is irreversible):"
190
190
  \t@echo " make deploy-<target> targets: $(TARGETS)"
191
- \t@echo "Registry state is set in the model (.sdk/model/target/<t>.aon):"
191
+ \t@echo "Registry state is set in the model (.sdk/model/target/<t>.aontu):"
192
192
  ${targets.map((t: any) => {
193
193
  const reg = registryOf(t)
194
194
  const state = reg ? `${reg.name} ${regIsActive(reg) ? 'ACTIVE' : 'publish pending (deploy = git tag only)'}` : 'tag-only'
@@ -1,12 +1,129 @@
1
1
 
2
2
  import Path from 'node:path'
3
3
 
4
+ import { SdkGenError } from '../utility'
5
+
4
6
  import { isJunk } from './junk'
5
7
 
6
8
 
9
+ const EXT = '.aontu'
10
+
11
+ // Pre-rename aontu files: read from a package not yet renamed, never written.
12
+ const LEGACY_EXT = '.aon'
13
+
14
+ const SOURCE_RE = /\.(aontu|aon)$/
15
+
16
+
17
+ function definitionFileName(name: string): string {
18
+ return name + EXT
19
+ }
20
+
21
+
7
22
  // The definition file for one item.
8
23
  function definitionPath(sdkfolder: string, kind: string, name: string): string {
9
- return Path.join(sdkfolder, 'model', kind, name + '.aon')
24
+ return Path.join(sdkfolder, 'model', kind, definitionFileName(name))
25
+ }
26
+
27
+
28
+ function legacyPath(path: string): string {
29
+ return path.replace(/\.aontu$/, LEGACY_EXT)
30
+ }
31
+
32
+
33
+ function isLegacyPath(path: string): boolean {
34
+ return path.endsWith(LEGACY_EXT)
35
+ }
36
+
37
+
38
+ // The file an item ACTUALLY has: `.aontu`, else the pre-rename `.aon`. Without
39
+ // the fallback a remove reports success and leaves the file behind, and an
40
+ // item from a package that has not renamed its files is not found at all.
41
+ function definitionPathAny(
42
+ fs: any, sdkfolder: string, kind: string, name: string,
43
+ ): string {
44
+ const current = definitionPath(sdkfolder, kind, name)
45
+ if (fs.existsSync(current)) {
46
+ return current
47
+ }
48
+
49
+ const legacy = legacyPath(current)
50
+
51
+ return fs.existsSync(legacy) ? legacy : current
52
+ }
53
+
54
+
55
+ const LEGACY_INCLUDE_RE =
56
+ /@([ \t]*)(?:"((?:[^"\\\r\n]|\\.)*)\.aon"|'((?:[^'\\\r\n]|\\.)*)\.aon')/y
57
+
58
+
59
+ // Renames each `.aon` include to `.aontu`, the only extension aontu reads.
60
+ // Strings and comments are skipped whole, so a `.aon` that is only text stays.
61
+ function migrateIncludes(src: string): string {
62
+ return mapLegacyIncludes(src, (gap: string, quote: string, path: string) =>
63
+ '@' + gap + quote + path + '.aontu' + quote)
64
+ }
65
+
66
+
67
+ // Removes each `.aon` include instead, leaving what the file itself declares.
68
+ function dropLegacyIncludes(src: string): string {
69
+ return mapLegacyIncludes(src, () => '')
70
+ }
71
+
72
+
73
+ function mapLegacyIncludes(
74
+ src: string, replace: (gap: string, quote: string, path: string) => string,
75
+ ): string {
76
+ let out = ''
77
+ let at = 0
78
+
79
+ while (at < src.length) {
80
+ LEGACY_INCLUDE_RE.lastIndex = at
81
+ const include = '@' === src[at] ? LEGACY_INCLUDE_RE.exec(src) : null
82
+
83
+ if (null != include) {
84
+ const [, gap, dq, sq] = include
85
+ out += null != dq ? replace(gap, '"', dq) : replace(gap, "'", sq)
86
+ at = LEGACY_INCLUDE_RE.lastIndex
87
+ continue
88
+ }
89
+
90
+ const end = textEnd(src, at)
91
+ out += src.slice(at, end)
92
+ at = end
93
+ }
94
+
95
+ return out
96
+ }
97
+
98
+
99
+ // The end of the string or comment that starts at `at`, else `at + 1`.
100
+ function textEnd(src: string, at: number): number {
101
+ const c = src[at]
102
+ const next = src[at + 1]
103
+
104
+ if ('#' === c || ('/' === c && '/' === next)) {
105
+ const eol = src.indexOf('\n', at)
106
+ return eol < 0 ? src.length : eol
107
+ }
108
+
109
+ if ('/' === c && '*' === next) {
110
+ const close = src.indexOf('*/', at + 2)
111
+ return close < 0 ? src.length : close + 2
112
+ }
113
+
114
+ if ('"' === c || "'" === c || '`' === c) {
115
+ for (let i = at + 1; i < src.length; i++) {
116
+ if ('\\' === src[i]) {
117
+ i++
118
+ }
119
+ else if (c === src[i] || ('`' !== c && '\n' === src[i])) {
120
+ return i + 1
121
+ }
122
+ }
123
+ return src.length
124
+ }
125
+
126
+ return at + 1
10
127
  }
11
128
 
12
129
 
@@ -18,13 +135,19 @@ function definitionFolder(sdkfolder: string, kind: string): string {
18
135
 
19
136
  // The include list beside them.
20
137
  function indexName(kind: string): string {
21
- return kind + '-index.aon'
138
+ return kind + '-index' + EXT
139
+ }
140
+
141
+
142
+ function indexPath(sdkfolder: string, kind: string): string {
143
+ return Path.join(definitionFolder(sdkfolder, kind), indexName(kind))
22
144
  }
23
145
 
24
146
 
25
147
  function definitionNames(fs: any, sdkfolder: string, kind: string): string[] {
26
148
  const dir = definitionFolder(sdkfolder, kind)
27
149
  const index = indexName(kind)
150
+ const indexes = [index, legacyPath(index)]
28
151
 
29
152
  let entries: string[]
30
153
  try {
@@ -34,20 +157,50 @@ function definitionNames(fs: any, sdkfolder: string, kind: string): string[] {
34
157
  return []
35
158
  }
36
159
 
37
- // The `.aon` suffix is not enough on its own: an emacs lock link is named
38
- // `.#target.aon` and a merge leaves `target.aon.orig`, so an editor open
39
- // in the wrong window invents an item called `.#target`, which then fails to
40
- // resolve everywhere it is named. See helpers/junk.
41
- return entries
42
- .filter((n: string) => n.endsWith('.aon') && index !== n && !isJunk(n))
43
- .map((n: string) => n.replace(/\.aon$/, ''))
44
- .sort()
160
+ // The suffix alone is not enough: `.#target.aontu` is an emacs lock link and
161
+ // `target.aontu.orig` a merge leftover, either of which would invent an item
162
+ // that then resolves nowhere. See helpers/junk. Both extensions, deduped.
163
+ const names = new Set<string>(entries
164
+ .filter((n: string) =>
165
+ SOURCE_RE.test(n) && !indexes.includes(n) && !isJunk(n))
166
+ .map((n: string) => n.replace(SOURCE_RE, '')))
167
+
168
+ return [...names].sort()
169
+ }
170
+
171
+
172
+ // A project from before the rename has the `.aon` file and no `.aontu`: aontu
173
+ // reads neither it nor a new `.aontu` written beside it that nothing includes.
174
+ function assertMigrated(fs: any, paths: string[]): void {
175
+ const stale = paths
176
+ .filter((p: string) => !fs.existsSync(p) && fs.existsSync(legacyPath(p)))
177
+ .map((p: string) => Path.normalize(legacyPath(p)).split(Path.sep).join('/'))
178
+
179
+ if (0 === stale.length) {
180
+ return
181
+ }
182
+
183
+ throw new SdkGenError(
184
+ 'This project predates .aontu model files: ' + stale.join(', ') +
185
+ (1 === stale.length ? ' has' : ' have') + ' no .aontu counterpart, ' +
186
+ 'and aontu reads only .aontu.' +
187
+ '\n Re-scaffold the project with the current create-sdkgen, which ' +
188
+ 'migrates it:' +
189
+ '\n npm create @voxgig/sdkgen@latest ... (run over this project, ' +
190
+ 'with the arguments it was created with)')
45
191
  }
46
192
 
47
193
 
48
194
  export {
195
+ assertMigrated,
196
+ definitionFileName,
49
197
  definitionPath,
198
+ definitionPathAny,
50
199
  definitionFolder,
200
+ dropLegacyIncludes,
51
201
  definitionNames,
52
202
  indexName,
203
+ indexPath,
204
+ isLegacyPath,
205
+ migrateIncludes,
53
206
  }
@@ -1,7 +1,7 @@
1
1
 
2
2
  import Path from 'node:path'
3
3
 
4
- import { definitionNames } from './definition'
4
+ import { definitionNames, definitionPathAny } from './definition'
5
5
 
6
6
 
7
7
  const MANIFEST = 'sdkgen-package.json'
@@ -281,8 +281,9 @@ function validateManifest(
281
281
  if (!claimed.has(name)) {
282
282
  found.push({
283
283
  level: 'warn', point: 'manifest-item-unclaimed', file, kind, name,
284
- note: file + ': model/' + kind + '/' + name +
285
- '.aon is in the package but not listed in `provides.' + kind +
284
+ note: file + ': model/' + kind + '/' +
285
+ Path.basename(definitionPathAny(fs, sdkfolder, kind, name)) +
286
+ ' is in the package but not listed in `provides.' + kind +
286
287
  '` — nothing will install it'
287
288
  })
288
289
  }
@@ -304,7 +305,7 @@ function missingPaths(
304
305
  const missing: string[] = []
305
306
 
306
307
  if (!defined.has(name)) {
307
- missing.push('model/' + kind + '/' + name + '.aon')
308
+ missing.push('model/' + kind + '/' + name + '.aontu')
308
309
  }
309
310
 
310
311
  for (const tree of (def.trees ?? []).filter((t) => t.required)) {
@@ -67,6 +67,10 @@ function includeLine(file: string): string {
67
67
  type CompileResult = {
68
68
  model?: any
69
69
  errors: string[]
70
+
71
+ // aontu's code for each error that carries one, such as
72
+ // `multisource_not_found` for an include that did not resolve.
73
+ why: string[]
70
74
  }
71
75
 
72
76
 
@@ -104,14 +108,23 @@ function compileModel(
104
108
  model,
105
109
  errors: errs.map((e: any) =>
106
110
  tidy((null == e.why ? '' : '[' + e.why + '] ') + (e.msg ?? String(e)))),
111
+ why: whyOf(errs),
107
112
  }
108
113
  }
109
114
  catch (err: any) {
110
- return { errors: [tidy(err.message ?? String(err))] }
115
+ return {
116
+ errors: [tidy(err.message ?? String(err))],
117
+ why: whyOf('function' === typeof err?.errs ? err.errs() : []),
118
+ }
111
119
  }
112
120
  }
113
121
 
114
122
 
123
+ function whyOf(errs: any[]): string[] {
124
+ return errs.map((e: any) => e?.why).filter((w: any) => 'string' === typeof w)
125
+ }
126
+
127
+
115
128
  const PUBLISH_OVERRIDES: [string, string, string][] = [
116
129
  ['publish: version', "'9.9.9'", "'8.8.8'"],
117
130
  ['publish: tag: active', 'false', 'true'],
@@ -141,6 +154,7 @@ function publishOverrideProbe(
141
154
  return {
142
155
  model: first.model ?? second.model,
143
156
  errors: [...first.errors, ...second.errors],
157
+ why: [...first.why, ...second.why],
144
158
  }
145
159
  }
146
160
 
@@ -8,7 +8,7 @@ function packageRoot(): string {
8
8
 
9
9
 
10
10
  function schemaFile(): string {
11
- return Path.join(packageRoot(), 'model', 'sdkgen.aon')
11
+ return Path.join(packageRoot(), 'model', 'sdkgen.aontu')
12
12
  }
13
13
 
14
14
 
package/src/sdkgen.ts CHANGED
@@ -87,9 +87,11 @@ import {
87
87
  import type { FeatureSource } from './helpers/featureSource'
88
88
  import { stationLibrary } from './helpers/station'
89
89
  import {
90
+ assertMigrated,
90
91
  definitionPath,
91
92
  definitionFolder,
92
93
  definitionNames,
94
+ indexPath,
93
95
  } from './helpers/definition'
94
96
  import { isNoise, copyOpts } from './helpers/junk'
95
97
  import {
@@ -156,6 +158,7 @@ import { edition_add } from './action/edition'
156
158
 
157
159
  // The verbs, built from the kind registry — see action/dispatch.
158
160
  import { ACTION_MAP, actionNames, needsModel } from './action/dispatch'
161
+ import { KINDS } from './action/kind'
159
162
 
160
163
 
161
164
 
@@ -398,7 +401,7 @@ function SdkGen(opts: SdkGenOptions) {
398
401
 
399
402
 
400
403
  function resolveModel(wanted: boolean) {
401
- const path = './model/sdk.aon'
404
+ const path = './model/sdk.aontu'
402
405
  const errs: any[] = []
403
406
 
404
407
  // A verb that does not act on a project (see `needsModel`) is run where
@@ -409,6 +412,9 @@ function SdkGen(opts: SdkGenOptions) {
409
412
  return { model: { main: {} } as any, url: path }
410
413
  }
411
414
 
415
+ assertMigrated(fs, [
416
+ path, ...Object.keys(KINDS).map((kind: string) => indexPath('.', kind))])
417
+
412
418
  if (null == aontu) {
413
419
  aontu = new Aontu()
414
420
  }
@@ -536,7 +542,7 @@ SdkGen.makeBuild = async function(opts: SdkGenOptions) {
536
542
  root: opts.root,
537
543
  def: opts.def || 'no-def',
538
544
  kind: 'openapi-3',
539
- model: opts.model ? (opts.model.folder + '/api.aon') : 'no-model',
545
+ model: opts.model ? (opts.model.folder + '/api.aontu') : 'no-model',
540
546
  meta: opts.meta || {},
541
547
  }
542
548
 
package/src/testkit.ts CHANGED
@@ -102,17 +102,17 @@ function stageConsumer(opts: StageOptions = {}): Consumer {
102
102
  Fs.mkdirSync(Path.join(sdk, 'model', 'target'), { recursive: true })
103
103
  Fs.mkdirSync(Path.join(sdk, 'model', 'feature'), { recursive: true })
104
104
 
105
- Fs.writeFileSync(Path.join(sdk, 'model', 'target', 'target-index.aon'),
105
+ Fs.writeFileSync(Path.join(sdk, 'model', 'target', 'target-index.aontu'),
106
106
  '# Targets\n')
107
- Fs.writeFileSync(Path.join(sdk, 'model', 'feature', 'feature-index.aon'),
107
+ Fs.writeFileSync(Path.join(sdk, 'model', 'feature', 'feature-index.aontu'),
108
108
  '# Features\n')
109
109
 
110
110
  const name = opts.name ?? 'demo'
111
111
 
112
- Fs.writeFileSync(Path.join(sdk, 'model', 'sdk.aon'),
112
+ Fs.writeFileSync(Path.join(sdk, 'model', 'sdk.aontu'),
113
113
  "name: '" + name + "'\n" +
114
- '@"./target/target-index.aon"\n' +
115
- '@"./feature/feature-index.aon"\n' +
114
+ '@"./target/target-index.aontu"\n' +
115
+ '@"./feature/feature-index.aontu"\n' +
116
116
  (opts.extra ? opts.extra + '\n' : ''))
117
117
 
118
118
  const modules = Path.join(sdk, 'node_modules')
@@ -138,7 +138,7 @@ function stageConsumer(opts: StageOptions = {}): Consumer {
138
138
  [KIT]: { feature: {}, entity: {}, target: {} },
139
139
  },
140
140
  },
141
- url: Path.join(sdk, 'model', 'sdk.aon'),
141
+ url: Path.join(sdk, 'model', 'sdk.aontu'),
142
142
  jostraca: Jostraca({ existing: { txt: { write: true, merge: false } } }),
143
143
  opts: { dryrun: false },
144
144
  }
package/testkit.js CHANGED
@@ -5,7 +5,7 @@
5
5
  // A stub rather than an `exports` map entry, on purpose. A map would name
6
6
  // this subpath and, in doing so, replace the deep-import freedom this package
7
7
  // has without one — and consumers depend on that freedom invisibly (generated
8
- // model files include `@voxgig/sdkgen/model/sdkgen.aon`; the scaffold is
8
+ // model files include `@voxgig/sdkgen/model/sdkgen.aontu`; the scaffold is
9
9
  // reached as `@voxgig/sdkgen/project/<lang>`). See the `_no_exports_comment`
10
10
  // in package.json for what was measured.
11
11
 
@@ -1,27 +0,0 @@
1
- # Features
2
-
3
- # Core
4
- @"./test.aon"
5
- @"./log.aon"
6
- @"./secrets.aon"
7
-
8
- # Enterprise capabilities
9
- @"./retry.aon"
10
- @"./timeout.aon"
11
- @"./ratelimit.aon"
12
- @"./cache.aon"
13
- @"./cost.aon"
14
- @"./idempotency.aon"
15
- @"./paging.aon"
16
- @"./streaming.aon"
17
- @"./proxy.aon"
18
- @"./telemetry.aon"
19
- @"./metrics.aon"
20
- @"./debug.aon"
21
- @"./audit.aon"
22
- @"./clienttrack.aon"
23
- @"./rbac.aon"
24
- @"./validate.aon"
25
-
26
- # Test support: network behaviour simulation
27
- @"./netsim.aon"
File without changes