@telorun/analyzer 0.72.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.
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +76 -20
- package/dist/artifact-axes.d.ts +14 -0
- package/dist/artifact-axes.d.ts.map +1 -0
- package/dist/artifact-axes.js +12 -0
- package/dist/artifact-layer-index.d.ts +2 -2
- package/dist/artifact-layer-index.d.ts.map +1 -1
- package/dist/artifact-layer-index.js +9 -4
- package/dist/artifact-selector.d.ts +47 -21
- package/dist/artifact-selector.d.ts.map +1 -1
- package/dist/artifact-selector.js +85 -16
- package/dist/builtins.d.ts.map +1 -1
- package/dist/builtins.js +144 -113
- package/dist/call-graph.d.ts +12 -1
- package/dist/call-graph.d.ts.map +1 -1
- package/dist/call-graph.js +22 -0
- package/dist/catch-scope.js +1 -1
- package/dist/cel-scope-query.d.ts.map +1 -1
- package/dist/cel-scope-query.js +32 -11
- package/dist/cel-scope.d.ts.map +1 -1
- package/dist/cel-scope.js +1 -0
- package/dist/eval-paths.d.ts +36 -5
- package/dist/eval-paths.d.ts.map +1 -1
- package/dist/eval-paths.js +47 -6
- package/dist/extends-resolution.d.ts +12 -0
- package/dist/extends-resolution.d.ts.map +1 -1
- package/dist/extends-resolution.js +23 -0
- package/dist/forwarded-declaration.d.ts +26 -0
- package/dist/forwarded-declaration.d.ts.map +1 -0
- package/dist/forwarded-declaration.js +31 -0
- package/dist/index.d.ts +10 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/kernel-globals.d.ts.map +1 -1
- package/dist/kernel-globals.js +21 -5
- package/dist/module-alias-scope.d.ts +11 -0
- package/dist/module-alias-scope.d.ts.map +1 -1
- package/dist/module-alias-scope.js +10 -0
- package/dist/module-file-claims.d.ts +17 -1
- package/dist/module-file-claims.d.ts.map +1 -1
- package/dist/module-file-claims.js +38 -3
- package/dist/module-named-files.d.ts +72 -0
- package/dist/module-named-files.d.ts.map +1 -0
- package/dist/module-named-files.js +115 -0
- package/dist/native-entries.d.ts +83 -0
- package/dist/native-entries.d.ts.map +1 -0
- package/dist/native-entries.js +169 -0
- package/dist/nearest-name.d.ts +22 -0
- package/dist/nearest-name.d.ts.map +1 -0
- package/dist/nearest-name.js +43 -0
- package/dist/normalize-inline-resources.d.ts +41 -13
- package/dist/normalize-inline-resources.d.ts.map +1 -1
- package/dist/normalize-inline-resources.js +236 -54
- package/dist/reference-field-map.d.ts +59 -1
- package/dist/reference-field-map.d.ts.map +1 -1
- package/dist/reference-field-map.js +200 -34
- package/dist/release/destinations.d.ts +59 -0
- package/dist/release/destinations.d.ts.map +1 -0
- package/dist/release/destinations.js +75 -0
- package/dist/release/index.d.ts +6 -2
- package/dist/release/index.d.ts.map +1 -1
- package/dist/release/index.js +3 -1
- package/dist/release/ledger.d.ts +20 -11
- package/dist/release/ledger.d.ts.map +1 -1
- package/dist/release/ledger.js +43 -14
- package/dist/release/payload-digest.d.ts +2 -1
- package/dist/release/payload-digest.d.ts.map +1 -1
- package/dist/release/payload-digest.js +2 -1
- package/dist/release/release-plan.d.ts +3 -2
- package/dist/release/release-plan.d.ts.map +1 -1
- package/dist/release/release-plan.js +12 -19
- package/dist/release/workspace-config.d.ts +114 -34
- package/dist/release/workspace-config.d.ts.map +1 -1
- package/dist/release/workspace-config.js +322 -38
- package/dist/release/workspace-schema.d.ts +41 -0
- package/dist/release/workspace-schema.d.ts.map +1 -0
- package/dist/release/workspace-schema.js +77 -0
- package/dist/resolve-ref-sentinels.d.ts.map +1 -1
- package/dist/resolve-ref-sentinels.js +8 -5
- package/dist/resolve-throws-union.d.ts +25 -4
- package/dist/resolve-throws-union.d.ts.map +1 -1
- package/dist/resolve-throws-union.js +62 -32
- package/dist/resolve-zone-requirements.d.ts.map +1 -1
- package/dist/resolve-zone-requirements.js +2 -1
- package/dist/rewrite-synthetic-origins.d.ts +6 -1
- package/dist/rewrite-synthetic-origins.d.ts.map +1 -1
- package/dist/rewrite-synthetic-origins.js +107 -13
- package/dist/schema-compat.d.ts.map +1 -1
- package/dist/schema-compat.js +18 -5
- package/dist/schema-error-report.d.ts +7 -0
- package/dist/schema-error-report.d.ts.map +1 -1
- package/dist/schema-error-report.js +9 -4
- package/dist/schema-walk.d.ts +47 -13
- package/dist/schema-walk.d.ts.map +1 -1
- package/dist/schema-walk.js +150 -30
- package/dist/scope-declarations.d.ts +59 -0
- package/dist/scope-declarations.d.ts.map +1 -0
- package/dist/scope-declarations.js +45 -0
- package/dist/source-entries.d.ts +119 -0
- package/dist/source-entries.d.ts.map +1 -0
- package/dist/source-entries.js +349 -0
- package/dist/step-bodies.d.ts +24 -0
- package/dist/step-bodies.d.ts.map +1 -0
- package/dist/step-bodies.js +28 -0
- package/dist/telo-version.d.ts +1 -1
- package/dist/telo-version.js +1 -1
- package/dist/template-body.d.ts +10 -0
- package/dist/template-body.d.ts.map +1 -1
- package/dist/template-body.js +25 -0
- package/dist/validate-cel-context.d.ts +23 -8
- package/dist/validate-cel-context.d.ts.map +1 -1
- package/dist/validate-cel-context.js +51 -18
- package/dist/validate-exports.d.ts +28 -0
- package/dist/validate-exports.d.ts.map +1 -0
- package/dist/validate-exports.js +146 -0
- package/dist/validate-extends.d.ts.map +1 -1
- package/dist/validate-extends.js +37 -1
- package/dist/validate-module-artifact.d.ts +4 -2
- package/dist/validate-module-artifact.d.ts.map +1 -1
- package/dist/validate-module-artifact.js +43 -4
- package/dist/validate-native-entries.d.ts +15 -0
- package/dist/validate-native-entries.d.ts.map +1 -0
- package/dist/validate-native-entries.js +103 -0
- package/dist/validate-observed-state.d.ts +7 -1
- package/dist/validate-observed-state.d.ts.map +1 -1
- package/dist/validate-observed-state.js +24 -6
- package/dist/validate-provider-coherence.d.ts +4 -8
- package/dist/validate-provider-coherence.d.ts.map +1 -1
- package/dist/validate-provider-coherence.js +12 -123
- package/dist/validate-reference-forms.d.ts.map +1 -1
- package/dist/validate-reference-forms.js +2 -2
- package/dist/validate-references.d.ts.map +1 -1
- package/dist/validate-references.js +152 -65
- package/dist/validate-scope-reach.d.ts +31 -0
- package/dist/validate-scope-reach.d.ts.map +1 -0
- package/dist/validate-scope-reach.js +180 -0
- package/dist/validate-source-entries.d.ts +16 -0
- package/dist/validate-source-entries.d.ts.map +1 -0
- package/dist/validate-source-entries.js +90 -0
- package/dist/validate-template-body.d.ts +36 -0
- package/dist/validate-template-body.d.ts.map +1 -0
- package/dist/validate-template-body.js +246 -0
- package/dist/validate-throws-coverage.d.ts.map +1 -1
- package/dist/validate-throws-coverage.js +21 -39
- package/dist/value-type-keyword.d.ts +22 -5
- package/dist/value-type-keyword.d.ts.map +1 -1
- package/dist/value-type-keyword.js +16 -7
- package/package.json +4 -3
- package/src/analyzer.ts +97 -20
- package/src/artifact-axes.ts +24 -0
- package/src/artifact-layer-index.ts +9 -6
- package/src/artifact-selector.ts +110 -35
- package/src/builtins.ts +160 -113
- package/src/call-graph.ts +30 -0
- package/src/catch-scope.ts +1 -1
- package/src/cel-scope-query.ts +28 -9
- package/src/cel-scope.ts +1 -0
- package/src/eval-paths.ts +53 -6
- package/src/extends-resolution.ts +24 -0
- package/src/forwarded-declaration.ts +32 -0
- package/src/index.ts +37 -1
- package/src/kernel-globals.ts +28 -5
- package/src/migrations/CLAUDE.md +35 -0
- package/src/module-alias-scope.ts +17 -0
- package/src/module-file-claims.ts +63 -4
- package/src/module-named-files.ts +162 -0
- package/src/native-entries.ts +227 -0
- package/src/nearest-name.ts +47 -0
- package/src/normalize-inline-resources.ts +326 -70
- package/src/reference-field-map.ts +257 -52
- package/src/release/CLAUDE.md +32 -0
- package/src/release/destinations.ts +105 -0
- package/src/release/index.ts +33 -2
- package/src/release/ledger.ts +51 -21
- package/src/release/payload-digest.ts +2 -1
- package/src/release/release-plan.ts +16 -26
- package/src/release/workspace-config.ts +483 -47
- package/src/release/workspace-schema.ts +99 -0
- package/src/resolve-ref-sentinels.ts +7 -6
- package/src/resolve-throws-union.ts +87 -32
- package/src/resolve-zone-requirements.ts +2 -1
- package/src/rewrite-synthetic-origins.ts +107 -16
- package/src/schema-compat.ts +18 -4
- package/src/schema-error-report.ts +16 -4
- package/src/schema-walk.ts +162 -34
- package/src/scope-declarations.ts +98 -0
- package/src/source-entries.ts +502 -0
- package/src/step-bodies.ts +55 -0
- package/src/telo-version.ts +1 -1
- package/src/template-body.ts +25 -0
- package/src/validate-cel-context.ts +60 -18
- package/src/validate-exports.ts +185 -0
- package/src/validate-extends.ts +43 -0
- package/src/validate-module-artifact.ts +46 -3
- package/src/validate-native-entries.ts +147 -0
- package/src/validate-observed-state.ts +36 -7
- package/src/validate-provider-coherence.ts +17 -127
- package/src/validate-reference-forms.ts +2 -3
- package/src/validate-references.ts +151 -66
- package/src/validate-scope-reach.ts +213 -0
- package/src/validate-source-entries.ts +120 -0
- package/src/validate-template-body.ts +274 -0
- package/src/validate-throws-coverage.ts +24 -31
- package/src/value-type-keyword.ts +35 -9
- package/dist/validate-template-dispatch.d.ts +0 -27
- package/dist/validate-template-dispatch.d.ts.map +0 -1
- package/dist/validate-template-dispatch.js +0 -95
- package/src/validate-template-dispatch.ts +0 -99
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A module's **sources** — the `sources:` block on a `Telo.Library` or
|
|
3
|
+
* `Telo.Application` doc, saying where every staged file comes from: a pinned
|
|
4
|
+
* upstream archive, fetched by `telo release stage`.
|
|
5
|
+
*
|
|
6
|
+
* ```yaml
|
|
7
|
+
* sources:
|
|
8
|
+
* better-sqlite3:
|
|
9
|
+
* version: 12.8.0
|
|
10
|
+
* url: https://github.com/WiseLibs/better-sqlite3/releases/download/v{version}/better-sqlite3-v{version}-{upstream}.tar.gz
|
|
11
|
+
* archive: tar.gz
|
|
12
|
+
* notices: [./notices/better-sqlite3.LICENSE]
|
|
13
|
+
* entries:
|
|
14
|
+
* ./native/linux-amd64-gnu-node-137/better_sqlite3.node:
|
|
15
|
+
* upstream: node-v137-linux-x64
|
|
16
|
+
* member: build/Release/better_sqlite3.node
|
|
17
|
+
* sha256: 4c9e…
|
|
18
|
+
* executable: false
|
|
19
|
+
* ./native/linux-amd64-gnu/libvips.so:
|
|
20
|
+
* target: libvips.so.42
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* Keyed by the module-relative path an entry produces, because the manifest
|
|
24
|
+
* already names every staged file — a `native:` entry's path or a
|
|
25
|
+
* platform-qualified controller candidate's `path=`.
|
|
26
|
+
*
|
|
27
|
+
* The single reader: every rule decidable from the block alone is a problem
|
|
28
|
+
* here, so `telo check` (`validate-source-entries.ts`), the stager and the
|
|
29
|
+
* kernels refuse the same blocks. Browser-safe: string work only.
|
|
30
|
+
*/
|
|
31
|
+
import { normalizeNativePath } from "./native-entries.js";
|
|
32
|
+
const SOURCE_NAME_TOKEN = /^[a-z0-9][a-z0-9_.-]*$/;
|
|
33
|
+
const SHA256_HEX = /^[0-9a-f]{64}$/;
|
|
34
|
+
const INPUTS_DIGEST = /^sha256-[A-Za-z0-9_-]{43}$/;
|
|
35
|
+
const SOURCE_KEYS = ["version", "url", "archive", "notices", "entries", "build"];
|
|
36
|
+
const BUILD_KEYS = ["cargo", "inputs"];
|
|
37
|
+
const URL_PLACEHOLDERS = new Set(["version", "upstream"]);
|
|
38
|
+
const FILE_KEYS = ["upstream", "member", "sha256", "executable"];
|
|
39
|
+
const URL_ORIGIN = /^([a-z][a-z0-9+.-]*):\/\/([^/?#]*)/i;
|
|
40
|
+
const LOOPBACK_HOST = /^(localhost|127\.\d{1,3}\.\d{1,3}\.\d{1,3}|\[::1\])$/i;
|
|
41
|
+
/** The archive formats an upstream may be. */
|
|
42
|
+
export const SOURCE_ARCHIVE_FORMATS = ["tar.gz"];
|
|
43
|
+
const isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
44
|
+
/** The URL an entry is fetched from: substitution only. */
|
|
45
|
+
export function resolveSourceUrl(source, upstream) {
|
|
46
|
+
return source.url.replaceAll("{version}", source.version).replaceAll("{upstream}", upstream);
|
|
47
|
+
}
|
|
48
|
+
/** Resolve a link target against the link's own directory, confined to the module. */
|
|
49
|
+
function resolveLinkTarget(linkPath, target) {
|
|
50
|
+
const dir = linkPath.includes("/") ? linkPath.slice(0, linkPath.lastIndexOf("/")) : "";
|
|
51
|
+
if (target.startsWith("/") || target.startsWith("\\"))
|
|
52
|
+
return undefined;
|
|
53
|
+
const verdict = normalizeNativePath(dir === "" ? target : `${dir}/${target}`);
|
|
54
|
+
return "path" in verdict ? verdict.path : undefined;
|
|
55
|
+
}
|
|
56
|
+
/** Why a url — a template, or the URL a fetch ended at after redirects — may not
|
|
57
|
+
* be fetched from, or undefined when it may: https, or plain http to a loopback
|
|
58
|
+
* host. */
|
|
59
|
+
export function sourceUrlProblem(url) {
|
|
60
|
+
const origin = URL_ORIGIN.exec(url);
|
|
61
|
+
if (!origin) {
|
|
62
|
+
return {
|
|
63
|
+
code: "SOURCE_INVALID",
|
|
64
|
+
detail: `url '${url}' is not an absolute URL. Write an https:// URL template.`,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const scheme = origin[1].toLowerCase();
|
|
68
|
+
if (scheme === "https")
|
|
69
|
+
return undefined;
|
|
70
|
+
const authority = origin[2];
|
|
71
|
+
const hostPort = authority.slice(authority.lastIndexOf("@") + 1);
|
|
72
|
+
const host = hostPort.startsWith("[")
|
|
73
|
+
? hostPort.slice(0, hostPort.indexOf("]") + 1)
|
|
74
|
+
: hostPort.split(":")[0];
|
|
75
|
+
if (scheme === "http" && LOOPBACK_HOST.test(host))
|
|
76
|
+
return undefined;
|
|
77
|
+
return {
|
|
78
|
+
code: "SOURCE_URL_INSECURE",
|
|
79
|
+
detail: `url '${url}' is fetched over ${scheme}, where the archive could be altered on the way. ` +
|
|
80
|
+
`Use https; plain http is accepted only for a loopback host (localhost, 127.0.0.0/8, [::1]).`,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/** Whether one normalized module-relative path is a directory the other runs through. */
|
|
84
|
+
function runsThrough(path, parent) {
|
|
85
|
+
return path.startsWith(`${parent}/`);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Read the `sources:` block off an owner document's JSON projection.
|
|
89
|
+
*
|
|
90
|
+
* A source or entry with any problem is left out, never read partially: a
|
|
91
|
+
* half-read entry would stage a file the author did not declare.
|
|
92
|
+
*
|
|
93
|
+
* `ignorePins` reads a file entry's `sha256` / `executable` and a build's
|
|
94
|
+
* `inputs` as absent — for the one writer of pins, which replaces them whatever
|
|
95
|
+
* they held.
|
|
96
|
+
*/
|
|
97
|
+
export function readModuleSources(ownerJson, options = {}) {
|
|
98
|
+
const ignorePins = options.ignorePins === true;
|
|
99
|
+
const declared = ownerJson?.sources;
|
|
100
|
+
const sources = [];
|
|
101
|
+
const problems = [];
|
|
102
|
+
if (declared === undefined)
|
|
103
|
+
return { sources, problems };
|
|
104
|
+
const problem = (code, path, message) => problems.push({ code, path, message });
|
|
105
|
+
if (!isObject(declared)) {
|
|
106
|
+
problem("SHAPE", "sources", "sources: expected a map of source name to source.");
|
|
107
|
+
return { sources, problems };
|
|
108
|
+
}
|
|
109
|
+
const producers = new Map();
|
|
110
|
+
for (const [name, raw] of Object.entries(declared)) {
|
|
111
|
+
const at = `sources.${name}`;
|
|
112
|
+
const label = `source '${name}'`;
|
|
113
|
+
if (!isObject(raw)) {
|
|
114
|
+
problem("SHAPE", at, `${label}: expected an object.`);
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
const build = raw.build;
|
|
118
|
+
if (typeof raw.version !== "string" ||
|
|
119
|
+
typeof raw.url !== "string" ||
|
|
120
|
+
!SOURCE_ARCHIVE_FORMATS.includes(raw.archive) ||
|
|
121
|
+
!Array.isArray(raw.notices) ||
|
|
122
|
+
raw.notices.length === 0 ||
|
|
123
|
+
raw.notices.some((notice) => typeof notice !== "string") ||
|
|
124
|
+
!isObject(raw.entries) ||
|
|
125
|
+
(build !== undefined &&
|
|
126
|
+
(!isObject(build) ||
|
|
127
|
+
typeof build.cargo !== "string" ||
|
|
128
|
+
(!ignorePins && "inputs" in build && typeof build.inputs !== "string") ||
|
|
129
|
+
Object.keys(build).some((key) => !BUILD_KEYS.includes(key)))) ||
|
|
130
|
+
Object.keys(raw).some((key) => !SOURCE_KEYS.includes(key))) {
|
|
131
|
+
problem("SHAPE", at, `${label}: a source is { version, url, archive (${SOURCE_ARCHIVE_FORMATS.join(" | ")}), ` +
|
|
132
|
+
`notices (non-empty list), entries, build? { cargo, inputs? } } and nothing else.`);
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
let valid = true;
|
|
136
|
+
if (!SOURCE_NAME_TOKEN.test(name)) {
|
|
137
|
+
problem("SOURCE_INVALID", `${at}`, `${label}: the name is not a canonical token. Use lowercase letters, digits, '.', '-' or ` +
|
|
138
|
+
`'_', starting with a letter or digit.`);
|
|
139
|
+
valid = false;
|
|
140
|
+
}
|
|
141
|
+
for (const key of ["version", "url"]) {
|
|
142
|
+
if (raw[key].trim() === "") {
|
|
143
|
+
problem("SOURCE_INVALID", `${at}.${key}`, `${label}: '${key}' must not be empty.`);
|
|
144
|
+
valid = false;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const url = raw.url;
|
|
148
|
+
for (const match of url.matchAll(/\{([^{}]*)\}/g)) {
|
|
149
|
+
if (URL_PLACEHOLDERS.has(match[1]))
|
|
150
|
+
continue;
|
|
151
|
+
problem("SOURCE_URL_PLACEHOLDER_UNKNOWN", `${at}.url`, `${label}: the url placeholder '{${match[1]}}' is not recognized. A url template may use ` +
|
|
152
|
+
`only {version} (the source's version) and {upstream} (each entry's upstream).`);
|
|
153
|
+
valid = false;
|
|
154
|
+
}
|
|
155
|
+
const insecure = url.trim() === "" ? undefined : sourceUrlProblem(url);
|
|
156
|
+
if (insecure) {
|
|
157
|
+
problem(insecure.code, `${at}.url`, `${label}: ${insecure.detail}`);
|
|
158
|
+
valid = false;
|
|
159
|
+
}
|
|
160
|
+
const notices = [];
|
|
161
|
+
raw.notices.forEach((notice, index) => {
|
|
162
|
+
const verdict = normalizeNativePath(notice.trim());
|
|
163
|
+
if ("path" in verdict) {
|
|
164
|
+
notices.push(verdict.path);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
problem("SOURCE_INVALID", `${at}.notices[${index}]`, `${label}: notice ${verdict.detail}`);
|
|
168
|
+
valid = false;
|
|
169
|
+
});
|
|
170
|
+
let readBuild;
|
|
171
|
+
if (isObject(build)) {
|
|
172
|
+
const written = build.cargo.trim();
|
|
173
|
+
const verdict = /^\.?\/?$/.test(written) ? { path: "" } : normalizeNativePath(written);
|
|
174
|
+
const inputs = ignorePins ? undefined : build.inputs;
|
|
175
|
+
if (!("path" in verdict)) {
|
|
176
|
+
problem("SOURCE_INVALID", `${at}.build.cargo`, verdict.kind === "escape"
|
|
177
|
+
? `${label}: build.cargo '${written}' is not a directory inside the module. Name the ` +
|
|
178
|
+
`crate relative to the directory holding telo.yaml; code outside the module reaches ` +
|
|
179
|
+
`its digest as a path dependency of that crate.`
|
|
180
|
+
: `${label}: build.cargo '${written}' does not name one module-relative directory.`);
|
|
181
|
+
valid = false;
|
|
182
|
+
}
|
|
183
|
+
else if (inputs !== undefined && !INPUTS_DIGEST.test(inputs)) {
|
|
184
|
+
problem("SOURCE_INVALID", `${at}.build.inputs`, `${label}: build.inputs must be a digest of the form sha256-<43 base64url characters> — ` +
|
|
185
|
+
`run \`telo release stage --pin\` to write it.`);
|
|
186
|
+
valid = false;
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
readBuild = { cargo: verdict.path, ...(inputs !== undefined ? { inputs } : {}) };
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const entries = [];
|
|
193
|
+
const rawEntries = raw.entries;
|
|
194
|
+
const entryPaths = new Map();
|
|
195
|
+
const links = [];
|
|
196
|
+
// Paths first, from every key, so a link to an entry with an unrelated
|
|
197
|
+
// problem is not also reported as unresolved.
|
|
198
|
+
const pathOfKey = new Map();
|
|
199
|
+
for (const key of Object.keys(rawEntries)) {
|
|
200
|
+
const entryAt = `${at}.entries.${key}`;
|
|
201
|
+
const verdict = normalizeNativePath(key.trim());
|
|
202
|
+
if (!("path" in verdict)) {
|
|
203
|
+
problem("SOURCE_ENTRY_INVALID", entryAt, `${label} entry '${key}': ${verdict.detail}`);
|
|
204
|
+
valid = false;
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
if (entryPaths.has(verdict.path)) {
|
|
208
|
+
problem("SOURCE_ENTRY_DUPLICATE", entryAt, `${label} entry '${key}': path '${verdict.path}' is also produced by entry ` +
|
|
209
|
+
`'${entryPaths.get(verdict.path)}'.`);
|
|
210
|
+
valid = false;
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
entryPaths.set(verdict.path, key);
|
|
214
|
+
pathOfKey.set(key, verdict.path);
|
|
215
|
+
}
|
|
216
|
+
for (const [key, value] of Object.entries(rawEntries)) {
|
|
217
|
+
const entryAt = `${at}.entries.${key}`;
|
|
218
|
+
const entryLabel = `${label} entry '${key}'`;
|
|
219
|
+
const path = pathOfKey.get(key);
|
|
220
|
+
if (path === undefined)
|
|
221
|
+
continue;
|
|
222
|
+
if (!isObject(value)) {
|
|
223
|
+
problem("SHAPE", entryAt, `${entryLabel}: expected an object.`);
|
|
224
|
+
valid = false;
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
const fileKeys = FILE_KEYS.filter((k) => k in value);
|
|
228
|
+
const isLink = "target" in value;
|
|
229
|
+
if (isLink && fileKeys.length > 0) {
|
|
230
|
+
problem("SOURCE_ENTRY_INVALID", entryAt, `${entryLabel}: an entry is either a link (target) or a file (upstream, member, ` +
|
|
231
|
+
`sha256, executable) — remove ${fileKeys.map((k) => `'${k}'`).join(", ")} or 'target'.`);
|
|
232
|
+
valid = false;
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
const strings = isLink ? ["target"] : ["upstream", "member"];
|
|
236
|
+
if (strings.some((k) => typeof value[k] !== "string") ||
|
|
237
|
+
(!ignorePins && "sha256" in value && typeof value.sha256 !== "string") ||
|
|
238
|
+
(!ignorePins && "executable" in value && typeof value.executable !== "boolean")) {
|
|
239
|
+
problem("SHAPE", entryAt, `${entryLabel}: expected a file or a link entry.`);
|
|
240
|
+
valid = false;
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
const blank = strings.filter((k) => value[k].trim() === "");
|
|
244
|
+
if (blank.length > 0) {
|
|
245
|
+
for (const k of blank) {
|
|
246
|
+
problem("SOURCE_ENTRY_INVALID", `${entryAt}.${k}`, `${entryLabel}: '${k}' must not be empty.`);
|
|
247
|
+
}
|
|
248
|
+
valid = false;
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if (isLink) {
|
|
252
|
+
links.push({ key, path, target: value.target });
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
const sha256 = ignorePins ? undefined : value.sha256;
|
|
256
|
+
const executable = ignorePins ? undefined : value.executable;
|
|
257
|
+
if (sha256 !== undefined && !SHA256_HEX.test(sha256)) {
|
|
258
|
+
problem("SOURCE_ENTRY_INVALID", `${entryAt}.sha256`, `${entryLabel}: sha256 must be 64 lowercase hex characters — run ` +
|
|
259
|
+
`\`telo release stage --pin\` to write it.`);
|
|
260
|
+
valid = false;
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
if ((sha256 === undefined) !== (executable === undefined)) {
|
|
264
|
+
problem("SOURCE_ENTRY_INVALID", entryAt, `${entryLabel}: a pin is sha256 and executable together — run ` +
|
|
265
|
+
`\`telo release stage --pin\` to write both.`);
|
|
266
|
+
valid = false;
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
entries.push({
|
|
270
|
+
kind: "file",
|
|
271
|
+
key,
|
|
272
|
+
path,
|
|
273
|
+
upstream: value.upstream,
|
|
274
|
+
member: value.member,
|
|
275
|
+
...(sha256 !== undefined ? { pin: { sha256, executable: executable } } : {}),
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
const linkTargets = new Map();
|
|
279
|
+
for (const link of links) {
|
|
280
|
+
const resolved = resolveLinkTarget(link.path, link.target);
|
|
281
|
+
const targetAt = `${at}.entries.${link.key}.target`;
|
|
282
|
+
if (resolved === link.path) {
|
|
283
|
+
problem("SOURCE_LINK_CYCLE", targetAt, `${label} entry '${link.key}': link target '${link.target}' resolves to the link itself.`);
|
|
284
|
+
valid = false;
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
if (resolved === undefined || !entryPaths.has(resolved)) {
|
|
288
|
+
problem("SOURCE_LINK_TARGET_UNRESOLVED", targetAt, `${label} entry '${link.key}': link target '${link.target}' resolves, relative to the ` +
|
|
289
|
+
`link's directory, to ${resolved === undefined ? "a path outside the module" : `'${resolved}'`}, ` +
|
|
290
|
+
`which is not another entry of this source.`);
|
|
291
|
+
valid = false;
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
linkTargets.set(link.path, resolved);
|
|
295
|
+
entries.push({ kind: "link", key: link.key, path: link.path, target: link.target, resolved });
|
|
296
|
+
}
|
|
297
|
+
for (const link of links) {
|
|
298
|
+
if (!linkTargets.has(link.path))
|
|
299
|
+
continue;
|
|
300
|
+
const chain = [link.path];
|
|
301
|
+
for (let next = linkTargets.get(link.path); next !== undefined; next = linkTargets.get(next)) {
|
|
302
|
+
if (!chain.includes(next)) {
|
|
303
|
+
chain.push(next);
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
problem("SOURCE_LINK_CYCLE", `${at}.entries.${link.key}.target`, `${label} entry '${link.key}': the link never reaches a file — it cycles through ` +
|
|
307
|
+
`${chain.map((p) => `'${p}'`).join(" → ")} → '${next}'. A link chain must end at a file entry.`);
|
|
308
|
+
valid = false;
|
|
309
|
+
break;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
for (const entry of entries) {
|
|
313
|
+
const other = producers.get(entry.path);
|
|
314
|
+
if (other !== undefined) {
|
|
315
|
+
problem("SOURCE_ENTRY_DUPLICATE", `${at}.entries.${entry.key}`, `${label} entry '${entry.key}': path '${entry.path}' is also produced by source ` +
|
|
316
|
+
`'${other.source}'. Each staged file has exactly one source.`);
|
|
317
|
+
valid = false;
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
for (const [path, producer] of producers) {
|
|
321
|
+
const relation = runsThrough(entry.path, path)
|
|
322
|
+
? `runs through '${path}' as a directory`
|
|
323
|
+
: runsThrough(path, entry.path)
|
|
324
|
+
? `is a directory that '${path}' runs through`
|
|
325
|
+
: undefined;
|
|
326
|
+
if (relation === undefined)
|
|
327
|
+
continue;
|
|
328
|
+
problem("SOURCE_ENTRY_NESTED", `${at}.entries.${entry.key}`, `${label} entry '${entry.key}': path '${entry.path}' ${relation}, and source ` +
|
|
329
|
+
`'${producer.source}' entry '${producer.key}' produces '${path}'. A staged path cannot ` +
|
|
330
|
+
`be both a file and a directory — give each entry its own path.`);
|
|
331
|
+
valid = false;
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
producers.set(entry.path, { source: name, key: entry.key });
|
|
335
|
+
}
|
|
336
|
+
if (!valid)
|
|
337
|
+
continue;
|
|
338
|
+
sources.push({
|
|
339
|
+
name,
|
|
340
|
+
version: raw.version,
|
|
341
|
+
url,
|
|
342
|
+
archive: raw.archive,
|
|
343
|
+
notices,
|
|
344
|
+
entries,
|
|
345
|
+
...(readBuild !== undefined ? { build: readBuild } : {}),
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
return { sources, problems };
|
|
349
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A declaration's step bodies, found through its kind's step-body slots — the
|
|
3
|
+
* ONLY way a value is read as a step, never its shape. Shared by inline
|
|
4
|
+
* extraction and the scope-reach check, which must agree about where a step's
|
|
5
|
+
* dispatch target is.
|
|
6
|
+
*
|
|
7
|
+
* Browser-safe.
|
|
8
|
+
*/
|
|
9
|
+
/** One step body of one declaration. */
|
|
10
|
+
export interface StepBody {
|
|
11
|
+
/** The field holding it (`steps`). */
|
|
12
|
+
field: string;
|
|
13
|
+
/** The field on each step naming what it dispatches (`invoke`). */
|
|
14
|
+
invokeField: string;
|
|
15
|
+
steps: unknown[];
|
|
16
|
+
/** The step item schema, local `$ref` resolved, which says how steps nest. */
|
|
17
|
+
itemSchema: Record<string, any> | undefined;
|
|
18
|
+
}
|
|
19
|
+
/** Every step body `declaration` holds, per its kind's author-facing `schema`. */
|
|
20
|
+
export declare function stepBodiesOf(declaration: Record<string, unknown>, schema: Record<string, any>): StepBody[];
|
|
21
|
+
/** Visit every step of a body at every nesting depth, with its concrete path
|
|
22
|
+
* (`steps[1].then[0]`). */
|
|
23
|
+
export declare function forEachStep(body: StepBody, schema: Record<string, any>, visit: (step: Record<string, any>, stepPath: string) => void): void;
|
|
24
|
+
//# sourceMappingURL=step-bodies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"step-bodies.d.ts","sourceRoot":"","sources":["../src/step-bodies.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AAEH,wCAAwC;AACxC,MAAM,WAAW,QAAQ;IACvB,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,8EAA8E;IAC9E,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CAAC;CAC7C;AAED,kFAAkF;AAClF,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC1B,QAAQ,EAAE,CAiBZ;AAED;4BAC4B;AAC5B,wBAAgB,WAAW,CACzB,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,GAC3D,IAAI,CAEN"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { gatherPropertySchemas, resolveLocalRef, walkStepArray } from "./schema-walk.js";
|
|
2
|
+
import { readStepSlot } from "./step-slot.js";
|
|
3
|
+
/** Every step body `declaration` holds, per its kind's author-facing `schema`. */
|
|
4
|
+
export function stepBodiesOf(declaration, schema) {
|
|
5
|
+
const out = [];
|
|
6
|
+
const seen = new Set();
|
|
7
|
+
for (const [field, fieldSchema] of gatherPropertySchemas(schema)) {
|
|
8
|
+
const slot = readStepSlot(fieldSchema);
|
|
9
|
+
if (!slot || seen.has(field))
|
|
10
|
+
continue;
|
|
11
|
+
const steps = declaration[field];
|
|
12
|
+
if (!Array.isArray(steps))
|
|
13
|
+
continue;
|
|
14
|
+
seen.add(field);
|
|
15
|
+
out.push({
|
|
16
|
+
field,
|
|
17
|
+
invokeField: slot.invoke,
|
|
18
|
+
steps,
|
|
19
|
+
itemSchema: resolveLocalRef(fieldSchema.items, schema),
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
24
|
+
/** Visit every step of a body at every nesting depth, with its concrete path
|
|
25
|
+
* (`steps[1].then[0]`). */
|
|
26
|
+
export function forEachStep(body, schema, visit) {
|
|
27
|
+
walkStepArray(body.steps, body.itemSchema, schema, body.field, visit);
|
|
28
|
+
}
|
package/dist/telo-version.d.ts
CHANGED
package/dist/telo-version.js
CHANGED
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
// its release identity, this is the scale a module's `requires.telo` range is
|
|
6
6
|
// written against, and every kernel in every language reports the same scale.
|
|
7
7
|
/** The surface generation this analyzer implements. */
|
|
8
|
-
export const TELO_SURFACE_VERSION = "0.
|
|
8
|
+
export const TELO_SURFACE_VERSION = "0.90.0";
|
package/dist/template-body.d.ts
CHANGED
|
@@ -33,6 +33,16 @@ export interface TemplateBody {
|
|
|
33
33
|
/** The template bodies a manifest declares — empty for anything that is not a
|
|
34
34
|
* `Telo.Definition` with a `resources:` array. */
|
|
35
35
|
export declare function templateBodies(m: ResourceManifest, registry: DefinitionRegistry, aliases: AliasResolver | undefined, scopes: ModuleScopes | undefined): TemplateBody[];
|
|
36
|
+
/** What a definition's dispatch slot names: the `resources:` entry a `!ref` at
|
|
37
|
+
* `slot` (`invoke` / `provide` / `run` / `mount`) resolves to, with its kind.
|
|
38
|
+
* The entry is matched by its LITERAL `metadata.name`; a slot holding anything
|
|
39
|
+
* but a `!ref`, or naming no entry, resolves to nothing — `validate-template-body`
|
|
40
|
+
* is what reports either. `Self.<entry>` is the explicit self-qualifier. */
|
|
41
|
+
export declare function dispatchTargetOf(definition: Record<string, any>, slot: string): {
|
|
42
|
+
entry: Record<string, any> | undefined;
|
|
43
|
+
kind: string;
|
|
44
|
+
name: string;
|
|
45
|
+
} | undefined;
|
|
36
46
|
/** True when a CEL path lies at or inside a body's own subtree. */
|
|
37
47
|
export declare function pathInBody(path: string, prefix: string): boolean;
|
|
38
48
|
/** The body a CEL path belongs to, or undefined for a path in the definition's
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template-body.d.ts","sourceRoot":"","sources":["../src/template-body.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"template-body.d.ts","sourceRoot":"","sources":["../src/template-body.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,YAAY;IAC3B;qBACiB;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,UAAU,EAAE,kBAAkB,GAAG,SAAS,CAAC;CAC5C;AAED;mDACmD;AACnD,wBAAgB,cAAc,CAC5B,CAAC,EAAE,gBAAgB,EACnB,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,EAAE,aAAa,GAAG,SAAS,EAClC,MAAM,EAAE,YAAY,GAAG,SAAS,GAC/B,YAAY,EAAE,CA0BhB;AAED;;;;6EAI6E;AAC7E,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC/B,IAAI,EAAE,MAAM,GACX;IAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAcpF;AAED,mEAAmE;AACnE,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAIhE;AAED;;+EAE+E;AAC/E,wBAAgB,WAAW,CAAC,CAAC,SAAS;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,EACtD,MAAM,EAAE,SAAS,CAAC,EAAE,EACpB,IAAI,EAAE,MAAM,GACX,CAAC,GAAG,SAAS,CAEf;AAED;;;;6CAI6C;AAC7C,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAQxF"}
|
package/dist/template-body.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isRefSentinel } from "@telorun/templating";
|
|
1
2
|
import { moduleAliasScope } from "./module-alias-scope.js";
|
|
2
3
|
/** The template bodies a manifest declares — empty for anything that is not a
|
|
3
4
|
* `Telo.Definition` with a `resources:` array. */
|
|
@@ -30,6 +31,30 @@ export function templateBodies(m, registry, aliases, scopes) {
|
|
|
30
31
|
}
|
|
31
32
|
return out;
|
|
32
33
|
}
|
|
34
|
+
/** What a definition's dispatch slot names: the `resources:` entry a `!ref` at
|
|
35
|
+
* `slot` (`invoke` / `provide` / `run` / `mount`) resolves to, with its kind.
|
|
36
|
+
* The entry is matched by its LITERAL `metadata.name`; a slot holding anything
|
|
37
|
+
* but a `!ref`, or naming no entry, resolves to nothing — `validate-template-body`
|
|
38
|
+
* is what reports either. `Self.<entry>` is the explicit self-qualifier. */
|
|
39
|
+
export function dispatchTargetOf(definition, slot) {
|
|
40
|
+
const value = definition[slot];
|
|
41
|
+
if (!isRefSentinel(value))
|
|
42
|
+
return undefined;
|
|
43
|
+
const source = value.source;
|
|
44
|
+
const name = source.startsWith("Self.") ? source.slice("Self.".length) : source;
|
|
45
|
+
const bodies = definition.resources;
|
|
46
|
+
if (!Array.isArray(bodies))
|
|
47
|
+
return undefined;
|
|
48
|
+
for (const body of bodies) {
|
|
49
|
+
if (!body || typeof body !== "object")
|
|
50
|
+
continue;
|
|
51
|
+
const entry = body;
|
|
52
|
+
if (entry.metadata?.name !== name || typeof entry.kind !== "string")
|
|
53
|
+
continue;
|
|
54
|
+
return { entry, kind: entry.kind, name };
|
|
55
|
+
}
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
33
58
|
/** True when a CEL path lies at or inside a body's own subtree. */
|
|
34
59
|
export function pathInBody(path, prefix) {
|
|
35
60
|
return (path === prefix || path.startsWith(`${prefix}.`) || path.startsWith(`${prefix}[`));
|
|
@@ -13,6 +13,11 @@ export interface ContextResolveOpts {
|
|
|
13
13
|
aliases?: {
|
|
14
14
|
resolveKind(kind: string): string | undefined;
|
|
15
15
|
};
|
|
16
|
+
/** Per-declaring-module alias tables, so a kind read off a forwarded
|
|
17
|
+
* definition resolves in the module that wrote it. */
|
|
18
|
+
aliasesByModule?: ReadonlyMap<string, {
|
|
19
|
+
resolveKind(kind: string): string | undefined;
|
|
20
|
+
}>;
|
|
16
21
|
allManifests?: Record<string, any>[];
|
|
17
22
|
}
|
|
18
23
|
export declare function resolveTypeFieldToSchema(value: unknown, allManifests: Record<string, any>[], ancestry?: ReadonlySet<string>): Record<string, any> | undefined;
|
|
@@ -39,18 +44,20 @@ export declare function resolveTypeFieldToSchema(value: unknown, allManifests: R
|
|
|
39
44
|
* Example: `properties.self.x-telo-context-from-root: "schema"` reads
|
|
40
45
|
* `manifestRoot.schema` and uses it as the schema of the `self` CEL variable.
|
|
41
46
|
*
|
|
42
|
-
* - `x-telo-context-from-ref-kind`: reads a
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
47
|
+
* - `x-telo-context-from-ref-kind`: reads a KIND from `manifestRoot.<refPath>` —
|
|
48
|
+
* a field holding a kind name, or a definition's dispatch slot holding a
|
|
49
|
+
* `!ref` to a `resources:` entry (whose kind it is) — and returns the
|
|
50
|
+
* `<field>` schema (e.g. `outputType`/`inputType`) the entry itself declares,
|
|
51
|
+
* else the one the kind's definition declares. Used to type `result` against
|
|
52
|
+
* the dispatch target's declared output shape.
|
|
46
53
|
*
|
|
47
54
|
* Syntax: `<refPath>#<field>` — slashes traverse the manifest tree.
|
|
48
55
|
*
|
|
49
|
-
* Example: `x-telo-context-from-ref-kind: "provide
|
|
50
|
-
* `manifestRoot.provide
|
|
51
|
-
*
|
|
56
|
+
* Example: `x-telo-context-from-ref-kind: "provide#outputType"` resolves
|
|
57
|
+
* `manifestRoot.provide` (`!ref source`) to the entry named `source`, and
|
|
58
|
+
* returns its `outputType` schema, or its kind's.
|
|
52
59
|
*
|
|
53
|
-
* Accepts either a single string or an array of strings. With an array,
|
|
60
|
+
* Accepts either a single string or an array of strings. With an array, slots
|
|
54
61
|
* are tried in order and the first one that resolves to a usable schema wins —
|
|
55
62
|
* used by `result:` to find its dispatch target under whichever entry-point
|
|
56
63
|
* field (`provide:` or `invoke:`) the definition declares.
|
|
@@ -70,6 +77,14 @@ export declare function resolveContextAnnotations(schema: Record<string, any>, m
|
|
|
70
77
|
* e.g. exprPath="routes[0].inputs.q", scope="$.routes[*].inputs" → manifest.routes[0]
|
|
71
78
|
*/
|
|
72
79
|
export declare function getManifestItem(exprPath: string, scope: string, manifest: Record<string, any>): Record<string, any>;
|
|
80
|
+
/** The kind an `x-telo-context-from-ref-kind` path names: a field holding a
|
|
81
|
+
* kind NAME (`targetKind`), or a definition's dispatch slot holding a `!ref`
|
|
82
|
+
* to a `resources:` entry, which carries the kind — and, where it narrows
|
|
83
|
+
* one, the contract field itself. */
|
|
84
|
+
export declare function kindAtPath(manifestRoot: Record<string, any>, refPath: string): {
|
|
85
|
+
kind: string;
|
|
86
|
+
entry?: Record<string, any>;
|
|
87
|
+
} | undefined;
|
|
73
88
|
/**
|
|
74
89
|
* Walk a JSON Schema tree and collect all `x-telo-context` annotations,
|
|
75
90
|
* returning them as `{ scope, schema }` pairs using JSONPath-style scopes —
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-cel-context.d.ts","sourceRoot":"","sources":["../src/validate-cel-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"validate-cel-context.d.ts","sourceRoot":"","sources":["../src/validate-cel-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAetF,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AA2B3E,MAAM,WAAW,kBAAkB;IACjC;mEAC+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACnC;;kDAE8C;IAC9C,IAAI,CAAC,EAAE;QACL,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CAAC;KACxD,CAAC;IACF,OAAO,CAAC,EAAE;QACR,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;KAC/C,CAAC;IACF;2DACuD;IACvD,eAAe,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE;QAAE,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC,CAAC;IACzF,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;CACtC;AA4CD,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,OAAO,EACd,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EACnC,QAAQ,GAAE,WAAW,CAAC,MAAM,CAAa,GACxC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CA0EjC;AAyID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACjC,IAAI,CAAC,EAAE,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,GAChD,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAiMrB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC5B,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAuBrB;AAqBD;;;sCAGsC;AACtC,wBAAgB,UAAU,CACxB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACjC,OAAO,EAAE,MAAM,GACd;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAAE,GAAG,SAAS,CAa3D;AAED;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,IAAI,SAAM,GACT,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAAE,CAAC,CAGvD"}
|