@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,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
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE closest candidate to a misspelled name, or undefined.
|
|
3
|
+
*
|
|
4
|
+
* One rule, because a suggestion here is emitted as a `DiagnosticFix` — a
|
|
5
|
+
* whole-value replacement an editor applies in one click — so "closest" has to
|
|
6
|
+
* mean the same thing wherever it is offered. Two properties carry that:
|
|
7
|
+
*
|
|
8
|
+
* - **A TIE returns undefined.** Two candidates at equal distance make the pick
|
|
9
|
+
* arbitrary, and an arbitrary pick that is one click from being applied is
|
|
10
|
+
* worse than no suggestion: it resolves by whatever order the candidate set
|
|
11
|
+
* happened to be built in, which is a `Set`'s insertion order.
|
|
12
|
+
* - **The threshold scales but is CAPPED** (`min(3, len/3)`, and nothing under
|
|
13
|
+
* 1). Without the cap a long name accepts a distant match; without the floor
|
|
14
|
+
* a two-character name gets a "correction" sharing nothing with it.
|
|
15
|
+
*
|
|
16
|
+
* Both are `computeSuggestKind`'s rule, lifted here so the kind-suggestion, the
|
|
17
|
+
* template-body and the export checks cannot drift into three answers — which
|
|
18
|
+
* they had, two of them byte-identical copies differing from this one in both
|
|
19
|
+
* properties.
|
|
20
|
+
*/
|
|
21
|
+
export declare function nearestName(target: string, candidates: Iterable<string>): string | undefined;
|
|
22
|
+
//# sourceMappingURL=nearest-name.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nearest-name.d.ts","sourceRoot":"","sources":["../src/nearest-name.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,GAC3B,MAAM,GAAG,SAAS,CAqBpB"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { distance } from "./levenshtein.js";
|
|
2
|
+
/**
|
|
3
|
+
* THE closest candidate to a misspelled name, or undefined.
|
|
4
|
+
*
|
|
5
|
+
* One rule, because a suggestion here is emitted as a `DiagnosticFix` — a
|
|
6
|
+
* whole-value replacement an editor applies in one click — so "closest" has to
|
|
7
|
+
* mean the same thing wherever it is offered. Two properties carry that:
|
|
8
|
+
*
|
|
9
|
+
* - **A TIE returns undefined.** Two candidates at equal distance make the pick
|
|
10
|
+
* arbitrary, and an arbitrary pick that is one click from being applied is
|
|
11
|
+
* worse than no suggestion: it resolves by whatever order the candidate set
|
|
12
|
+
* happened to be built in, which is a `Set`'s insertion order.
|
|
13
|
+
* - **The threshold scales but is CAPPED** (`min(3, len/3)`, and nothing under
|
|
14
|
+
* 1). Without the cap a long name accepts a distant match; without the floor
|
|
15
|
+
* a two-character name gets a "correction" sharing nothing with it.
|
|
16
|
+
*
|
|
17
|
+
* Both are `computeSuggestKind`'s rule, lifted here so the kind-suggestion, the
|
|
18
|
+
* template-body and the export checks cannot drift into three answers — which
|
|
19
|
+
* they had, two of them byte-identical copies differing from this one in both
|
|
20
|
+
* properties.
|
|
21
|
+
*/
|
|
22
|
+
export function nearestName(target, candidates) {
|
|
23
|
+
if (!target)
|
|
24
|
+
return undefined;
|
|
25
|
+
const threshold = Math.min(3, Math.floor(target.length / 3));
|
|
26
|
+
if (threshold < 1)
|
|
27
|
+
return undefined;
|
|
28
|
+
let best;
|
|
29
|
+
let bestDist = threshold + 1;
|
|
30
|
+
let tied = false;
|
|
31
|
+
for (const candidate of candidates) {
|
|
32
|
+
const d = distance(target, candidate);
|
|
33
|
+
if (d < bestDist) {
|
|
34
|
+
best = candidate;
|
|
35
|
+
bestDist = d;
|
|
36
|
+
tied = false;
|
|
37
|
+
}
|
|
38
|
+
else if (d === bestDist) {
|
|
39
|
+
tied = true;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return !best || bestDist > threshold || tied ? undefined : best;
|
|
43
|
+
}
|
|
@@ -1,23 +1,51 @@
|
|
|
1
|
-
import type
|
|
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
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
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
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
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
|
|
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,
|
|
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"}
|