@voxgig/sdkgen 4.24.3 → 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 +3 -3
  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
@@ -62,7 +62,7 @@ pub const DebugFeature = @import("feature/debug.zig").DebugFeature;
62
62
  pub const AuditFeature = @import("feature/audit.zig").AuditFeature;
63
63
  pub const ClienttrackFeature = @import("feature/clienttrack.zig").ClienttrackFeature;
64
64
  pub const RbacFeature = @import("feature/rbac.zig").RbacFeature;
65
- // GATED features (model/feature/<name>.aon `needs:`), exported ONLY when the
65
+ // GATED features (model/feature/<name>.aontu `needs:`), exported ONLY when the
66
66
  // model activates them: their source reaches a named build module (the
67
67
  // vendored sekreto for `secrets`) that build.zig declares under the same
68
68
  // condition, so a static export here would name a module an inactive SDK
@@ -29,7 +29,7 @@ OMNI_INC := -I tests -I tests/vendor/omni
29
29
  TEST_INC := -I tests
30
30
  LDLIBS := -lm
31
31
 
32
- # ---- gated feature payloads (model/feature/<name>.aon plugin groups) --------
32
+ # ---- gated feature payloads (model/feature/<name>.aontu plugin groups) --------
33
33
  #
34
34
  # A gated feature's vendored payload sits two levels under feature/
35
35
  # (feature/<name>/<lib>/*.c) - out of reach of the feature/*/*.c glob below,
@@ -6,8 +6,8 @@
6
6
  // and go's `Sekreto()` / `Credential()` accessors. Named for the feature so
7
7
  // the feature trim drops it with feature/secrets.c and feature/secrets/.
8
8
  //
9
- // The feature is GATED (model/feature/secrets.aon `needs: { sekreto: true }`
10
- // and model/target/c.aon `provides`), so its constructor is NOT in sdk.h's
9
+ // The feature is GATED (model/feature/secrets.aontu `needs: { sekreto: true }`
10
+ // and model/target/c.aontu `provides`), so its constructor is NOT in sdk.h's
11
11
  // bundled list: core/config.c emits the prototype for a project that
12
12
  // selected it, and this header repeats it for a caller that includes only
13
13
  // this file.
@@ -5,8 +5,8 @@
5
5
  // option value cannot hold - so it is set on the feature after construction,
6
6
  // the way the retry port takes its injectable sleep.
7
7
  //
8
- // The feature is GATED (model/feature/validate.aon `needs: { schema: true }`
9
- // and model/target/c.aon `provides`), so its constructor is NOT in sdk.h's
8
+ // The feature is GATED (model/feature/validate.aontu `needs: { schema: true }`
9
+ // and model/target/c.aontu `provides`), so its constructor is NOT in sdk.h's
10
10
  // bundled list: core/config.c emits the prototype for a project that selected
11
11
  // it, and this header repeats it for a caller that includes only this file.
12
12
 
@@ -686,7 +686,7 @@
686
686
  ;; ---------------------------------------------------------------------------
687
687
  ;; Prices every transport ATTEMPT and commits the spend once per OPERATION.
688
688
  ;; Mirrors tm/ts/src/feature/cost/CostFeature.ts; the cases are
689
- ;; .sdk/test/feature/cost.aon.
689
+ ;; .sdk/test/feature/cost.aontu.
690
690
  ;;
691
691
  ;; ORDER MATTERS. Cost must sit INSIDE the cache, or a response served from
692
692
  ;; cache is charged for money that was never spent. Activate in list form with
@@ -11,7 +11,7 @@
11
11
  CXX ?= g++
12
12
  CXXFLAGS ?= -std=c++17 -O0 -g -Wall -Wextra -Wno-unused-parameter -pthread
13
13
 
14
- # ---- gated feature payloads (model/feature/<name>.aon plugin groups) --------
14
+ # ---- gated feature payloads (model/feature/<name>.aontu plugin groups) --------
15
15
  #
16
16
  # A gated feature's vendored payload sits two levels under feature/
17
17
  # (feature/<name>/<lib>/*.cpp), as .cpp/.hpp pairs that cannot ride inside
@@ -786,7 +786,7 @@ static void transformResponseBasic() {
786
786
 
787
787
  // Sections under `primary` that are NOT this SDK's pipeline surface, with the
788
788
  // reason each is exempt. `check` is omni's OWN runner fixture (it comes from
789
- // .sdk/test/struct/test.aon, which the corpus build merges into primary); no
789
+ // .sdk/test/struct/test.aontu, which the corpus build merges into primary); no
790
790
  // port drives it from a primary suite.
791
791
  static const std::vector<std::string>& notThisSuite() {
792
792
  static const std::vector<std::string> names = {"check"};
@@ -11,7 +11,7 @@ clean:
11
11
  rm -rf bin obj test/bin test/obj
12
12
 
13
13
  # --- Release: tag for NuGet ------------------------------------------------
14
- # NuGet publication is pending (see model/target/csharp.aon publish block);
14
+ # NuGet publication is pending (see model/target/csharp.aontu publish block);
15
15
  # publishing a version currently means pushing the tag csharp/vX.Y.Z. When the
16
16
  # registry goes live, `dotnet pack` + `dotnet nuget push` slot in before the
17
17
  # tag (mirroring the voxgig/struct csharp Makefile). Run headless under the
@@ -41,7 +41,7 @@ internal class TestInitFeature : BaseFeature
41
41
  public class PrimaryUtilityTest
42
42
  {
43
43
  // PENDING sections are the ones deliberately left empty in the shared
44
- // corpus (.sdk/test/primary/<name>.aon). Everything else MUST
44
+ // corpus (.sdk/test/primary/<name>.aontu). Everything else MUST
45
45
  // contribute cases.
46
46
  private static readonly HashSet<string> Pending = new()
47
47
  {
@@ -45,7 +45,7 @@ public class PrimaryUtilityTest {
45
45
  static final String TEST_JSON_FILE = "../.sdk/test/test.json";
46
46
 
47
47
  // PENDING sections are the ones deliberately left empty in the shared
48
- // corpus (.sdk/test/primary/<name>.aon). Everything else MUST contribute
48
+ // corpus (.sdk/test/primary/<name>.aontu). Everything else MUST contribute
49
49
  // cases.
50
50
  static final Set<String> PENDING = Set.of(
51
51
  "fetcher", "makeFetchDef", "makeResult",
@@ -39,7 +39,7 @@ class PrimaryUtilityTest {
39
39
  const val TEST_JSON_FILE = "../.sdk/test/test.json"
40
40
 
41
41
  // PENDING sections are the ones deliberately left empty in the shared
42
- // corpus (.sdk/test/primary/<name>.aon). Everything else MUST
42
+ // corpus (.sdk/test/primary/<name>.aontu). Everything else MUST
43
43
  // contribute cases.
44
44
  val PENDING = setOf(
45
45
  "fetcher", "makeFetchDef", "makeResult",
@@ -129,7 +129,7 @@ end
129
129
 
130
130
 
131
131
  -- Sections deliberately left empty in the shared corpus
132
- -- (.sdk/test/primary/<name>.aon carries a PENDING header). Everything else
132
+ -- (.sdk/test/primary/<name>.aontu carries a PENDING header). Everything else
133
133
  -- MUST contribute cases.
134
134
  local PENDING = {
135
135
  fetcher = true,
@@ -771,7 +771,7 @@ let audit_feature () : feature =
771
771
  (* ------------------------------------------------------------------ *)
772
772
  (* Prices every transport ATTEMPT and commits the spend once per
773
773
  OPERATION. Mirrors tm/ts/src/feature/cost/CostFeature.ts; the corpus
774
- cases are .sdk/test/feature/cost.aon.
774
+ cases are .sdk/test/feature/cost.aontu.
775
775
 
776
776
  ORDER MATTERS. Cost must sit INSIDE the cache, or a response served from
777
777
  cache is charged for money that was never spent. Activate in array form
@@ -57,7 +57,7 @@ ok(Voxgig::Struct::ismap($spec), 'primary section found in test.json');
57
57
 
58
58
 
59
59
  # Sections deliberately left empty in the shared corpus
60
- # (.sdk/test/primary/<name>.aon carries a PENDING header). Everything else
60
+ # (.sdk/test/primary/<name>.aontu carries a PENDING header). Everything else
61
61
  # MUST contribute cases.
62
62
  my %PENDING = map { $_ => 1 } qw(
63
63
  fetcher makeFetchDef makeResult featureAdd featureHook featureInit
@@ -38,7 +38,7 @@ class PrimaryUtilityTest extends TestCase
38
38
  private const TEST_JSON_FILE = '../../.sdk/test/test.json';
39
39
 
40
40
  // Sections deliberately left empty in the shared corpus
41
- // (.sdk/test/primary/<name>.aon carries a PENDING header). Everything
41
+ // (.sdk/test/primary/<name>.aontu carries a PENDING header). Everything
42
42
  // else MUST contribute cases.
43
43
  private const PENDING = [
44
44
  'fetcher', 'makeFetchDef', 'makeResult',
@@ -105,7 +105,7 @@ def _retarget_auth(node, cred):
105
105
 
106
106
 
107
107
  # Sections deliberately left empty in the shared corpus
108
- # (.sdk/test/primary/<name>.aon carries a PENDING header). Everything else
108
+ # (.sdk/test/primary/<name>.aontu carries a PENDING header). Everything else
109
109
  # MUST contribute cases.
110
110
  PENDING = {
111
111
  'fetcher', 'makeFetchDef', 'makeResult',
@@ -29,7 +29,7 @@ class PrimaryUtilityTest < Minitest::Test
29
29
  TEST_JSON_FILE = "../../.sdk/test/test.json"
30
30
 
31
31
  # Sections deliberately left empty in the shared corpus
32
- # (.sdk/test/primary/<name>.aon carries a PENDING header). Everything
32
+ # (.sdk/test/primary/<name>.aontu carries a PENDING header). Everything
33
33
  # else MUST contribute cases.
34
34
  PENDING = %w[
35
35
  fetcher makeFetchDef makeResult
@@ -10,7 +10,7 @@
10
10
  //
11
11
  // The Scala peer of tm/java/test/OmniSmokeTest.java, tm/lua/test/
12
12
  // omni_smoke_test.lua and tm/ts/test/omni.test.ts. There is no test
13
- // framework in this target (see model/target/scala.aon), so it is a plain
13
+ // framework in this target (see model/target/scala.aontu), so it is a plain
14
14
  // scala-cli main that exits non-zero on failure, like the corpus mains
15
15
  // beside it.
16
16
 
@@ -775,7 +775,7 @@ object SecretsTestMain {
775
775
  check("vocabulary.table", untabled.isEmpty,
776
776
  "sekreto ships provider kinds this test does not know about: " +
777
777
  untabled.mkString(", ") + " - add them to PLUGINMODULES, and to a " +
778
- "`plugin` group in model/feature/secrets.aon")
778
+ "`plugin` group in model/feature/secrets.aontu")
779
779
 
780
780
  val w = new Wire()
781
781
  val client = secretsClient(w, "feature" -> secretsOpts(memchain("APIKEY" -> "VOCAB01")))
@@ -12,7 +12,7 @@ clean:
12
12
 
13
13
  # --- Release: tag for the SwiftPM registry ---------------------------------
14
14
  # SwiftPM has no upload step - publishing IS the git tag. Publication is
15
- # pending (see model/target/swift.aon publish block); publishing a version
15
+ # pending (see model/target/swift.aontu publish block); publishing a version
16
16
  # currently means pushing the tag swift/vX.Y.Z. Run headless under the boru key
17
17
  # vault, which injects the GitHub token so nothing lands on disk or argv:
18
18
  # boru vault exec --for=github=<alias> -- make publish
@@ -36,7 +36,7 @@ final class TestInitFeature: BaseFeature {
36
36
 
37
37
  final class PrimaryUtilityTest: XCTestCase {
38
38
  // PENDING sections are the ones deliberately left EMPTY in the shared
39
- // corpus (.sdk/test/primary/<name>.aon). Everything else MUST contribute
39
+ // corpus (.sdk/test/primary/<name>.aontu). Everything else MUST contribute
40
40
  // cases: a renamed section or a fixture that failed to compile used to
41
41
  // report PASS while running zero assertions.
42
42
  private static let PENDING: Set<String> = [
@@ -31,7 +31,7 @@ describe('Corpus', () => {
31
31
  })
32
32
  equal(undeclared.join(','), '',
33
33
  'these sections compile to ZERO cases and carry no `basic: pending` ' +
34
- 'reason — add cases, or state the blocker in .sdk/test/primary/<name>.aon')
34
+ 'reason — add cases, or state the blocker in .sdk/test/primary/<name>.aontu')
35
35
  })
36
36
 
37
37
 
@@ -3,7 +3,7 @@
3
3
  "package": 1
4
4
  },
5
5
  "name": "@voxgig/sdkgen",
6
- "version": "4.24.3",
6
+ "version": "4.25.0",
7
7
  "provides": {
8
8
  "target": [
9
9
  "c",
@@ -11,11 +11,17 @@ import type {
11
11
  ActionContext,
12
12
  } from '../types'
13
13
 
14
+ import {
15
+ assertMigrated, indexName, migrateIncludes,
16
+ } from '../helpers/definition'
17
+
14
18
 
15
- const indexEntry = (name: string) => `@"./${name}.aon"`
19
+ const indexEntry = (name: string) => `@"./${name}.aontu"`
16
20
 
17
21
 
18
- const INDEX_ENTRY_RE = /^\s*@"(?:\.\/)?([^"]+)\.aon"\s*(?:#.*)?$/
22
+ // Either extension, so a legacy index is READ as naming its items. `.aontu`
23
+ // is the only one written; see helpers/definition `migrateIncludes`.
24
+ const INDEX_ENTRY_RE = /^\s*@"(?:\.\/)?([^"]+)\.(?:aontu|aon)"\s*(?:#.*)?$/
19
25
 
20
26
  function indexEntryName(line: string): string | undefined {
21
27
  const m = line.match(INDEX_ENTRY_RE)
@@ -30,11 +36,11 @@ function hasIndexEntry(content: string, name: string): boolean {
30
36
  }
31
37
 
32
38
 
33
- // Append `@"<name>.aon"` import lines for each name not already present in
39
+ // Append `@"<name>.aontu"` import lines for each name not already present in
34
40
  // the index content. Checking against the accumulating result (not the
35
41
  // original) means duplicate names in the same call are added at most once.
36
42
  function appendIndexEntries(content: string, names: string[]): string {
37
- let out = content
43
+ let out = migrateIncludes(content)
38
44
 
39
45
  for (const n of names) {
40
46
  if (!hasIndexEntry(out, n)) {
@@ -82,7 +88,9 @@ function loadContent(
82
88
  const modelfolder = Path.dirname(actx.url)
83
89
 
84
90
  which.map((w: string) => {
85
- const indexfile = Path.join(modelfolder, w, w + '-index.aon')
91
+ const indexfile = Path.join(modelfolder, w, indexName(w))
92
+
93
+ assertMigrated(fs, [indexfile])
86
94
 
87
95
  content[`${w}_index`] = (null != seed?.[w] && !fs.existsSync(indexfile)) ?
88
96
  seed[w] : fs.readFileSync(indexfile, 'utf8')
@@ -20,7 +20,12 @@ import {
20
20
 
21
21
  import type { Finding, Manifest } from '../helpers/manifest'
22
22
 
23
- import { definitionPath, definitionNames } from '../helpers/definition'
23
+ import type { CompileResult } from '../helpers/modelcheck'
24
+
25
+ import {
26
+ definitionNames, definitionPathAny, dropLegacyIncludes, isLegacyPath,
27
+ migrateIncludes,
28
+ } from '../helpers/definition'
24
29
 
25
30
  import {
26
31
  ANCHOR,
@@ -45,6 +50,14 @@ import { KINDS } from './kind'
45
50
  const SAME_FILE_LIMIT = 5
46
51
 
47
52
 
53
+ const UNRESOLVED_INCLUDE = ['multisource_not_found', 'include_extension']
54
+
55
+ function unresolvedIncludeOnly(result: CompileResult): boolean {
56
+ return 0 < result.why.length &&
57
+ result.why.every((w: string) => UNRESOLVED_INCLUDE.includes(w))
58
+ }
59
+
60
+
48
61
  function claims(map: any, key: string): string[] {
49
62
  const value = map?.[key]
50
63
 
@@ -170,7 +183,7 @@ function checkItems(fs: any, sdk: string, manifest?: Manifest): Finding[] {
170
183
  const names = Array.from(new Set([...claimed, ...ondisk])).sort()
171
184
 
172
185
  for (const name of names) {
173
- const file = definitionPath(sdk, kind, name)
186
+ const file = definitionPathAny(fs, sdk, kind, name)
174
187
 
175
188
  if (!fs.existsSync(file)) {
176
189
  continue
@@ -188,11 +201,29 @@ function checkDefinition(
188
201
  fs: any, kind: string, name: string, file: string,
189
202
  ): Finding[] {
190
203
  const found: Finding[] = []
191
- const src = String(fs.readFileSync(file, 'utf8'))
204
+ const raw = String(fs.readFileSync(file, 'utf8'))
205
+
206
+ // Checked as a project receives it: `add` renames `.aon` includes.
207
+ const src = migrateIncludes(raw)
208
+ const legacyFile = isLegacyPath(file)
209
+ const legacy = legacyFile || src !== raw
192
210
 
193
211
  const at = (level: 'error' | 'warn', point: string, note: string): Finding =>
194
212
  ({ level, point, kind, name, file, note: file + ': ' + note })
195
213
 
214
+ if (legacy) {
215
+ const where = [
216
+ ...(legacyFile ? ['its file name'] : []),
217
+ ...(src !== raw ? ['its includes'] : []),
218
+ ].join(' and ')
219
+
220
+ found.push(at('warn', 'model-legacy-aon',
221
+ 'uses the retired `.aon` extension in ' + where + ' — `add` installs ' +
222
+ 'it as `' + name + '.aontu` with every include renamed to `.aontu`, ' +
223
+ 'the only extension aontu reads; rename them in the package so it ' +
224
+ 'holds what a project is given'))
225
+ }
226
+
196
227
  // 1. The provenance anchor. Its absence costs nothing at add time and
197
228
  // everything afterwards: the copy records no source, so `doctor` and
198
229
  // `package update` cannot find where it came from.
@@ -220,13 +251,26 @@ function checkDefinition(
220
251
  return found
221
252
  }
222
253
 
223
- const strict = compileModel(src, file)
254
+ let checked = src
255
+ let strict = compileModel(checked, file)
256
+
257
+ // The warning does not end the check: what the file itself declares is
258
+ // still checked, without the includes that cannot resolve.
259
+ if (legacy && unresolvedIncludeOnly(strict)) {
260
+ found.push(at('warn', 'model-legacy-unresolved',
261
+ strict.errors.join(' | ') + ' (an include renamed to `.aontu` ' +
262
+ 'resolves only once what it names ships as `.aontu`; until then a ' +
263
+ 'project that installs this cannot compile it)'))
264
+
265
+ checked = dropLegacyIncludes(raw)
266
+ strict = compileModel(checked, file)
267
+ }
224
268
 
225
269
  if (0 < strict.errors.length) {
226
270
  // Which parser rejected it changes what the author must do, so say. A
227
271
  // file that a bare Aontu() accepts and the strict one rejects is almost
228
272
  // always the comment dialect above.
229
- const bare = compileModel(src, file, { strict: false })
273
+ const bare = compileModel(checked, file, { strict: false })
230
274
 
231
275
  found.push(at('error', 'model-parse',
232
276
  strict.errors.join(' | ') +
@@ -249,7 +293,7 @@ function checkDefinition(
249
293
  // 5. The base schema. A non-defaulted key the file omits (`ext`,
250
294
  // `comment.line`, `module.name`, a feature's `title`) compiles fine
251
295
  // alone and fails the consumer's whole model.
252
- const unified = compileModel(src, file, { schema: true })
296
+ const unified = compileModel(checked, file, { schema: true })
253
297
 
254
298
  for (const err of unified.errors.slice(0, SAME_FILE_LIMIT)) {
255
299
  found.push(at('error', 'model-schema',
@@ -268,7 +312,7 @@ function checkDefinition(
268
312
  }
269
313
 
270
314
  if ('target' === kind) {
271
- found.push(...checkTargetModel(src, name, file, at))
315
+ found.push(...checkTargetModel(checked, name, file, at))
272
316
  }
273
317
 
274
318
  if ('feature' === kind) {
@@ -405,7 +449,7 @@ function checkFeatureSource(
405
449
  level: 'warn', point: 'feature-source-unrecognised', file,
406
450
  kind: 'target', name: tname,
407
451
  note: 'tm/' + tname + ': ' + strays.map((e) => e.path).join(', ') +
408
- ' — named like feature source, but no `model/feature/<name>.aon` ' +
452
+ ' — named like feature source, but no `model/feature/<name>.aontu` ' +
409
453
  'declares ' + strays.map((e) => e.name).join(', ') +
410
454
  ', so the trim cannot recognise them and every project gets them ' +
411
455
  'whatever its model selects'
@@ -23,7 +23,9 @@ import {
23
23
  aliasCmpName,
24
24
  } from './target'
25
25
 
26
- import { recordedRef, KINDS, kindDef, kindTrees } from './kind'
26
+ import {
27
+ recordedRef, KINDS, kindDef, kindTrees, installedModelText,
28
+ } from './kind'
27
29
  import type { TreeDef } from './kind'
28
30
 
29
31
  import { resolveSource } from './resolve'
@@ -60,7 +62,7 @@ const ROOT_COMPONENTS: [string, string][] = [
60
62
  // What the check found, by category. Categories 1-3 are drift; `additive` is
61
63
  // the project's own work and is reported separately, never as a problem.
62
64
  type DoctorReport = {
63
- // `.sdk/src/cmp/**`, or a target's own `.sdk/model/target/<t>.aon`, that
65
+ // `.sdk/src/cmp/**`, or a target's own `.sdk/model/target/<t>.aontu`, that
64
66
  // differs from the scaffold. `target add` will silently revert every one of
65
67
  // these.
66
68
  forked: string[]
@@ -184,13 +186,14 @@ function orphanModelFiles(actx: ActionContext): string[] {
184
186
  }
185
187
 
186
188
  const all = walk(fs, modeldir)
187
- .filter((rel) => rel.endsWith('.aon') || rel.endsWith('.aontu'))
189
+ .filter((rel) => rel.endsWith('.aontu') || rel.endsWith('.aon'))
188
190
  .filter((rel) => !rel.includes('.jostraca/') && !rel.startsWith('guide/'))
189
191
 
192
+ // Walked, never an entry: aontu reads no `.aon`, so a leftover is an orphan.
190
193
  const ENTRY = [
191
- 'sdk.aon', 'sdk.aontu',
192
- 'test/test.aon', 'test/test.aontu',
193
- '.model-config/model-config.aon', '.model-config/model-config.aontu',
194
+ 'sdk.aontu',
195
+ 'test/test.aontu',
196
+ '.model-config/model-config.aontu',
194
197
  ]
195
198
 
196
199
  const seen = new Set<string>()
@@ -708,7 +711,7 @@ function checkItemModel(
708
711
  const base = source.base
709
712
  const fs = actx.fs()
710
713
 
711
- const scaffold = definitionPath(source.folder, kind, origname)
714
+ const scaffold = source.model
712
715
 
713
716
  if (!fs.existsSync(scaffold)) {
714
717
  return
@@ -717,7 +720,7 @@ function checkItemModel(
717
720
  const aliased = kindDef(kind).alias && name !== origname
718
721
 
719
722
  const project = definitionPath(actx.folder, kind, name)
720
- const label = 'model/' + kind + '/' + name + '.aon'
723
+ const label = 'model/' + kind + '/' + Path.basename(project)
721
724
 
722
725
  if (!fs.existsSync(project)) {
723
726
  report.missing.push(label)
@@ -727,10 +730,7 @@ function checkItemModel(
727
730
  const provenance = provenanceReplace(
728
731
  { base, origname, name, package: source.package })
729
732
 
730
- const rename = kindDef(kind).rename
731
-
732
- const rewrite = (aliased && null != rename) ?
733
- (src: string) => rename(src, origname, name) : undefined
733
+ const rewrite = (src: string) => installedModelText(kind, source, src)
734
734
 
735
735
  if (!differs(fs, scaffold, project, actx.model, provenance, undefined, rewrite)) {
736
736
  return
@@ -140,7 +140,7 @@ const FeatureRoot = cmp(function FeatureRoot(props: any) {
140
140
  Project({}, () => {
141
141
  // The names as INSTALLED, which is what the index must list. A ref is
142
142
  // not a name: `feature add @acme/sdkgen-iot/circuitbreaker` installs
143
- // `circuitbreaker`, and writing the raw ref into feature-index.aon
143
+ // `circuitbreaker`, and writing the raw ref into feature-index.aontu
144
144
  // would produce an include of a file that does not exist.
145
145
  const fnames: string[] = []
146
146
 
@@ -1,9 +1,7 @@
1
1
  import { kindCollection } from '../helpers/kindCollection'
2
2
 
3
3
 
4
- import Path from 'node:path'
5
-
6
- import { File, Copy, Content, template } from 'jostraca'
4
+ import { File, Content } from 'jostraca'
7
5
 
8
6
  import { KIT } from '../types'
9
7
 
@@ -11,6 +9,10 @@ import { SdkGenError } from '../utility'
11
9
 
12
10
  import { provenanceReplace } from '../helpers/stdrep'
13
11
 
12
+ import {
13
+ definitionFileName, definitionPath, indexName, migrateIncludes,
14
+ } from '../helpers/definition'
15
+
14
16
  import { resolveSource, recordedRef, isBare } from './resolve'
15
17
  import type { Source } from './resolve'
16
18
 
@@ -22,9 +24,8 @@ type KindDef = {
22
24
 
23
25
  alias: boolean
24
26
 
25
- // Rewrite the definition's own text when it is installed under a different
26
- // name (targets rewrite their `main: kit: target: <name>:` key). Only
27
- // reached when `alias` is true.
27
+ // Rewrite the definition's text when an ALIAS installs it under another
28
+ // name (targets rewrite their `main: kit: target: <name>:` key).
28
29
  rename?: (src: string, origname: string, name: string) => string
29
30
 
30
31
  // Is the copied definition PROJECT-OWNED once written? An alias exists to
@@ -141,6 +142,16 @@ function resolveKind(ref: string, kind: string, ctx$: any): Source {
141
142
  }
142
143
 
143
144
 
145
+ // What `add` writes as an item's model file, and doctor re-derives to compare.
146
+ function installedModelText(kind: string, source: Source, src: string): string {
147
+ const rename = kindDef(kind).rename
148
+ const aliased = source.name !== source.origname
149
+
150
+ return migrateIncludes((aliased && null != rename) ?
151
+ rename(src, source.origname, source.name) : src)
152
+ }
153
+
154
+
144
155
  function kindModel(props: {
145
156
  ctx$: any,
146
157
  kind: string,
@@ -154,6 +165,7 @@ function kindModel(props: {
154
165
  const log = ctx$.log
155
166
 
156
167
  const aliased = source.name !== source.origname
168
+ const owned = aliased && true === def.ownedWhenAliased
157
169
 
158
170
  const replace = provenanceReplace({
159
171
  base: source.base,
@@ -162,33 +174,22 @@ function kindModel(props: {
162
174
  package: source.package,
163
175
  })
164
176
 
165
- if (aliased) {
166
- const owned = true === def.ownedWhenAliased
177
+ if (owned) {
178
+ const dest = definitionPath(ctx$.folder ?? '.', kind, source.name)
167
179
 
168
- if (owned) {
169
- const dest = Path.join(
170
- ctx$.folder ?? '.', 'model', kind, source.name + '.aon')
171
-
172
- if (fs.existsSync(dest)) {
173
- log.info({
174
- point: kind + '-alias-model-kept', [kind]: source.name, file: dest,
175
- note: source.name + ': keeping the existing aliased ' + kind +
176
- ' model (project-owned — an alias is differentiated by editing it)'
177
- })
178
- }
180
+ if (fs.existsSync(dest)) {
181
+ log.info({
182
+ point: kind + '-alias-model-kept', [kind]: source.name, file: dest,
183
+ note: source.name + ': keeping the existing aliased ' + kind +
184
+ ' model (project-owned — an alias is differentiated by editing it)'
185
+ })
179
186
  }
180
-
181
- const src = fs.readFileSync(source.model, 'utf8')
182
- const text = null == def.rename ? src :
183
- def.rename(src, source.origname, source.name)
184
-
185
- File({ name: source.name + '.aon', exclude: owned }, () =>
186
- Content(template(text, ctx$.model, { replace })))
187
- }
188
- else {
189
- Copy({ from: source.model, replace })
190
187
  }
191
188
 
189
+ const src = fs.readFileSync(source.model, 'utf8')
190
+
191
+ File({ name: definitionFileName(source.name), exclude: owned }, () =>
192
+ Content({ src: installedModelText(kind, source, src), replace }))
192
193
  }
193
194
 
194
195
 
@@ -198,7 +199,7 @@ function kindIndex(props: {
198
199
  content: string,
199
200
  }) {
200
201
  const { kind, names, content } = props
201
- File({ name: kindDef(kind).name + '-index.aon' }, () => UpdateIndex({
202
+ File({ name: indexName(kindDef(kind).name) }, () => UpdateIndex({
202
203
  content,
203
204
  names,
204
205
  }))
@@ -225,5 +226,6 @@ export {
225
226
  resolveKind,
226
227
  kindModel,
227
228
  kindIndex,
229
+ installedModelText,
228
230
  isBare,
229
231
  }
@@ -806,7 +806,7 @@ async function reAdd(
806
806
  skipped.map((i: Installed) => i.origname).join(', ') +
807
807
  ' must be ported by hand: ' +
808
808
  skipped.map((i: Installed) =>
809
- 'model/' + i.kind + '/' + i.name + '.aon').join(', ')
809
+ 'model/' + i.kind + '/' + i.name + '.aontu').join(', ')
810
810
  })
811
811
  }
812
812