@telorun/analyzer 0.73.0 → 0.74.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 (138) hide show
  1. package/dist/analyzer.d.ts.map +1 -1
  2. package/dist/analyzer.js +26 -7
  3. package/dist/artifact-axes.d.ts +14 -0
  4. package/dist/artifact-axes.d.ts.map +1 -0
  5. package/dist/artifact-axes.js +12 -0
  6. package/dist/artifact-layer-index.d.ts +2 -2
  7. package/dist/artifact-layer-index.d.ts.map +1 -1
  8. package/dist/artifact-layer-index.js +9 -4
  9. package/dist/artifact-selector.d.ts +47 -21
  10. package/dist/artifact-selector.d.ts.map +1 -1
  11. package/dist/artifact-selector.js +85 -16
  12. package/dist/builtins.d.ts.map +1 -1
  13. package/dist/builtins.js +73 -16
  14. package/dist/call-graph.d.ts +12 -1
  15. package/dist/call-graph.d.ts.map +1 -1
  16. package/dist/call-graph.js +22 -0
  17. package/dist/catch-scope.js +1 -1
  18. package/dist/forwarded-declaration.d.ts +26 -0
  19. package/dist/forwarded-declaration.d.ts.map +1 -0
  20. package/dist/forwarded-declaration.js +31 -0
  21. package/dist/index.d.ts +9 -3
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +4 -1
  24. package/dist/kernel-globals.d.ts.map +1 -1
  25. package/dist/kernel-globals.js +21 -5
  26. package/dist/module-alias-scope.d.ts +11 -0
  27. package/dist/module-alias-scope.d.ts.map +1 -1
  28. package/dist/module-alias-scope.js +10 -0
  29. package/dist/module-file-claims.d.ts +17 -1
  30. package/dist/module-file-claims.d.ts.map +1 -1
  31. package/dist/module-file-claims.js +38 -3
  32. package/dist/module-named-files.d.ts +72 -0
  33. package/dist/module-named-files.d.ts.map +1 -0
  34. package/dist/module-named-files.js +115 -0
  35. package/dist/native-entries.d.ts +83 -0
  36. package/dist/native-entries.d.ts.map +1 -0
  37. package/dist/native-entries.js +169 -0
  38. package/dist/normalize-inline-resources.d.ts +41 -13
  39. package/dist/normalize-inline-resources.d.ts.map +1 -1
  40. package/dist/normalize-inline-resources.js +236 -54
  41. package/dist/reference-field-map.d.ts +59 -1
  42. package/dist/reference-field-map.d.ts.map +1 -1
  43. package/dist/reference-field-map.js +200 -34
  44. package/dist/release/payload-digest.d.ts +2 -1
  45. package/dist/release/payload-digest.d.ts.map +1 -1
  46. package/dist/release/payload-digest.js +2 -1
  47. package/dist/resolve-ref-sentinels.d.ts.map +1 -1
  48. package/dist/resolve-ref-sentinels.js +8 -5
  49. package/dist/resolve-throws-union.d.ts +25 -4
  50. package/dist/resolve-throws-union.d.ts.map +1 -1
  51. package/dist/resolve-throws-union.js +62 -32
  52. package/dist/resolve-zone-requirements.d.ts.map +1 -1
  53. package/dist/resolve-zone-requirements.js +2 -1
  54. package/dist/rewrite-synthetic-origins.d.ts +6 -1
  55. package/dist/rewrite-synthetic-origins.d.ts.map +1 -1
  56. package/dist/rewrite-synthetic-origins.js +107 -13
  57. package/dist/schema-compat.d.ts.map +1 -1
  58. package/dist/schema-compat.js +18 -5
  59. package/dist/schema-walk.d.ts +47 -13
  60. package/dist/schema-walk.d.ts.map +1 -1
  61. package/dist/schema-walk.js +150 -30
  62. package/dist/scope-declarations.d.ts +59 -0
  63. package/dist/scope-declarations.d.ts.map +1 -0
  64. package/dist/scope-declarations.js +45 -0
  65. package/dist/source-entries.d.ts +119 -0
  66. package/dist/source-entries.d.ts.map +1 -0
  67. package/dist/source-entries.js +349 -0
  68. package/dist/step-bodies.d.ts +24 -0
  69. package/dist/step-bodies.d.ts.map +1 -0
  70. package/dist/step-bodies.js +28 -0
  71. package/dist/telo-version.d.ts +1 -1
  72. package/dist/telo-version.js +1 -1
  73. package/dist/validate-cel-context.d.ts.map +1 -1
  74. package/dist/validate-cel-context.js +3 -2
  75. package/dist/validate-module-artifact.d.ts +4 -2
  76. package/dist/validate-module-artifact.d.ts.map +1 -1
  77. package/dist/validate-module-artifact.js +43 -4
  78. package/dist/validate-native-entries.d.ts +15 -0
  79. package/dist/validate-native-entries.d.ts.map +1 -0
  80. package/dist/validate-native-entries.js +103 -0
  81. package/dist/validate-observed-state.d.ts +7 -1
  82. package/dist/validate-observed-state.d.ts.map +1 -1
  83. package/dist/validate-observed-state.js +24 -6
  84. package/dist/validate-reference-forms.d.ts.map +1 -1
  85. package/dist/validate-reference-forms.js +2 -2
  86. package/dist/validate-references.d.ts.map +1 -1
  87. package/dist/validate-references.js +11 -5
  88. package/dist/validate-scope-reach.d.ts +31 -0
  89. package/dist/validate-scope-reach.d.ts.map +1 -0
  90. package/dist/validate-scope-reach.js +180 -0
  91. package/dist/validate-source-entries.d.ts +16 -0
  92. package/dist/validate-source-entries.d.ts.map +1 -0
  93. package/dist/validate-source-entries.js +90 -0
  94. package/dist/validate-throws-coverage.d.ts.map +1 -1
  95. package/dist/validate-throws-coverage.js +21 -39
  96. package/dist/value-type-keyword.d.ts +22 -5
  97. package/dist/value-type-keyword.d.ts.map +1 -1
  98. package/dist/value-type-keyword.js +16 -7
  99. package/package.json +3 -3
  100. package/src/analyzer.ts +33 -9
  101. package/src/artifact-axes.ts +24 -0
  102. package/src/artifact-layer-index.ts +9 -6
  103. package/src/artifact-selector.ts +110 -35
  104. package/src/builtins.ts +75 -16
  105. package/src/call-graph.ts +30 -0
  106. package/src/catch-scope.ts +1 -1
  107. package/src/forwarded-declaration.ts +32 -0
  108. package/src/index.ts +36 -1
  109. package/src/kernel-globals.ts +28 -5
  110. package/src/migrations/CLAUDE.md +35 -0
  111. package/src/module-alias-scope.ts +17 -0
  112. package/src/module-file-claims.ts +63 -4
  113. package/src/module-named-files.ts +162 -0
  114. package/src/native-entries.ts +227 -0
  115. package/src/normalize-inline-resources.ts +326 -70
  116. package/src/reference-field-map.ts +257 -52
  117. package/src/release/CLAUDE.md +32 -0
  118. package/src/release/payload-digest.ts +2 -1
  119. package/src/resolve-ref-sentinels.ts +7 -6
  120. package/src/resolve-throws-union.ts +87 -32
  121. package/src/resolve-zone-requirements.ts +2 -1
  122. package/src/rewrite-synthetic-origins.ts +107 -16
  123. package/src/schema-compat.ts +18 -4
  124. package/src/schema-walk.ts +162 -34
  125. package/src/scope-declarations.ts +98 -0
  126. package/src/source-entries.ts +502 -0
  127. package/src/step-bodies.ts +55 -0
  128. package/src/telo-version.ts +1 -1
  129. package/src/validate-cel-context.ts +3 -2
  130. package/src/validate-module-artifact.ts +46 -3
  131. package/src/validate-native-entries.ts +147 -0
  132. package/src/validate-observed-state.ts +36 -7
  133. package/src/validate-reference-forms.ts +2 -3
  134. package/src/validate-references.ts +10 -6
  135. package/src/validate-scope-reach.ts +213 -0
  136. package/src/validate-source-entries.ts +120 -0
  137. package/src/validate-throws-coverage.ts +24 -31
  138. package/src/value-type-keyword.ts +35 -9
@@ -0,0 +1,115 @@
1
+ /**
2
+ * The rules that relate a module's `native:` entries, its file claims and its
3
+ * `sources:` block — which files a source may stage, which declarations collide
4
+ * on one path, and which staged entries nothing names.
5
+ *
6
+ * One home, because `telo check` (`validate-native-entries.ts`,
7
+ * `validate-source-entries.ts`) and `telo publish` apply the same rules to the
8
+ * same manifest; two copies would each drift toward whatever its own tests pin.
9
+ * Callers read the three blocks with their own readers and hand the results in.
10
+ * Browser-safe: no filesystem.
11
+ */
12
+ import { PLATFORM_AXES, describeSelector } from "./artifact-selector.js";
13
+ const CLAIM_LABEL = {
14
+ controller: "the controller candidate",
15
+ library: "the exports.code entry",
16
+ assets: "the embed",
17
+ };
18
+ /** The declaration behind a claim, for messages: `the controller candidate pkg:… on Telo.Definition/Reader`. */
19
+ export function describeClaim(located) {
20
+ const { claim, where } = located;
21
+ return `${CLAIM_LABEL[claim.role]} ${claim.origin}${where === undefined ? "" : ` on ${where}`}`;
22
+ }
23
+ /**
24
+ * Every `native:` entry whose path the module also names as code or as an embed.
25
+ * Each declaration decides a different layer, and a file extracts from exactly
26
+ * one — a runtime materializing one would find the file missing through the other.
27
+ */
28
+ export function nativeClaimConflicts(native, claims) {
29
+ const out = [];
30
+ for (const entry of native) {
31
+ for (const claim of claims) {
32
+ if (claim.claim.path === entry.path)
33
+ out.push({ entry, claim });
34
+ }
35
+ }
36
+ return out;
37
+ }
38
+ /**
39
+ * The files the module names that a `sources:` entry may stage: every `native:`
40
+ * entry's path, and every bundled controller candidate's `path=` that carries a
41
+ * platform qualifier. A platform-neutral candidate is one bundle for every host,
42
+ * which nothing stages.
43
+ */
44
+ export function stageableFiles(native, claims) {
45
+ const out = new Map();
46
+ for (const entry of native) {
47
+ if (out.has(entry.path))
48
+ continue;
49
+ out.set(entry.path, {
50
+ path: entry.path,
51
+ label: `${entry.origin} for ${describeSelector(entry.selector)}`,
52
+ layer: `native ${describeSelector(entry.selector)}`,
53
+ built: false,
54
+ });
55
+ }
56
+ for (const { claim } of claims) {
57
+ if (claim.role !== "controller")
58
+ continue;
59
+ if (!PLATFORM_AXES.some((axis) => claim.selector[axis] !== undefined))
60
+ continue;
61
+ const existing = out.get(claim.path);
62
+ if (existing) {
63
+ if (claim.localPath && !existing.built)
64
+ out.set(claim.path, { ...existing, built: true });
65
+ continue;
66
+ }
67
+ out.set(claim.path, {
68
+ path: claim.path,
69
+ label: `controller candidate ${claim.origin}`,
70
+ layer: `controller ${describeSelector(claim.selector)}`,
71
+ built: claim.localPath !== undefined,
72
+ });
73
+ }
74
+ return out;
75
+ }
76
+ /**
77
+ * The staged entries nothing in the module names: not a stageable file, and not
78
+ * one of the entry's own source's notices. `alsoNamed` holds paths the caller
79
+ * knows are named though they did not read — a `native:` entry with an unrelated
80
+ * problem — so one defect is not reported twice.
81
+ */
82
+ export function unclaimedSourceEntries(sources, stageable, alsoNamed = new Set()) {
83
+ const out = [];
84
+ for (const source of sources) {
85
+ for (const entry of source.entries) {
86
+ if (stageable.has(entry.path) || source.notices.includes(entry.path))
87
+ continue;
88
+ if (alsoNamed.has(entry.path))
89
+ continue;
90
+ out.push({ source, entry });
91
+ }
92
+ }
93
+ return out;
94
+ }
95
+ /**
96
+ * The link entries whose target ships in another layer. A runtime extracts only
97
+ * the layers it needs, so such a link dangles wherever the other layer is not
98
+ * materialized. A notice ships in `common`.
99
+ */
100
+ export function crossLayerSourceLinks(sources, stageable) {
101
+ const layerOf = (source, path) => stageable.get(path)?.layer ?? (source.notices.includes(path) ? "common" : undefined);
102
+ const out = [];
103
+ for (const source of sources) {
104
+ for (const entry of source.entries) {
105
+ if (entry.kind !== "link")
106
+ continue;
107
+ const layer = layerOf(source, entry.path);
108
+ const targetLayer = layerOf(source, entry.resolved);
109
+ if (layer !== undefined && targetLayer !== undefined && layer !== targetLayer) {
110
+ out.push({ source, entry, layer, targetLayer });
111
+ }
112
+ }
113
+ }
114
+ return out;
115
+ }
@@ -0,0 +1,83 @@
1
+ /**
2
+ * A module's **native files** — the `native:` block on a `Telo.Library` or
3
+ * `Telo.Application` doc, naming each platform-specific file the runtime does
4
+ * not import as a controller (a sidecar addon, a `dlopen`'d library, a
5
+ * per-platform data blob) once per platform tuple.
6
+ *
7
+ * ```yaml
8
+ * native:
9
+ * - name: better-sqlite3
10
+ * format: node
11
+ * os: linux
12
+ * arch: amd64
13
+ * libc: gnu
14
+ * abi: node-137
15
+ * path: ./native/linux-amd64-gnu-node-137/better_sqlite3.node
16
+ * ```
17
+ *
18
+ * Declared on the module doc rather than on a controller candidate, so the
19
+ * platform matrix is written once whatever the kind count, and the
20
+ * platform-neutral bundle ships once. Publish places each entry's file in the
21
+ * `native` layer of its selector (spec §1.2).
22
+ *
23
+ * `format` plus the platform axes build the same `ArtifactSelector` a
24
+ * controller candidate does, through the one selector normalizer. The declared
25
+ * `path` is the in-layer path — never flattened — because every layer of a
26
+ * module extracts into one directory, so paths must be disjoint per tuple.
27
+ *
28
+ * The single reader: the strict half is `validate-native-entries.ts`, and
29
+ * publish consumes the entries this returns. Browser-safe: string work only.
30
+ */
31
+ import { type ArtifactSelector } from "./artifact-selector.js";
32
+ export interface NativeEntry {
33
+ /** The logical name controller code asks for. */
34
+ readonly name: string;
35
+ readonly selector: ArtifactSelector;
36
+ /** Module-root-relative POSIX path, normalized. */
37
+ readonly path: string;
38
+ /** Position in the `native:` list. */
39
+ readonly index: number;
40
+ /** Human-facing label for diagnostics: `native[0] ('better-sqlite3')`. */
41
+ readonly origin: string;
42
+ }
43
+ /**
44
+ * Why an entry could not be read.
45
+ *
46
+ * - `shape` — a missing, non-string or unknown key; the owner doc's JSON Schema
47
+ * reports these in the same analysis pass.
48
+ * - `invalid` — a value the schema accepts and the grammar rejects: an empty
49
+ * required string, a `name` or selector value outside the token grammar, an
50
+ * `abi` outside its value form, a path that names no single file.
51
+ * - `escape` — a `path` pointing outside the module directory.
52
+ */
53
+ export interface NativeEntryProblem {
54
+ readonly kind: "shape" | "invalid" | "escape";
55
+ readonly index?: number;
56
+ readonly origin: string;
57
+ /** Dotted/bracketed path from the module doc root, for `data.path`. */
58
+ readonly path: string;
59
+ /** What is wrong, prefixed with `origin`. */
60
+ readonly message: string;
61
+ }
62
+ export interface NativeEntries {
63
+ readonly entries: NativeEntry[];
64
+ readonly problems: NativeEntryProblem[];
65
+ }
66
+ export type PathVerdict = {
67
+ path: string;
68
+ } | {
69
+ kind: "invalid" | "escape";
70
+ detail: string;
71
+ };
72
+ /** Normalize a module-relative path, deciding confinement from the written
73
+ * path alone: the module root is the one directory every path is measured
74
+ * from, so `..` below depth zero is an escape wherever the module sits. */
75
+ export declare function normalizeNativePath(raw: string): PathVerdict;
76
+ /**
77
+ * Read the `native:` block off an owner document's JSON projection.
78
+ *
79
+ * An entry with any problem is left out of `entries`, never read partially: a
80
+ * half-read entry would name a layer the author did not declare.
81
+ */
82
+ export declare function readNativeEntries(ownerJson: unknown): NativeEntries;
83
+ //# sourceMappingURL=native-entries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-entries.d.ts","sourceRoot":"","sources":["../src/native-entries.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,wBAAwB,CAAC;AAchC,MAAM,WAAW,WAAW;IAC1B,iDAAiD;IACjD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,mDAAmD;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,0EAA0E;IAC1E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC9C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,uEAAuE;IACvE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,6CAA6C;IAC7C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,EAAE,CAAC;CACzC;AAED,MAAM,MAAM,WAAW,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5F;;4EAE4E;AAC5E,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAgC5D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,OAAO,GAAG,aAAa,CA8FnE"}
@@ -0,0 +1,169 @@
1
+ /**
2
+ * A module's **native files** — the `native:` block on a `Telo.Library` or
3
+ * `Telo.Application` doc, naming each platform-specific file the runtime does
4
+ * not import as a controller (a sidecar addon, a `dlopen`'d library, a
5
+ * per-platform data blob) once per platform tuple.
6
+ *
7
+ * ```yaml
8
+ * native:
9
+ * - name: better-sqlite3
10
+ * format: node
11
+ * os: linux
12
+ * arch: amd64
13
+ * libc: gnu
14
+ * abi: node-137
15
+ * path: ./native/linux-amd64-gnu-node-137/better_sqlite3.node
16
+ * ```
17
+ *
18
+ * Declared on the module doc rather than on a controller candidate, so the
19
+ * platform matrix is written once whatever the kind count, and the
20
+ * platform-neutral bundle ships once. Publish places each entry's file in the
21
+ * `native` layer of its selector (spec §1.2).
22
+ *
23
+ * `format` plus the platform axes build the same `ArtifactSelector` a
24
+ * controller candidate does, through the one selector normalizer. The declared
25
+ * `path` is the in-layer path — never flattened — because every layer of a
26
+ * module extracts into one directory, so paths must be disjoint per tuple.
27
+ *
28
+ * The single reader: the strict half is `validate-native-entries.ts`, and
29
+ * publish consumes the entries this returns. Browser-safe: string work only.
30
+ */
31
+ import { ArtifactSelectorError, PLATFORM_AXES, selectorFromQualifiers, } from "./artifact-selector.js";
32
+ /** Every key an entry may carry. */
33
+ const KNOWN_KEYS = new Set(["name", "format", "path", ...PLATFORM_AXES]);
34
+ /** Axes an entry must state: a native file is built for one platform. */
35
+ const REQUIRED_AXES = ["os", "arch"];
36
+ /** The selector value grammar, applied to `name` as written. */
37
+ const NAME_TOKEN = /^[a-z0-9][a-z0-9_.-]*$/;
38
+ const GLOB_CHARS = /[*?[\]{}]/;
39
+ const URI_SCHEME = /^[a-z][a-z0-9+.-]*:/i;
40
+ /** Normalize a module-relative path, deciding confinement from the written
41
+ * path alone: the module root is the one directory every path is measured
42
+ * from, so `..` below depth zero is an escape wherever the module sits. */
43
+ export function normalizeNativePath(raw) {
44
+ if (URI_SCHEME.test(raw) || raw.startsWith("/") || raw.startsWith("\\")) {
45
+ return {
46
+ kind: "escape",
47
+ detail: `path '${raw}' is not relative to the module root. A native file ships inside the module artifact, so name it relative to the directory holding telo.yaml.`,
48
+ };
49
+ }
50
+ if (GLOB_CHARS.test(raw)) {
51
+ return {
52
+ kind: "invalid",
53
+ detail: `path '${raw}' looks like a pattern. A native entry names exactly one file.`,
54
+ };
55
+ }
56
+ const out = [];
57
+ for (const segment of raw.split(/[/\\]+/)) {
58
+ if (segment === "" || segment === ".")
59
+ continue;
60
+ if (segment !== "..") {
61
+ out.push(segment);
62
+ continue;
63
+ }
64
+ if (out.length === 0) {
65
+ return {
66
+ kind: "escape",
67
+ detail: `path '${raw}' points above the module root. A native file must ship inside the module directory.`,
68
+ };
69
+ }
70
+ out.pop();
71
+ }
72
+ if (out.length === 0) {
73
+ return { kind: "invalid", detail: `path '${raw}' resolves to the module root, not to a file.` };
74
+ }
75
+ return { path: out.join("/") };
76
+ }
77
+ /**
78
+ * Read the `native:` block off an owner document's JSON projection.
79
+ *
80
+ * An entry with any problem is left out of `entries`, never read partially: a
81
+ * half-read entry would name a layer the author did not declare.
82
+ */
83
+ export function readNativeEntries(ownerJson) {
84
+ const declared = ownerJson?.native;
85
+ const entries = [];
86
+ const problems = [];
87
+ if (declared === undefined)
88
+ return { entries, problems };
89
+ if (!Array.isArray(declared)) {
90
+ problems.push({
91
+ kind: "shape",
92
+ origin: "native",
93
+ path: "native",
94
+ message: "native: expected a list of entries.",
95
+ });
96
+ return { entries, problems };
97
+ }
98
+ declared.forEach((raw, index) => {
99
+ const at = `native[${index}]`;
100
+ const shape = (detail) => problems.push({ kind: "shape", index, origin: at, path: at, message: `${at}: ${detail}` });
101
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
102
+ shape("expected an object.");
103
+ return;
104
+ }
105
+ const entry = raw;
106
+ const unknown = Object.keys(entry).filter((key) => !KNOWN_KEYS.has(key));
107
+ if (unknown.length > 0) {
108
+ shape(`unknown ${unknown.length === 1 ? "key" : "keys"} ${unknown.map((k) => `'${k}'`).join(", ")}. ` +
109
+ `Known: ${[...KNOWN_KEYS].join(", ")}.`);
110
+ return;
111
+ }
112
+ const requiredKeys = ["name", "format", ...REQUIRED_AXES, "path"];
113
+ const missing = requiredKeys.filter((key) => typeof entry[key] !== "string");
114
+ if (missing.length > 0) {
115
+ shape(`${missing.map((k) => `'${k}'`).join(", ")} must be strings.`);
116
+ return;
117
+ }
118
+ // A blank string satisfies the schema's `type: string`, so it is reported here.
119
+ const blank = requiredKeys.filter((key) => entry[key].trim() === "");
120
+ if (blank.length > 0) {
121
+ for (const key of blank) {
122
+ problems.push({
123
+ kind: "invalid",
124
+ index,
125
+ origin: at,
126
+ path: `${at}.${key}`,
127
+ message: `${at}: '${key}' must not be empty.`,
128
+ });
129
+ }
130
+ return;
131
+ }
132
+ const name = entry.name;
133
+ const origin = `${at} ('${name}')`;
134
+ if (!NAME_TOKEN.test(name)) {
135
+ problems.push({
136
+ kind: "invalid",
137
+ index,
138
+ origin,
139
+ path: `${at}.name`,
140
+ message: `${origin}: name '${name}' is not a canonical token. Use lowercase letters, digits, ` +
141
+ `'.', '-' or '_', starting with a letter or digit.`,
142
+ });
143
+ return;
144
+ }
145
+ let selector;
146
+ try {
147
+ selector = selectorFromQualifiers(entry.format, entry, origin);
148
+ }
149
+ catch (err) {
150
+ if (!(err instanceof ArtifactSelectorError))
151
+ throw err;
152
+ problems.push({ kind: "invalid", index, origin, path: at, message: err.message });
153
+ return;
154
+ }
155
+ const verdict = normalizeNativePath(entry.path.trim());
156
+ if (!("path" in verdict)) {
157
+ problems.push({
158
+ kind: verdict.kind,
159
+ index,
160
+ origin,
161
+ path: `${at}.path`,
162
+ message: `${origin}: ${verdict.detail}`,
163
+ });
164
+ return;
165
+ }
166
+ entries.push({ name, selector, path: verdict.path, index, origin });
167
+ });
168
+ return { entries, problems };
169
+ }
@@ -1,23 +1,51 @@
1
- import type { ResourceManifest } from "@telorun/sdk";
2
- import type { DefinitionRegistry } from "./definition-registry.js";
1
+ import { type ResourceManifest } from "@telorun/sdk";
3
2
  import type { AliasResolver } from "./alias-resolver.js";
3
+ import type { DefinitionRegistry } from "./definition-registry.js";
4
4
  /**
5
5
  * Phase 2 — Inline resource normalization.
6
6
  *
7
- * After all manifests and definitions are loaded, walks every non-system resource's
8
- * x-telo-ref slots. For each inline resource value (has keys beyond kind/name/metadata),
9
- * assigns a deterministic name, extracts it as a first-class manifest, and replaces
10
- * the inline value in-place with `{kind, name}`. Newly extracted resources are enqueued
11
- * so nested inlines are resolved in the same pass.
7
+ * Every inline declaration (a `{kind, …config}` with no `name`) is extracted as a
8
+ * first-class manifest under a deterministic name and replaced in place with
9
+ * `{kind, name}`. Two kinds of slot carry one:
10
+ *
11
+ * - a REFERENCE slot, found through the kind's field map, named
12
+ * `{parentName}_{pathSegment}[_{itemName|index}]_{fieldName}`
13
+ * (`TestBasicAddition_steps_AddTwoNumbers_invoke`);
14
+ * - a STEP's dispatch target, at any nesting depth of a step body, named by
15
+ * `inlineStepTargetName` — the name the step engine has always registered it
16
+ * under, which is durable identity and so must not move with the extraction.
17
+ *
18
+ * Step slots are found through the kind's step-body annotation and walked with
19
+ * `walkStepArray`, never through the field map: that map is the kernel's Phase-5
20
+ * injection surface, and a step's target resolves at dispatch.
21
+ *
22
+ * Every extracted manifest is queued in turn, so an inline declaration nested in
23
+ * another's slots — a handler inside an inline step target — is extracted too.
24
+ * So is every member of an `x-telo-scope` array, which is a declaration of its
25
+ * own.
26
+ *
27
+ * WHERE an extraction is created:
28
+ *
29
+ * - a reference slot lying in a region of a scope its owner declares (a
30
+ * sequence's `targets:`) resolves against that scope, so its declaration
31
+ * joins the scope's array and is created per scope run;
32
+ * - a step target is created where its owner is — the module's top level, or
33
+ * the scope array holding a scope member — and never in a scope the owner
34
+ * declares, because that would make every step target of a sequence with a
35
+ * `with:` block a scoped resource and move its durable identity;
36
+ * - any other extraction is created where its owner is.
37
+ *
38
+ * A declaration written inside a scope's region and created outside it records
39
+ * the scope (`xTeloOrigin.outsideScopes`), and `validateScopedNameReach` reports
40
+ * a reference from it to a name that scope declares.
12
41
  *
13
- * Naming scheme:
14
- * {parentName}_{pathSegment}[_{itemName|index}]_{fieldName}
15
- * e.g. TestBasicAddition_steps_AddTwoNumbers_invoke
16
- * TestBasicAddition_steps_0_invoke (when step has no name)
42
+ * An extraction out of a dependency's forwarded manifest is that dependency's
43
+ * code: it is stamped `forwardedInternal` (see `isForwardedDeclaration`) and
44
+ * carries the declaring module's `moduleGlobals`, as its parent does.
17
45
  *
18
46
  * Returns a new array of deep-cloned manifests (the rewrites land on the clones)
19
- * plus all extracted manifests. The caller's manifests — array and elements — are
20
- * never mutated; this is the analyzer's immutability boundary.
47
+ * plus every top-level extraction. The caller's manifests — array and elements —
48
+ * are never mutated; this is the analyzer's immutability boundary.
21
49
  */
22
50
  export declare function normalizeInlineResources(resources: ResourceManifest[], registry: DefinitionRegistry, aliases?: AliasResolver, aliasesByModule?: Map<string, AliasResolver>): ResourceManifest[];
23
51
  //# sourceMappingURL=normalize-inline-resources.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"normalize-inline-resources.d.ts","sourceRoot":"","sources":["../src/normalize-inline-resources.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AA6CzD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,gBAAgB,EAAE,EAC7B,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,CAAC,EAAE,aAAa,EACvB,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,GAC3C,gBAAgB,EAAE,CA0EpB"}
1
+ {"version":3,"file":"normalize-inline-resources.d.ts","sourceRoot":"","sources":["../src/normalize-inline-resources.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiD,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEpG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAqGnE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,gBAAgB,EAAE,EAC7B,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,CAAC,EAAE,aAAa,EACvB,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,GAC3C,gBAAgB,EAAE,CAuGpB"}