@telorun/analyzer 0.61.0 → 0.62.1

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 (73) hide show
  1. package/dist/analyzer.d.ts.map +1 -1
  2. package/dist/analyzer.js +130 -9
  3. package/dist/builtins.d.ts.map +1 -1
  4. package/dist/builtins.js +69 -12
  5. package/dist/cel-bindings.d.ts +0 -6
  6. package/dist/cel-bindings.d.ts.map +1 -1
  7. package/dist/cel-bindings.js +3 -28
  8. package/dist/definition-registry.d.ts +17 -0
  9. package/dist/definition-registry.d.ts.map +1 -1
  10. package/dist/definition-registry.js +31 -2
  11. package/dist/identifier-name.d.ts +114 -0
  12. package/dist/identifier-name.d.ts.map +1 -0
  13. package/dist/identifier-name.js +183 -0
  14. package/dist/index.d.ts +10 -0
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +8 -0
  17. package/dist/manifest-schemas.d.ts +81 -0
  18. package/dist/manifest-schemas.d.ts.map +1 -1
  19. package/dist/manifest-schemas.js +208 -6
  20. package/dist/release/payload-digest.d.ts +7 -3
  21. package/dist/release/payload-digest.d.ts.map +1 -1
  22. package/dist/release/payload-digest.js +7 -3
  23. package/dist/requires-block.d.ts +125 -0
  24. package/dist/requires-block.d.ts.map +1 -0
  25. package/dist/requires-block.js +182 -0
  26. package/dist/schema-keywords.d.ts +68 -0
  27. package/dist/schema-keywords.d.ts.map +1 -0
  28. package/dist/schema-keywords.js +324 -0
  29. package/dist/schema-region.d.ts +12 -1
  30. package/dist/schema-region.d.ts.map +1 -1
  31. package/dist/schema-region.js +12 -1
  32. package/dist/telo-version.d.ts +3 -0
  33. package/dist/telo-version.d.ts.map +1 -0
  34. package/dist/telo-version.js +8 -0
  35. package/dist/types.d.ts +31 -0
  36. package/dist/types.d.ts.map +1 -1
  37. package/dist/validate-identifier-names.d.ts +31 -0
  38. package/dist/validate-identifier-names.d.ts.map +1 -0
  39. package/dist/validate-identifier-names.js +144 -0
  40. package/dist/validate-observed-state.d.ts +9 -2
  41. package/dist/validate-observed-state.d.ts.map +1 -1
  42. package/dist/validate-observed-state.js +9 -2
  43. package/dist/validate-references.d.ts.map +1 -1
  44. package/dist/validate-references.js +5 -26
  45. package/dist/validate-requires.d.ts +49 -0
  46. package/dist/validate-requires.d.ts.map +1 -0
  47. package/dist/validate-requires.js +99 -0
  48. package/dist/value-type-keyword.d.ts +1 -1
  49. package/dist/value-type-keyword.d.ts.map +1 -1
  50. package/dist/value-type-keyword.js +1 -0
  51. package/dist/version-range.d.ts +88 -0
  52. package/dist/version-range.d.ts.map +1 -0
  53. package/dist/version-range.js +173 -0
  54. package/package.json +2 -2
  55. package/src/analyzer.ts +146 -10
  56. package/src/builtins.ts +73 -12
  57. package/src/cel-bindings.ts +3 -28
  58. package/src/definition-registry.ts +30 -2
  59. package/src/identifier-name.ts +228 -0
  60. package/src/index.ts +34 -0
  61. package/src/manifest-schemas.ts +223 -4
  62. package/src/release/payload-digest.ts +7 -3
  63. package/src/requires-block.ts +253 -0
  64. package/src/schema-keywords.ts +359 -0
  65. package/src/schema-region.ts +12 -1
  66. package/src/telo-version.ts +9 -0
  67. package/src/types.ts +32 -0
  68. package/src/validate-identifier-names.ts +173 -0
  69. package/src/validate-observed-state.ts +9 -2
  70. package/src/validate-references.ts +5 -26
  71. package/src/validate-requires.ts +129 -0
  72. package/src/value-type-keyword.ts +1 -0
  73. package/src/version-range.ts +238 -0
@@ -25,9 +25,13 @@ export declare const MANIFEST_LAYER = "manifest";
25
25
  * Exactly one today, and for a structural reason rather than an omission: the
26
26
  * published `layers:` index lives *inside* `telo.yaml`, so it cannot carry that
27
27
  * file's own digest — the entry would have to be computed over bytes containing
28
- * it. Nor can the digest be recovered by hashing what the registry serves, since
29
- * the transport injects the index at push time and the published text is
30
- * therefore not the text the payload builder produced.
28
+ * it. `readPublishedDigests` reads that index, so it has no answer for this key.
29
+ *
30
+ * It is no longer *unknowable*, though, only absent from the index: the payload
31
+ * builder now writes the index, so its manifest is the published text and this
32
+ * digest is what hashing the served `telo.yaml` yields. Reconciling it would
33
+ * mean fetching the manifest per module rather than reading one index — worth
34
+ * doing, and a separate change from the one that made it possible.
31
35
  *
32
36
  * It stays in the ledger regardless, because it is the only thing that sees a
33
37
  * **manifest-only change**: a schema edit, a new kind, a description, a
@@ -1 +1 @@
1
- {"version":3,"file":"payload-digest.d.ts","sourceRoot":"","sources":["../../src/release/payload-digest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAiB,KAAK,gBAAgB,EAAE,KAAK,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAE/F,sDAAsD;AACtD,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAE5D,yDAAyD;AACzD,eAAO,MAAM,cAAc,aAAa,CAAC;AAEzC;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,sBAAsB,EAAE,WAAW,CAAC,MAAM,CAA6B,CAAC;AAErF;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,EAAE,QAAQ,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAM5F;AAED;;;mBAGmB;AACnB,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;mCACmC;AACnC,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,GAAG,WAAW,EAAE,CAQzF"}
1
+ {"version":3,"file":"payload-digest.d.ts","sourceRoot":"","sources":["../../src/release/payload-digest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAiB,KAAK,gBAAgB,EAAE,KAAK,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAE/F,sDAAsD;AACtD,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAE5D,yDAAyD;AACzD,eAAO,MAAM,cAAc,aAAa,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,sBAAsB,EAAE,WAAW,CAAC,MAAM,CAA6B,CAAC;AAErF;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,EAAE,QAAQ,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAM5F;AAED;;;mBAGmB;AACnB,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;mCACmC;AACnC,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,GAAG,WAAW,EAAE,CAQzF"}
@@ -23,9 +23,13 @@ export const MANIFEST_LAYER = "manifest";
23
23
  * Exactly one today, and for a structural reason rather than an omission: the
24
24
  * published `layers:` index lives *inside* `telo.yaml`, so it cannot carry that
25
25
  * file's own digest — the entry would have to be computed over bytes containing
26
- * it. Nor can the digest be recovered by hashing what the registry serves, since
27
- * the transport injects the index at push time and the published text is
28
- * therefore not the text the payload builder produced.
26
+ * it. `readPublishedDigests` reads that index, so it has no answer for this key.
27
+ *
28
+ * It is no longer *unknowable*, though, only absent from the index: the payload
29
+ * builder now writes the index, so its manifest is the published text and this
30
+ * digest is what hashing the served `telo.yaml` yields. Reconciling it would
31
+ * mean fetching the manifest per module rather than reading one index — worth
32
+ * doing, and a separate change from the one that made it possible.
29
33
  *
30
34
  * It stays in the ledger regardless, because it is the only thing that sees a
31
35
  * **manifest-only change**: a schema edit, a new kind, a description, a
@@ -0,0 +1,125 @@
1
+ /**
2
+ * The single reader of a module doc's `requires:` block — the version ranges of
3
+ * runtime a module declares itself verified against. The load gate, the CLI's
4
+ * publish preflight and `upgrade`'s candidate filter all recognise the block
5
+ * here and nowhere else, the one-accessor rule `ref-slot.ts` and `zone-slot.ts`
6
+ * established. Browser-safe: no Node built-ins, so the editor reaches the
7
+ * identical rule the kernel does.
8
+ *
9
+ * ```yaml
10
+ * requires:
11
+ * telo: ">=0.80.0"
12
+ * host:
13
+ * node: ">=20.0.0"
14
+ * ```
15
+ *
16
+ * **Two tiers, and the split is not cosmetic.** `telo` names the *manifest
17
+ * surface generation* a runtime implements — one scale shared by every kernel,
18
+ * Node, Rust or Go, independent of each kernel's own release identity — and it
19
+ * is the one axis verified by EXECUTION, by running the CLI at each edge of the
20
+ * declared range. Host axes cannot be edge-verified by any CI; they are asserted
21
+ * by the author and compared against the version the running host reports
22
+ * ({@link HostVersions}). A flat map would imply one semantics for both.
23
+ *
24
+ * Nesting is also what disambiguates the names: `nodejs` and `rust` are already
25
+ * *kernel labels* in this repo (`LABEL_TO_PURL_TYPE`, an `imports:` entry's
26
+ * `runtime:`), so a top-level `node:` reads as the Node kernel rather than the
27
+ * Node.js runtime — and no word escapes that, because the host runtime and the
28
+ * kernel implementation genuinely share a name. Under `host:` position carries
29
+ * the disambiguation and no word has to.
30
+ *
31
+ * **Ordering is normative: `telo` is checked before `host`, and before any
32
+ * unknown-axis complaint.** A module using an axis introduced in telo 0.85 also
33
+ * declares telo `>=0.85`, so an older runtime fails on the telo axis first and
34
+ * never has to decide what an axis it has never heard of means. That is what
35
+ * makes the block safely extensible; consumers get the order from
36
+ * {@link evaluateRequires} rather than re-deriving it.
37
+ */
38
+ import { type VersionRange } from "./version-range.js";
39
+ /**
40
+ * Host axes this analyzer knows.
41
+ *
42
+ * **An axis is in this list only when something checks it.** A declared
43
+ * requirement nothing compares is worse than no requirement at all: it validates,
44
+ * it reads as protection, and it silently protects nobody — the exact failure
45
+ * class this whole mechanism exists to remove, reintroduced inside it. So `rustc`
46
+ * is deliberately absent until the slice that builds controller crates can
47
+ * compare it; adding it there is a one-line change here plus a supplier in
48
+ * {@link HostVersions}, and until then an author writing it is told it is not a
49
+ * known axis rather than quietly reassured.
50
+ *
51
+ * Extending the set is a telo release, which is exactly why a module using a new
52
+ * axis must also raise its `telo` bound — and why `telo` is checked first.
53
+ */
54
+ export declare const KNOWN_HOST_AXES: readonly ["node"];
55
+ export type HostAxis = (typeof KNOWN_HOST_AXES)[number];
56
+ export interface RequiresBlock {
57
+ /** The surface generation range, when declared. */
58
+ telo?: VersionRange;
59
+ /** Declared host axes, keyed by axis name. Empty when `host:` is absent. */
60
+ host: Partial<Record<HostAxis, VersionRange>>;
61
+ }
62
+ export interface RequiresIssue {
63
+ /** Dotted path within the doc, e.g. `requires.telo` or `requires.host.node`. */
64
+ path: string;
65
+ message: string;
66
+ /** The spelling to use instead, when there is an unambiguous one. */
67
+ hint?: string;
68
+ /** True for an unrecognized axis, which consumers suppress while the `telo`
69
+ * requirement itself is unmet — an older runtime not knowing a newer axis is
70
+ * a consequence of the version skew, not a second defect to report. */
71
+ unknownAxis?: boolean;
72
+ }
73
+ export interface ReadRequiresResult {
74
+ /** Present whenever the doc carries a `requires:` key at all, even a malformed
75
+ * one — so a consumer can tell "declared nothing" from "declared badly". */
76
+ declared: boolean;
77
+ block: RequiresBlock;
78
+ issues: RequiresIssue[];
79
+ }
80
+ /**
81
+ * Read and parse the block off a module doc. Never throws. A malformed entry
82
+ * yields an issue AND is omitted from the block, so a consumer enforcing the
83
+ * block never silently treats garbage as a satisfied requirement — the issue is
84
+ * what makes the manifest fail, exactly as a malformed zone annotation does.
85
+ */
86
+ export declare function readRequires(doc: Record<string, unknown> | undefined): ReadRequiresResult;
87
+ /** What a runtime concluded about a module's declared requirements. */
88
+ export type RequiresVerdict = {
89
+ satisfied: true;
90
+ }
91
+ /** An axis whose declared range excludes the version this runtime reported. */
92
+ | {
93
+ satisfied: false;
94
+ axis: "telo" | HostAxis;
95
+ declared: VersionRange;
96
+ running: string;
97
+ };
98
+ /** The versions a host can speak for. Absent entries are not checked — the
99
+ * editor has no host to report, and an axis nothing supplies is skipped rather
100
+ * than guessed. Every axis in {@link KNOWN_HOST_AXES} has a supplier; an axis
101
+ * with none does not belong in the vocabulary (see the note there). */
102
+ export interface HostVersions {
103
+ node?: string;
104
+ }
105
+ /**
106
+ * Evaluate a module's declared requirements against the runtime performing the
107
+ * analysis.
108
+ *
109
+ * `telo` is checked FIRST and short-circuits: a module using a host axis
110
+ * introduced in a later telo also declares that telo, so an older runtime must
111
+ * report the version skew rather than a host axis it may not even know. Absent
112
+ * declarations are satisfied — the bootstrap rule, permanent for everything
113
+ * published before the mechanism existed.
114
+ *
115
+ * **A version this cannot PARSE is satisfied, on every axis.** A runtime that
116
+ * cannot name its own version must not start rejecting modules on the strength
117
+ * of a number it could not read — the refusal-to-guess `module-version-order.ts`
118
+ * makes, pointed in the safe direction. The test is a parse, not a shape: `0.76`
119
+ * and `2024.1` look like versions and are not three-part ones, so a cheaper
120
+ * check (a leading digit, say) would fail them CLOSED and gate every module in
121
+ * the graph on a number nothing could compare. `AnalysisOptions.teloVersion` is
122
+ * hand-written by definition, so that is exactly where such a value arrives.
123
+ */
124
+ export declare function evaluateRequires(block: RequiresBlock, running: string | undefined, host?: HostVersions): RequiresVerdict;
125
+ //# sourceMappingURL=requires-block.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requires-block.d.ts","sourceRoot":"","sources":["../src/requires-block.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAGH,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,eAAe,mBAAoB,CAAC;AACjD,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAKxD,MAAM,WAAW,aAAa;IAC5B,mDAAmD;IACnD,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,4EAA4E;IAC5E,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,aAAa;IAC5B,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;4EAEwE;IACxE,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC;iFAC6E;IAC7E,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,aAAa,CAAC;IACrB,MAAM,EAAE,aAAa,EAAE,CAAC;CACzB;AAID;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,kBAAkB,CA4DzF;AAsBD,uEAAuE;AACvE,MAAM,MAAM,eAAe,GACvB;IAAE,SAAS,EAAE,IAAI,CAAA;CAAE;AACrB,+EAA+E;GAC7E;IACE,SAAS,EAAE,KAAK,CAAC;IACjB,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC;IACxB,QAAQ,EAAE,YAAY,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEN;;;wEAGwE;AACxE,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,IAAI,GAAE,YAAiB,GACtB,eAAe,CAQjB"}
@@ -0,0 +1,182 @@
1
+ /**
2
+ * The single reader of a module doc's `requires:` block — the version ranges of
3
+ * runtime a module declares itself verified against. The load gate, the CLI's
4
+ * publish preflight and `upgrade`'s candidate filter all recognise the block
5
+ * here and nowhere else, the one-accessor rule `ref-slot.ts` and `zone-slot.ts`
6
+ * established. Browser-safe: no Node built-ins, so the editor reaches the
7
+ * identical rule the kernel does.
8
+ *
9
+ * ```yaml
10
+ * requires:
11
+ * telo: ">=0.80.0"
12
+ * host:
13
+ * node: ">=20.0.0"
14
+ * ```
15
+ *
16
+ * **Two tiers, and the split is not cosmetic.** `telo` names the *manifest
17
+ * surface generation* a runtime implements — one scale shared by every kernel,
18
+ * Node, Rust or Go, independent of each kernel's own release identity — and it
19
+ * is the one axis verified by EXECUTION, by running the CLI at each edge of the
20
+ * declared range. Host axes cannot be edge-verified by any CI; they are asserted
21
+ * by the author and compared against the version the running host reports
22
+ * ({@link HostVersions}). A flat map would imply one semantics for both.
23
+ *
24
+ * Nesting is also what disambiguates the names: `nodejs` and `rust` are already
25
+ * *kernel labels* in this repo (`LABEL_TO_PURL_TYPE`, an `imports:` entry's
26
+ * `runtime:`), so a top-level `node:` reads as the Node kernel rather than the
27
+ * Node.js runtime — and no word escapes that, because the host runtime and the
28
+ * kernel implementation genuinely share a name. Under `host:` position carries
29
+ * the disambiguation and no word has to.
30
+ *
31
+ * **Ordering is normative: `telo` is checked before `host`, and before any
32
+ * unknown-axis complaint.** A module using an axis introduced in telo 0.85 also
33
+ * declares telo `>=0.85`, so an older runtime fails on the telo axis first and
34
+ * never has to decide what an axis it has never heard of means. That is what
35
+ * makes the block safely extensible; consumers get the order from
36
+ * {@link evaluateRequires} rather than re-deriving it.
37
+ */
38
+ import { parseModuleVersion } from "./module-version-order.js";
39
+ import { isUnsatisfiable, parseVersionRange, rangeAccepts, } from "./version-range.js";
40
+ /**
41
+ * Host axes this analyzer knows.
42
+ *
43
+ * **An axis is in this list only when something checks it.** A declared
44
+ * requirement nothing compares is worse than no requirement at all: it validates,
45
+ * it reads as protection, and it silently protects nobody — the exact failure
46
+ * class this whole mechanism exists to remove, reintroduced inside it. So `rustc`
47
+ * is deliberately absent until the slice that builds controller crates can
48
+ * compare it; adding it there is a one-line change here plus a supplier in
49
+ * {@link HostVersions}, and until then an author writing it is told it is not a
50
+ * known axis rather than quietly reassured.
51
+ *
52
+ * Extending the set is a telo release, which is exactly why a module using a new
53
+ * axis must also raise its `telo` bound — and why `telo` is checked first.
54
+ */
55
+ export const KNOWN_HOST_AXES = ["node"];
56
+ /** Top-level keys of the block. `host` is a container, `telo` a range. */
57
+ const KNOWN_AXES = ["telo", "host"];
58
+ const EMPTY = { host: {} };
59
+ /**
60
+ * Read and parse the block off a module doc. Never throws. A malformed entry
61
+ * yields an issue AND is omitted from the block, so a consumer enforcing the
62
+ * block never silently treats garbage as a satisfied requirement — the issue is
63
+ * what makes the manifest fail, exactly as a malformed zone annotation does.
64
+ */
65
+ export function readRequires(doc) {
66
+ const raw = doc?.requires;
67
+ if (raw === undefined)
68
+ return { declared: false, block: EMPTY, issues: [] };
69
+ const issues = [];
70
+ const block = { host: {} };
71
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
72
+ issues.push({
73
+ path: "requires",
74
+ message: `'requires' must be a mapping of axes, got ${describe(raw)}.`,
75
+ });
76
+ return { declared: true, block, issues };
77
+ }
78
+ const entries = raw;
79
+ for (const key of Object.keys(entries)) {
80
+ if (!KNOWN_AXES.includes(key)) {
81
+ issues.push({
82
+ path: `requires.${key}`,
83
+ message: `'requires.${key}' is not a known axis. This runtime knows ` +
84
+ `${KNOWN_AXES.map((a) => `'${a}'`).join(" and ")}; host requirements go under 'host'.`,
85
+ unknownAxis: true,
86
+ });
87
+ }
88
+ }
89
+ if (entries.telo !== undefined) {
90
+ const range = parseRangeAt(entries.telo, "requires.telo", issues);
91
+ if (range)
92
+ block.telo = range;
93
+ }
94
+ if (entries.host !== undefined) {
95
+ const host = entries.host;
96
+ if (host === null || typeof host !== "object" || Array.isArray(host)) {
97
+ issues.push({
98
+ path: "requires.host",
99
+ message: `'requires.host' must be a mapping of host axes, got ${describe(host)}.`,
100
+ });
101
+ }
102
+ else {
103
+ for (const [axis, value] of Object.entries(host)) {
104
+ if (!KNOWN_HOST_AXES.includes(axis)) {
105
+ issues.push({
106
+ path: `requires.host.${axis}`,
107
+ message: `'requires.host.${axis}' is not a known host axis. This runtime knows ` +
108
+ `${KNOWN_HOST_AXES.map((a) => `'${a}'`).join(", ")}.`,
109
+ unknownAxis: true,
110
+ });
111
+ continue;
112
+ }
113
+ const range = parseRangeAt(value, `requires.host.${axis}`, issues);
114
+ if (range)
115
+ block.host[axis] = range;
116
+ }
117
+ }
118
+ }
119
+ return { declared: true, block, issues };
120
+ }
121
+ function parseRangeAt(value, path, issues) {
122
+ const result = parseVersionRange(value);
123
+ if (!result.ok) {
124
+ issues.push({ path, message: `'${path}': ${result.error.message}.`, hint: result.error.hint });
125
+ return undefined;
126
+ }
127
+ if (isUnsatisfiable(result.range)) {
128
+ issues.push({
129
+ path,
130
+ message: `'${path}': '${result.range.raw}' admits no version — its bounds exclude each other.`,
131
+ });
132
+ return undefined;
133
+ }
134
+ return result.range;
135
+ }
136
+ /**
137
+ * Evaluate a module's declared requirements against the runtime performing the
138
+ * analysis.
139
+ *
140
+ * `telo` is checked FIRST and short-circuits: a module using a host axis
141
+ * introduced in a later telo also declares that telo, so an older runtime must
142
+ * report the version skew rather than a host axis it may not even know. Absent
143
+ * declarations are satisfied — the bootstrap rule, permanent for everything
144
+ * published before the mechanism existed.
145
+ *
146
+ * **A version this cannot PARSE is satisfied, on every axis.** A runtime that
147
+ * cannot name its own version must not start rejecting modules on the strength
148
+ * of a number it could not read — the refusal-to-guess `module-version-order.ts`
149
+ * makes, pointed in the safe direction. The test is a parse, not a shape: `0.76`
150
+ * and `2024.1` look like versions and are not three-part ones, so a cheaper
151
+ * check (a leading digit, say) would fail them CLOSED and gate every module in
152
+ * the graph on a number nothing could compare. `AnalysisOptions.teloVersion` is
153
+ * hand-written by definition, so that is exactly where such a value arrives.
154
+ */
155
+ export function evaluateRequires(block, running, host = {}) {
156
+ const telo = check("telo", block.telo, running);
157
+ if (telo)
158
+ return telo;
159
+ for (const axis of KNOWN_HOST_AXES) {
160
+ const verdict = check(axis, block.host[axis], host[axis]);
161
+ if (verdict)
162
+ return verdict;
163
+ }
164
+ return { satisfied: true };
165
+ }
166
+ /** One axis, or `undefined` when it is satisfied / undeclared / unreportable. */
167
+ function check(axis, declared, running) {
168
+ if (!declared || !running)
169
+ return undefined;
170
+ if (!parseModuleVersion(running))
171
+ return undefined;
172
+ if (rangeAccepts(declared, running))
173
+ return undefined;
174
+ return { satisfied: false, axis, declared, running };
175
+ }
176
+ function describe(value) {
177
+ if (value === null)
178
+ return "null";
179
+ if (Array.isArray(value))
180
+ return "an array";
181
+ return typeof value;
182
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * The JSON Schema vocabulary an author writes inside a manifest, as data.
3
+ *
4
+ * WHY THIS EXISTS. A schema-valued slot used to be declared `type: object` and
5
+ * nothing more, so every surface that reads a kind schema — completion, hover,
6
+ * the editor's field walk, AJV — knew only "some object". Autocompletion was
7
+ * dead from the first key, and a typo (`requred:`, `type: 5`) was carried all
8
+ * the way to a runtime validation failure that named the wrong thing.
9
+ *
10
+ * ONE SOURCE, TWO SURFACES. The maps below are the whole vocabulary; the
11
+ * fragments in `manifest-schemas.ts` are built FROM them, and completion reads
12
+ * them directly. A second hand-written list is exactly how the IDE's suggestions
13
+ * and the validator's rules would drift apart.
14
+ *
15
+ * WHY THE ANNOTATIONS ARE NOT IN THE VALIDATING FRAGMENT. `x-telo-*` keys are
16
+ * offered by completion but deliberately never appear as literal property names
17
+ * in the schema that gets hoisted into a manifest. Several passes walk a
18
+ * definition's schema testing every object for an annotation KEY
19
+ * (`resolveSchemaRefKinds`, `validate-ref-slots`, `validate-zone-slots`), and a
20
+ * `properties` map holding a key spelled `x-telo-ref` reads to them as an
21
+ * annotated node — inventing diagnostics about a slot the author never wrote.
22
+ * So the hoisted body stays open (`additionalProperties: true`, which admits
23
+ * every annotation) and the annotation vocabulary stays here, on the analyzer
24
+ * side of the boundary, where no manifest walk can reach it.
25
+ *
26
+ * Browser-safe: no Node built-ins.
27
+ */
28
+ import { X_TELO_TYPE } from "@telorun/sdk";
29
+ import { ANNOTATION_KEYWORDS } from "./value-type-keyword.js";
30
+ /** A keyword entry: the JSON Schema its VALUE must satisfy, carrying the title
31
+ * and description completion and hover show. */
32
+ export type SchemaKeywords = Record<string, Record<string, unknown>>;
33
+ /**
34
+ * The draft-07 keywords, as a property map for a fragment named `self`.
35
+ *
36
+ * Parameterized by the fragment name because a schema's nested positions hold
37
+ * schemas of the SAME flavour: a property of a kind schema may carry
38
+ * annotations, a property of a data schema may not. Both recurse into
39
+ * themselves, and the document-local pointer is what the hoisting in
40
+ * `expandManifestFragments` makes resolvable.
41
+ */
42
+ export declare function jsonSchemaKeywords(self: string): SchemaKeywords;
43
+ /**
44
+ * The `x-telo-*` annotation vocabulary — completion and hover only.
45
+ *
46
+ * TOTAL over {@link ANNOTATION_KEYWORDS} plus `x-telo-type`, which is what makes
47
+ * it a description of the existing list rather than a second copy of it: adding
48
+ * an annotation without a completion entry is a compile error here, and the
49
+ * first draft of this map — hand-written — had already silently dropped four
50
+ * annotations that live stdlib manifests use.
51
+ *
52
+ * Values are intentionally loose. What an annotation MEANS is checked by the
53
+ * pass that owns it (`validate-ref-slots`, `validate-zone-slots`,
54
+ * `validate-value-type-slots`), which reports in that annotation's own
55
+ * vocabulary; restating the shape here would give one mistake two diagnostics
56
+ * that disagree about what is wrong.
57
+ *
58
+ * A KNOWN BLIND SPOT, and not an oversight: several annotations
59
+ * (`x-telo-context`, `x-telo-error-context`, `x-telo-step-context`) hold JSON
60
+ * Schema themselves, and cannot be typed by the fragment this file feeds. A
61
+ * literal `x-telo-*` key inside a hoisted `properties` map reads to the
62
+ * annotation walkers as an annotated node, so the vocabulary has to stay out of
63
+ * anything that enters a manifest — which leaves an annotation's VALUE with
64
+ * neither validation nor completion. Closing it needs the walkers to distinguish
65
+ * a schema describing an annotation from an annotation, which nothing does yet.
66
+ */
67
+ export declare const TELO_SCHEMA_ANNOTATIONS: Record<(typeof ANNOTATION_KEYWORDS)[number] | typeof X_TELO_TYPE, Record<string, unknown>>;
68
+ //# sourceMappingURL=schema-keywords.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-keywords.d.ts","sourceRoot":"","sources":["../src/schema-keywords.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAE9D;iDACiD;AACjD,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AASrE;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAuJ/D;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAC1C,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,GAAG,OAAO,WAAW,EACzD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAgIxB,CAAC"}