@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.
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +130 -9
- package/dist/builtins.d.ts.map +1 -1
- package/dist/builtins.js +69 -12
- package/dist/cel-bindings.d.ts +0 -6
- package/dist/cel-bindings.d.ts.map +1 -1
- package/dist/cel-bindings.js +3 -28
- package/dist/definition-registry.d.ts +17 -0
- package/dist/definition-registry.d.ts.map +1 -1
- package/dist/definition-registry.js +31 -2
- package/dist/identifier-name.d.ts +114 -0
- package/dist/identifier-name.d.ts.map +1 -0
- package/dist/identifier-name.js +183 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/manifest-schemas.d.ts +81 -0
- package/dist/manifest-schemas.d.ts.map +1 -1
- package/dist/manifest-schemas.js +208 -6
- package/dist/release/payload-digest.d.ts +7 -3
- package/dist/release/payload-digest.d.ts.map +1 -1
- package/dist/release/payload-digest.js +7 -3
- package/dist/requires-block.d.ts +125 -0
- package/dist/requires-block.d.ts.map +1 -0
- package/dist/requires-block.js +182 -0
- package/dist/schema-keywords.d.ts +68 -0
- package/dist/schema-keywords.d.ts.map +1 -0
- package/dist/schema-keywords.js +324 -0
- package/dist/schema-region.d.ts +12 -1
- package/dist/schema-region.d.ts.map +1 -1
- package/dist/schema-region.js +12 -1
- package/dist/telo-version.d.ts +3 -0
- package/dist/telo-version.d.ts.map +1 -0
- package/dist/telo-version.js +8 -0
- package/dist/types.d.ts +31 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/validate-identifier-names.d.ts +31 -0
- package/dist/validate-identifier-names.d.ts.map +1 -0
- package/dist/validate-identifier-names.js +144 -0
- package/dist/validate-observed-state.d.ts +9 -2
- package/dist/validate-observed-state.d.ts.map +1 -1
- package/dist/validate-observed-state.js +9 -2
- package/dist/validate-references.d.ts.map +1 -1
- package/dist/validate-references.js +5 -26
- package/dist/validate-requires.d.ts +49 -0
- package/dist/validate-requires.d.ts.map +1 -0
- package/dist/validate-requires.js +99 -0
- package/dist/value-type-keyword.d.ts +1 -1
- package/dist/value-type-keyword.d.ts.map +1 -1
- package/dist/value-type-keyword.js +1 -0
- package/dist/version-range.d.ts +88 -0
- package/dist/version-range.d.ts.map +1 -0
- package/dist/version-range.js +173 -0
- package/package.json +2 -2
- package/src/analyzer.ts +146 -10
- package/src/builtins.ts +73 -12
- package/src/cel-bindings.ts +3 -28
- package/src/definition-registry.ts +30 -2
- package/src/identifier-name.ts +228 -0
- package/src/index.ts +34 -0
- package/src/manifest-schemas.ts +223 -4
- package/src/release/payload-digest.ts +7 -3
- package/src/requires-block.ts +253 -0
- package/src/schema-keywords.ts +359 -0
- package/src/schema-region.ts +12 -1
- package/src/telo-version.ts +9 -0
- package/src/types.ts +32 -0
- package/src/validate-identifier-names.ts +173 -0
- package/src/validate-observed-state.ts +9 -2
- package/src/validate-references.ts +5 -26
- package/src/validate-requires.ts +129 -0
- package/src/value-type-keyword.ts +1 -0
- package/src/version-range.ts +238 -0
package/dist/analyzer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAWzE,OAAO,EACL,aAAa,EAEb,KAAK,YAAY,EAElB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAE9D,OAAO,EACL,KAAK,aAAa,EAGnB,MAAM,0BAA0B,CAAC;AAsBlC,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAwBvF,OAAO,EAAsB,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"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"}
|
package/dist/analyzer.js
CHANGED
|
@@ -29,12 +29,15 @@ import { collectValueSchemaIssues } from "./validate-value-schema.js";
|
|
|
29
29
|
import { DiagnosticSeverity } from "./types.js";
|
|
30
30
|
import { extractAccessChains, extractCelRegionScopes, getManifestItem, pathMatchesScope, resolveContextAnnotations, resolveTypeFieldToSchema, } from "./validate-cel-context.js";
|
|
31
31
|
import { buildEvalPaths, evalPathsCover } from "./eval-paths.js";
|
|
32
|
-
import { BINDINGS_ANNOTATION, bindingContextProperties, bindingPathChain,
|
|
32
|
+
import { BINDINGS_ANNOTATION, bindingContextProperties, bindingPathChain, findBindingSites, resolveBindingOrder, schemaAtChain, } from "./cel-bindings.js";
|
|
33
|
+
import { CEL_RESERVED_WORDS, checkName } from "./identifier-name.js";
|
|
34
|
+
import { validateIdentifierNames } from "./validate-identifier-names.js";
|
|
33
35
|
import { validateExtends } from "./validate-extends.js";
|
|
34
36
|
import { validateLogging } from "./validate-logging.js";
|
|
35
37
|
import { validateModuleArtifact } from "./validate-module-artifact.js";
|
|
36
38
|
import { validateIncludePlacement } from "./validate-include-placement.js";
|
|
37
39
|
import { validateModuleMetadata } from "./validate-module-metadata.js";
|
|
40
|
+
import { validateRequires } from "./validate-requires.js";
|
|
38
41
|
import { validateBaseMapping } from "./validate-base-mapping.js";
|
|
39
42
|
import { validateInvocationContract } from "./validate-invocation-contract.js";
|
|
40
43
|
import { collectStepInputIssues } from "./validate-step-inputs.js";
|
|
@@ -819,6 +822,85 @@ function collectCelValueSlots(data, schema, path) {
|
|
|
819
822
|
}
|
|
820
823
|
return slots;
|
|
821
824
|
}
|
|
825
|
+
/**
|
|
826
|
+
* Files belonging to a module this runtime declared itself unable to read.
|
|
827
|
+
*
|
|
828
|
+
* Attribution is by FILE rather than by resource identity, the same choice
|
|
829
|
+
* `remapMigratedPaths` makes and for the same reason: a diagnostic carries at
|
|
830
|
+
* most two routing facts and routinely only one, so indexing by resource would
|
|
831
|
+
* leave every diagnostic without `data.resource` unreachable.
|
|
832
|
+
*
|
|
833
|
+
* **A module NAME is not a graph-unique key.** Names are module-scoped, so two
|
|
834
|
+
* libraries may both be called `Store` — CLAUDE.md names this exact hazard for
|
|
835
|
+
* migration provenance ("two libraries declaring a Store would share one
|
|
836
|
+
* bucket"), where the answer is to narrow or not remap at all. Same answer here:
|
|
837
|
+
* the gated doc's own `metadata.source` is always suppressed, and a name is used
|
|
838
|
+
* to reach its `include:` partials only when that name identifies exactly ONE
|
|
839
|
+
* module doc in the set. Where it does not, the partials keep their diagnostics
|
|
840
|
+
* rather than risk silencing an unrelated library's — a stray extra diagnostic is
|
|
841
|
+
* a far cheaper failure than a hidden one.
|
|
842
|
+
*
|
|
843
|
+
* A module doc with no `source` contributes nothing — suppressing on a guess
|
|
844
|
+
* would hide diagnostics belonging to files nobody named.
|
|
845
|
+
*/
|
|
846
|
+
function filesOfUnreadableModules(manifests, requiresDiagnostics) {
|
|
847
|
+
const files = new Set();
|
|
848
|
+
const gatedNames = new Set();
|
|
849
|
+
for (const d of requiresDiagnostics) {
|
|
850
|
+
if (d.code !== "MODULE_REQUIRES_NEWER_RUNTIME")
|
|
851
|
+
continue;
|
|
852
|
+
const data = d.data;
|
|
853
|
+
// The gated document itself, addressed by the file it was declared in.
|
|
854
|
+
if (typeof data?.filePath === "string" && data.filePath)
|
|
855
|
+
files.add(data.filePath);
|
|
856
|
+
const name = data?.resource?.name;
|
|
857
|
+
if (typeof name === "string")
|
|
858
|
+
gatedNames.add(name);
|
|
859
|
+
}
|
|
860
|
+
if (files.size === 0 && gatedNames.size === 0)
|
|
861
|
+
return files;
|
|
862
|
+
// How many module docs answer to each gated name — the ambiguity test.
|
|
863
|
+
const docsPerName = new Map();
|
|
864
|
+
for (const m of manifests) {
|
|
865
|
+
if (m.kind !== "Telo.Application" && m.kind !== "Telo.Library")
|
|
866
|
+
continue;
|
|
867
|
+
const name = m.metadata?.name;
|
|
868
|
+
if (typeof name === "string" && gatedNames.has(name)) {
|
|
869
|
+
docsPerName.set(name, (docsPerName.get(name) ?? 0) + 1);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
for (const m of manifests) {
|
|
873
|
+
const metadata = (m.metadata ?? {});
|
|
874
|
+
const owner = metadata.module;
|
|
875
|
+
if (typeof owner !== "string" || !gatedNames.has(owner))
|
|
876
|
+
continue;
|
|
877
|
+
if (docsPerName.get(owner) !== 1)
|
|
878
|
+
continue; // ambiguous — do not guess
|
|
879
|
+
if (typeof metadata.source === "string" && metadata.source)
|
|
880
|
+
files.add(metadata.source);
|
|
881
|
+
}
|
|
882
|
+
return files;
|
|
883
|
+
}
|
|
884
|
+
/**
|
|
885
|
+
* Drop every diagnostic anchored in a file whose module this runtime cannot
|
|
886
|
+
* read, except the gate diagnostic itself.
|
|
887
|
+
*
|
|
888
|
+
* A filter rather than a guard on each validator: threading "skip this module"
|
|
889
|
+
* through thirty validators would make each one responsible for a rule none of
|
|
890
|
+
* them owns, and a validator added later would silently opt out of it. A
|
|
891
|
+
* diagnostic with no `filePath` is KEPT — suppression must never be the default
|
|
892
|
+
* for something it cannot attribute.
|
|
893
|
+
*/
|
|
894
|
+
function suppressUnreadableModuleDiagnostics(diagnostics, unreadableFiles) {
|
|
895
|
+
if (unreadableFiles.size === 0)
|
|
896
|
+
return diagnostics;
|
|
897
|
+
return diagnostics.filter((d) => {
|
|
898
|
+
if (d.code === "MODULE_REQUIRES_NEWER_RUNTIME")
|
|
899
|
+
return true;
|
|
900
|
+
const filePath = d.data?.filePath;
|
|
901
|
+
return typeof filePath !== "string" || !unreadableFiles.has(filePath);
|
|
902
|
+
});
|
|
903
|
+
}
|
|
822
904
|
export class StaticAnalyzer {
|
|
823
905
|
celEnv;
|
|
824
906
|
constructor(options = {}) {
|
|
@@ -1278,6 +1360,21 @@ export class StaticAnalyzer {
|
|
|
1278
1360
|
});
|
|
1279
1361
|
}
|
|
1280
1362
|
}
|
|
1363
|
+
// Declared runtime requirements, FIRST among the validators and suppressing
|
|
1364
|
+
// the rest for any module this runtime cannot read. A module that adopted
|
|
1365
|
+
// newer syntax also produces the vocabulary errors that syntax causes here —
|
|
1366
|
+
// an unknown `use` token, an object where a zone annotation expects a
|
|
1367
|
+
// pointer, an `additionalProperties` violation against a kernel-owned
|
|
1368
|
+
// schema — every one of which is true and blames the module's author for a
|
|
1369
|
+
// version skew. Reporting them beside the gate would bury the one message
|
|
1370
|
+
// that names the actual cause and the actual fix.
|
|
1371
|
+
const requiresDiagnostics = validateRequires(allManifests, {
|
|
1372
|
+
teloVersion: options?.teloVersion,
|
|
1373
|
+
hostVersions: options?.hostVersions,
|
|
1374
|
+
entryModules: rootModules,
|
|
1375
|
+
});
|
|
1376
|
+
const unreadableFiles = filesOfUnreadableModules(allManifests, requiresDiagnostics);
|
|
1377
|
+
diagnostics.push(...requiresDiagnostics);
|
|
1281
1378
|
if (!options?.skipValidation) {
|
|
1282
1379
|
diagnostics.push(...validateSchemaTypeRefs(allManifests, defs, aliases, aliasesByModule, rootModules));
|
|
1283
1380
|
// §14.1 / §10.3: redaction paths and `on_full: block` are statically
|
|
@@ -1292,6 +1389,11 @@ export class StaticAnalyzer {
|
|
|
1292
1389
|
// these fields, which is precisely why they need a check: a mistyped one
|
|
1293
1390
|
// has no runtime failure mode that would ever surface it.
|
|
1294
1391
|
diagnostics.push(...validateModuleMetadata(allManifests, defs, aliases));
|
|
1392
|
+
// Every author-written name. Telo has no lexer, so a name's shape is
|
|
1393
|
+
// unchecked where it is declared and its consequences land at whichever
|
|
1394
|
+
// CEL site reads it — for a hyphen, sometimes as silent arithmetic. Takes
|
|
1395
|
+
// the call graph for step names rather than re-walking the step arrays.
|
|
1396
|
+
diagnostics.push(...validateIdentifierNames(allManifests, defs, aliases, rootModules, getCallGraph()));
|
|
1295
1397
|
// A file embed resolves at resource creation, so one written on a doc that
|
|
1296
1398
|
// is never instantiated is read by nothing and would ship silently.
|
|
1297
1399
|
diagnostics.push(...validateIncludePlacement(allManifests));
|
|
@@ -1304,7 +1406,7 @@ export class StaticAnalyzer {
|
|
|
1304
1406
|
// normalisation have already run above; that's all downstream
|
|
1305
1407
|
// consumers (prepare, init loop) require.
|
|
1306
1408
|
if (options?.skipValidation) {
|
|
1307
|
-
return diagnostics;
|
|
1409
|
+
return suppressUnreadableModuleDiagnostics(diagnostics, unreadableFiles);
|
|
1308
1410
|
}
|
|
1309
1411
|
// Build a name→manifest map for looking up referenced resources
|
|
1310
1412
|
const byName = new Map();
|
|
@@ -1769,15 +1871,34 @@ export class StaticAnalyzer {
|
|
|
1769
1871
|
const keywords = new Set(CEL_RESERVED_WORDS);
|
|
1770
1872
|
for (const name of Object.keys(declared)) {
|
|
1771
1873
|
const shadows = inScope.has(name);
|
|
1772
|
-
if (
|
|
1874
|
+
if (shadows || keywords.has(name)) {
|
|
1875
|
+
diagnostics.push({
|
|
1876
|
+
severity: DiagnosticSeverity.Error,
|
|
1877
|
+
code: "BINDING_NAME_RESERVED",
|
|
1878
|
+
source: SOURCE,
|
|
1879
|
+
message: shadows
|
|
1880
|
+
? `${m.kind}/${bindingsName}: binding '${name}' shadows a variable already in scope here (${[...inScope].sort().join(", ")}). Rename the binding — a scope variable always wins, so this one would never be read.`
|
|
1881
|
+
: `${m.kind}/${bindingsName}: binding '${name}' is a CEL keyword, so no expression can read it as a reference. Rename the binding.`,
|
|
1882
|
+
data: {
|
|
1883
|
+
resource: resourceRef,
|
|
1884
|
+
filePath: bindingsFile,
|
|
1885
|
+
path: `${celBindingSites.field}.${name}`,
|
|
1886
|
+
},
|
|
1887
|
+
});
|
|
1888
|
+
continue;
|
|
1889
|
+
}
|
|
1890
|
+
// A binding is read by bare name, so it lives in the same
|
|
1891
|
+
// identifier space as a resource or step name and breaks the
|
|
1892
|
+
// same way. The keyword tier is unreachable here — the check
|
|
1893
|
+
// above owns it, and can also say what is being shadowed.
|
|
1894
|
+
const violation = checkName(name, "value", "binding name");
|
|
1895
|
+
if (!violation)
|
|
1773
1896
|
continue;
|
|
1774
1897
|
diagnostics.push({
|
|
1775
|
-
severity:
|
|
1776
|
-
code:
|
|
1898
|
+
severity: violation.severity,
|
|
1899
|
+
code: violation.code,
|
|
1777
1900
|
source: SOURCE,
|
|
1778
|
-
message:
|
|
1779
|
-
? `${m.kind}/${bindingsName}: binding '${name}' shadows a variable already in scope here (${[...inScope].sort().join(", ")}). Rename the binding — a scope variable always wins, so this one would never be read.`
|
|
1780
|
-
: `${m.kind}/${bindingsName}: binding '${name}' is a CEL keyword, so no expression can read it as a reference. Rename the binding.`,
|
|
1901
|
+
message: `${m.kind}/${bindingsName}: ${violation.message}`,
|
|
1781
1902
|
data: {
|
|
1782
1903
|
resource: resourceRef,
|
|
1783
1904
|
filePath: bindingsFile,
|
|
@@ -2120,7 +2241,7 @@ export class StaticAnalyzer {
|
|
|
2120
2241
|
diagnostics.push(...validateUnusedDeclarations(allManifests, this.celEnv));
|
|
2121
2242
|
// Reroute diagnostics on synthetic (inline-extracted) resources back to
|
|
2122
2243
|
// the chain root so position-index lookups land on the parent doc.
|
|
2123
|
-
return rewriteSyntheticOrigins(diagnostics, allManifests);
|
|
2244
|
+
return rewriteSyntheticOrigins(suppressUnreadableModuleDiagnostics(diagnostics, unreadableFiles), allManifests);
|
|
2124
2245
|
}
|
|
2125
2246
|
analyzeErrors(manifests, options, registry, zoneExportCache) {
|
|
2126
2247
|
return this.analyze(manifests, options, registry, zoneExportCache).filter((d) => d.severity === DiagnosticSeverity.Error);
|
package/dist/builtins.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builtins.d.ts","sourceRoot":"","sources":["../src/builtins.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"builtins.d.ts","sourceRoot":"","sources":["../src/builtins.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAiNvD,eAAO,MAAM,eAAe,EAAE,kBAAkB,EAusB/C,CAAC"}
|
package/dist/builtins.js
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
|
-
import { manifestFragment } from "./manifest-schemas.js";
|
|
2
|
-
|
|
1
|
+
import { manifestFragment, manifestFragmentRef, withSchemaFragments } from "./manifest-schemas.js";
|
|
2
|
+
/** A slot holding author-written JSON Schema. Localized and hoisted by
|
|
3
|
+
* {@link withSchemaFragments} on the enclosing schema, which is what makes the
|
|
4
|
+
* `#/$defs` pointer resolve inside whatever AJV compiles.
|
|
5
|
+
*
|
|
6
|
+
* `KindSchema` and `JsonSchema7` share a body; the name is the discriminator
|
|
7
|
+
* the IDE reads off the `x-telo-fragment` stamp to decide whether the
|
|
8
|
+
* `x-telo-*` vocabulary belongs here. A kind's own `schema:` is where it does;
|
|
9
|
+
* a `status:` block or an `inputType:` describes plain data, where it does not. */
|
|
10
|
+
const kindSchemaSlot = {
|
|
11
|
+
title: "Schema",
|
|
12
|
+
description: "Configuration this kind accepts, as JSON Schema plus `x-telo-*` annotations.",
|
|
13
|
+
$ref: manifestFragmentRef("KindSchema"),
|
|
14
|
+
};
|
|
15
|
+
/** Observed state a kind reports while running, as a data schema. `required:` is
|
|
16
|
+
* rejected separately by `validateObservedStateDeclarations`, which can say why
|
|
17
|
+
* and what to write instead. */
|
|
18
|
+
const observedStateSlot = {
|
|
19
|
+
title: "Observed state",
|
|
20
|
+
description: "What a resource of this kind reports while running, published at `resources.<name>.status.<field>`.",
|
|
21
|
+
$ref: manifestFragmentRef("JsonSchema7"),
|
|
22
|
+
};
|
|
3
23
|
/** Descriptive provenance a module declares about itself, shared by
|
|
4
24
|
* `Telo.Application` and `Telo.Library`.
|
|
5
25
|
*
|
|
@@ -21,6 +41,31 @@ const PROVENANCE_METADATA = {
|
|
|
21
41
|
license: { type: "string" },
|
|
22
42
|
documentation: { type: "string" },
|
|
23
43
|
};
|
|
44
|
+
/** The declared runtime requirements block, shared by `Telo.Application` and
|
|
45
|
+
* `Telo.Library` — the two module kinds, whose schemas are otherwise
|
|
46
|
+
* independent and would drift.
|
|
47
|
+
*
|
|
48
|
+
* **Deliberately says only "these are objects", and nothing about the values.**
|
|
49
|
+
* The grammar belongs to `requires-block.ts`, which is the single reader, and
|
|
50
|
+
* every rule that matters — `^` and `~` refused, a bare version refused, bounds
|
|
51
|
+
* that must not exclude each other, an upper bound that must name a version that
|
|
52
|
+
* exists — needs a parse and a comparison, not a schema. Adding `type: "string"`
|
|
53
|
+
* here bought nothing and cost a duplicate: `telo: 80` then produced BOTH a
|
|
54
|
+
* `SCHEMA_VIOLATION` and a `REQUIRES_INVALID` for one node, one of them phrased
|
|
55
|
+
* by a layer that does not know what the value is for.
|
|
56
|
+
*
|
|
57
|
+
* Left open at both tiers for the same reason. An unrecognized axis is reported
|
|
58
|
+
* by the reader with the vocabulary it knows — a far better message than AJV's —
|
|
59
|
+
* and, critically, is SUPPRESSED while the `telo` requirement is itself unmet,
|
|
60
|
+
* since an older runtime not knowing a newer axis is a consequence of the
|
|
61
|
+
* version skew rather than a second defect. AJV cannot express that ordering. */
|
|
62
|
+
const REQUIRES_SCHEMA = {
|
|
63
|
+
type: "object",
|
|
64
|
+
properties: {
|
|
65
|
+
host: { type: "object" },
|
|
66
|
+
},
|
|
67
|
+
additionalProperties: true,
|
|
68
|
+
};
|
|
24
69
|
/** Author-declared subset of `files:` that ships in the artifact's lazily
|
|
25
70
|
* materialized `assets` layer. Optional: an unclaimed file joins the `common`
|
|
26
71
|
* layer, which is pulled alongside any controller layer, so omitting this costs
|
|
@@ -265,13 +310,13 @@ export const KERNEL_BUILTINS = [
|
|
|
265
310
|
// kernel registers this controller directly at boot, before any lazy
|
|
266
311
|
// resolution — it states truthfully who provides it.
|
|
267
312
|
controllers: [{ runtime: "kernel", entry: "Telo.JsonSchema" }],
|
|
268
|
-
schema: {
|
|
313
|
+
schema: withSchemaFragments({
|
|
269
314
|
type: "object",
|
|
270
315
|
properties: {
|
|
271
316
|
schema: {
|
|
272
317
|
title: "Schema",
|
|
273
318
|
description: "JSON Schema definition for the declared data type.",
|
|
274
|
-
|
|
319
|
+
$ref: manifestFragmentRef("JsonSchema7"),
|
|
275
320
|
},
|
|
276
321
|
extends: {
|
|
277
322
|
title: "Extends",
|
|
@@ -304,13 +349,13 @@ export const KERNEL_BUILTINS = [
|
|
|
304
349
|
},
|
|
305
350
|
required: ["schema"],
|
|
306
351
|
additionalProperties: false,
|
|
307
|
-
},
|
|
352
|
+
}),
|
|
308
353
|
},
|
|
309
354
|
{
|
|
310
355
|
kind: "Telo.Definition",
|
|
311
356
|
metadata: { name: "Abstract", module: "Telo" },
|
|
312
357
|
capability: "Telo.Template",
|
|
313
|
-
schema: {
|
|
358
|
+
schema: withSchemaFragments({
|
|
314
359
|
type: "object",
|
|
315
360
|
properties: {
|
|
316
361
|
kind: { type: "string" },
|
|
@@ -321,15 +366,15 @@ export const KERNEL_BUILTINS = [
|
|
|
321
366
|
additionalProperties: true,
|
|
322
367
|
},
|
|
323
368
|
capability: { type: "string" },
|
|
324
|
-
schema:
|
|
325
|
-
status:
|
|
369
|
+
schema: kindSchemaSlot,
|
|
370
|
+
status: observedStateSlot,
|
|
326
371
|
},
|
|
327
372
|
required: ["metadata"],
|
|
328
373
|
// Telo.Abstract is an extension point by design — it must accept forward-compatible
|
|
329
374
|
// fields (e.g. inputType/outputType from the typed-abstracts plan) without requiring
|
|
330
375
|
// the analyzer to enumerate them here.
|
|
331
376
|
additionalProperties: true,
|
|
332
|
-
},
|
|
377
|
+
}),
|
|
333
378
|
},
|
|
334
379
|
{
|
|
335
380
|
kind: "Telo.Definition",
|
|
@@ -347,11 +392,17 @@ export const KERNEL_BUILTINS = [
|
|
|
347
392
|
// matching how Run.Sequence steps factor dispatch from data. The dispatch
|
|
348
393
|
// entry-point (`invoke` / `provide` / `run`) determines how `inputs`/`result`
|
|
349
394
|
// are interpreted at runtime. See analyzer/nodejs/plans/template-internal-cel-validation.md.
|
|
350
|
-
schema: {
|
|
395
|
+
schema: withSchemaFragments({
|
|
351
396
|
type: "object",
|
|
352
397
|
additionalProperties: true,
|
|
353
398
|
properties: {
|
|
354
|
-
|
|
399
|
+
// The kind's own configuration contract. Declared as a slot for the
|
|
400
|
+
// first time here: it was reachable only as an unnamed extra property,
|
|
401
|
+
// so nothing could say what belonged in it — no completion inside a
|
|
402
|
+
// `schema:` block, and a misspelled keyword surviving to a runtime
|
|
403
|
+
// failure that named a different field.
|
|
404
|
+
schema: kindSchemaSlot,
|
|
405
|
+
status: observedStateSlot,
|
|
355
406
|
resources: {
|
|
356
407
|
type: "array",
|
|
357
408
|
items: {
|
|
@@ -521,7 +572,7 @@ export const KERNEL_BUILTINS = [
|
|
|
521
572
|
},
|
|
522
573
|
},
|
|
523
574
|
},
|
|
524
|
-
},
|
|
575
|
+
}),
|
|
525
576
|
},
|
|
526
577
|
{
|
|
527
578
|
kind: "Telo.Definition",
|
|
@@ -772,6 +823,9 @@ export const KERNEL_BUILTINS = [
|
|
|
772
823
|
// CLI flag — so a level derived from the host environment goes through a
|
|
773
824
|
// `variables:` entry read with `!cel`. See kernel/specs/logging.md §12.
|
|
774
825
|
logging: ROOT_LOGGING_SCHEMA,
|
|
826
|
+
// The runtime range this module is verified against. See
|
|
827
|
+
// `analyzer/nodejs/src/requires-block.ts`.
|
|
828
|
+
requires: REQUIRES_SCHEMA,
|
|
775
829
|
},
|
|
776
830
|
required: ["metadata"],
|
|
777
831
|
additionalProperties: false,
|
|
@@ -862,6 +916,9 @@ export const KERNEL_BUILTINS = [
|
|
|
862
916
|
},
|
|
863
917
|
additionalProperties: true,
|
|
864
918
|
},
|
|
919
|
+
// The runtime range this module is verified against. See
|
|
920
|
+
// `analyzer/nodejs/src/requires-block.ts`.
|
|
921
|
+
requires: REQUIRES_SCHEMA,
|
|
865
922
|
},
|
|
866
923
|
required: ["metadata"],
|
|
867
924
|
additionalProperties: false,
|
package/dist/cel-bindings.d.ts
CHANGED
|
@@ -14,12 +14,6 @@ export interface BindingSites {
|
|
|
14
14
|
/** Variable names the annotated contexts declare — a binding may not shadow one. */
|
|
15
15
|
scopeNames: Set<string>;
|
|
16
16
|
}
|
|
17
|
-
/**
|
|
18
|
-
* CEL keywords. A binding named after one is unreachable — `true` lexes as a
|
|
19
|
-
* literal, `in` as an operator — so it is reserved alongside the scope names,
|
|
20
|
-
* which turns silence into a diagnostic.
|
|
21
|
-
*/
|
|
22
|
-
export declare const CEL_RESERVED_WORDS: readonly string[];
|
|
23
17
|
/** Locate a kind's bindings field and the scope names its annotated contexts
|
|
24
18
|
* declare. Returns undefined for a kind that declares no bindings region. */
|
|
25
19
|
export declare function findBindingSites(definitionSchema: Record<string, any> | undefined): BindingSites | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cel-bindings.d.ts","sourceRoot":"","sources":["../src/cel-bindings.ts"],"names":[],"mappings":"AAIA;;;;gCAIgC;AAChC,eAAO,MAAM,mBAAmB,yBAAyB,CAAC;AAE1D,MAAM,WAAW,YAAY;IAC3B,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd;;gCAE4B;IAC5B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,oFAAoF;IACpF,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACzB;
|
|
1
|
+
{"version":3,"file":"cel-bindings.d.ts","sourceRoot":"","sources":["../src/cel-bindings.ts"],"names":[],"mappings":"AAIA;;;;gCAIgC;AAChC,eAAO,MAAM,mBAAmB,yBAAyB,CAAC;AAE1D,MAAM,WAAW,YAAY;IAC3B,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd;;gCAE4B;IAC5B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,oFAAoF;IACpF,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACzB;AAMD;8EAC8E;AAC9E,wBAAgB,gBAAgB,CAC9B,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAChD,YAAY,GAAG,SAAS,CAW1B;AAuDD;uEACuE;AACvE,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAW1B;AAED;;mFAEmF;AACnF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,GAAG,IAAI,CAQhE;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACjC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAMrB;AAED;oEACoE;AACpE,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACxB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CASjC;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IACtE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC;CACpB,CAwBA"}
|
package/dist/cel-bindings.js
CHANGED
|
@@ -7,34 +7,9 @@ import { extractContextsFromSchema } from "./validate-cel-context.js";
|
|
|
7
7
|
* contexts that see it may be anchored anywhere (a decision table annotates both
|
|
8
8
|
* `choices` and `default`). */
|
|
9
9
|
export const BINDINGS_ANNOTATION = "x-telo-bindings-from";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
* which turns silence into a diagnostic.
|
|
14
|
-
*/
|
|
15
|
-
export const CEL_RESERVED_WORDS = [
|
|
16
|
-
"as",
|
|
17
|
-
"break",
|
|
18
|
-
"const",
|
|
19
|
-
"continue",
|
|
20
|
-
"else",
|
|
21
|
-
"false",
|
|
22
|
-
"for",
|
|
23
|
-
"function",
|
|
24
|
-
"if",
|
|
25
|
-
"import",
|
|
26
|
-
"in",
|
|
27
|
-
"let",
|
|
28
|
-
"loop",
|
|
29
|
-
"namespace",
|
|
30
|
-
"null",
|
|
31
|
-
"package",
|
|
32
|
-
"return",
|
|
33
|
-
"true",
|
|
34
|
-
"var",
|
|
35
|
-
"void",
|
|
36
|
-
"while",
|
|
37
|
-
];
|
|
10
|
+
// CEL keywords live in `identifier-name.ts` — a binding named after one is
|
|
11
|
+
// unreachable for exactly the reason a resource or step named after one is, so
|
|
12
|
+
// the list belongs to the identifier vocabulary rather than to this file.
|
|
38
13
|
/** Locate a kind's bindings field and the scope names its annotated contexts
|
|
39
14
|
* declare. Returns undefined for a kind that declares no bindings region. */
|
|
40
15
|
export function findBindingSites(definitionSchema) {
|
|
@@ -52,6 +52,23 @@ export declare class DefinitionRegistry {
|
|
|
52
52
|
* `$ref: "telo://<module>/<Name>"` would then silently validate against the
|
|
53
53
|
* kind's schema instead. The caller reports it; nothing is overwritten. */
|
|
54
54
|
registerNamedTypeSchema(id: string, schema: Record<string, any>): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Register a schema, surviving one AJV refuses.
|
|
57
|
+
*
|
|
58
|
+
* `addSchema` META-VALIDATES and THROWS, and a throw here escapes the whole
|
|
59
|
+
* analyze pass: one author schema with `minimum: "3"` in it aborted the run
|
|
60
|
+
* with AJV's own unanchored text and took every other diagnostic in the file
|
|
61
|
+
* down with it — including the anchored one that says exactly which keyword is
|
|
62
|
+
* wrong. Registration is a lookup table for `$ref` resolution, so failing to
|
|
63
|
+
* fill one entry costs a reference that could not have resolved anyway.
|
|
64
|
+
*
|
|
65
|
+
* Nothing is swallowed: an unregisterable schema is invalid, and the two
|
|
66
|
+
* checks that report it both run afterwards and both anchor on the offending
|
|
67
|
+
* line — `SCHEMA_VIOLATION` from the `KindSchema` / `JsonSchema7` fragment the
|
|
68
|
+
* slot points at, and `SCHEMA_COMPILE_ERROR` from {@link schemaCompileError},
|
|
69
|
+
* which wraps `compile` for this same reason.
|
|
70
|
+
*/
|
|
71
|
+
private tryAddSchema;
|
|
55
72
|
/** True when a schema is registered under `id` (a canonical `telo://` type id
|
|
56
73
|
* or a definition `$id`). Used to flag schema `$ref`s that resolve to nothing. */
|
|
57
74
|
hasSchemaId(id: string): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definition-registry.d.ts","sourceRoot":"","sources":["../src/definition-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,0BAA0B,CAAC;AAIlC,+EAA+E;AAC/E,qBAAa,kBAAkB;;IAK7B;;sFAEkF;IAClF,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAqB;IACzD;;mFAE+E;IAC/E,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAqB;IAEzD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAyC;IAC9D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwC;IAClE,mEAAmE;IACnE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA+B;IAC1D;;;;wEAIoE;IACpE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;IAEzD,QAAQ,CAAC,UAAU,EAAE,kBAAkB,GAAG,IAAI;IAoC9C,OAAO,CAAC,aAAa;IASrB;;;;;;;;;;;;;2FAauF;IACvF,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAK1E;;;;;;;;;;gFAU4E;IAC5E,uBAAuB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO;IAQzE;uFACmF;IACnF,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIhC;;;gEAG4D;IAC5D,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS;IAMxD;;;;oFAIgF;IAChF,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,EAAE;IAWtE;;;;;;iCAM6B;IAC7B,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,GAAG,SAAS;IASnE;;;;4EAIwE;IACxE,OAAO,CAAC,iBAAiB;
|
|
1
|
+
{"version":3,"file":"definition-registry.d.ts","sourceRoot":"","sources":["../src/definition-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,0BAA0B,CAAC;AAIlC,+EAA+E;AAC/E,qBAAa,kBAAkB;;IAK7B;;sFAEkF;IAClF,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAqB;IACzD;;mFAE+E;IAC/E,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAqB;IAEzD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAyC;IAC9D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwC;IAClE,mEAAmE;IACnE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA+B;IAC1D;;;;wEAIoE;IACpE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;IAEzD,QAAQ,CAAC,UAAU,EAAE,kBAAkB,GAAG,IAAI;IAoC9C,OAAO,CAAC,aAAa;IASrB;;;;;;;;;;;;;2FAauF;IACvF,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAK1E;;;;;;;;;;gFAU4E;IAC5E,uBAAuB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO;IAQzE;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,YAAY;IASpB;uFACmF;IACnF,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIhC;;;gEAG4D;IAC5D,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS;IAMxD;;;;oFAIgF;IAChF,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,EAAE;IAWtE;;;;;;iCAM6B;IAC7B,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,GAAG,SAAS;IASnE;;;;4EAIwE;IACxE,OAAO,CAAC,iBAAiB;IAqBzB;;;;;;;;;;;;;;4BAcwB;IACxB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAShD,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAIrD;;;uCAGmC;IACnC,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAWxD,gGAAgG;IAChG,kBAAkB,CAChB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;KAAE,GACvD,iBAAiB,GAAG,SAAS;IAOhC;;;;;;;;qFAQiF;IACjF,2BAA2B,CACzB,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,EAAE,aAAa,EACtB,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,GAC1C,iBAAiB,GAAG,SAAS;IAkChC,OAAO,CAAC,uBAAuB;IA+B/B;;qEAEiE;IACjE,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,kBAAkB,EAAE;IAgBxD,KAAK,IAAI,MAAM,EAAE;CAGlB"}
|
|
@@ -108,10 +108,36 @@ export class DefinitionRegistry {
|
|
|
108
108
|
return false;
|
|
109
109
|
if (this.registeredSchemaIds.has(id) || this.ajv.getSchema(id))
|
|
110
110
|
return true;
|
|
111
|
-
this.
|
|
111
|
+
if (!this.tryAddSchema(schema, id))
|
|
112
|
+
return true;
|
|
112
113
|
this.registeredSchemaIds.add(id);
|
|
113
114
|
return true;
|
|
114
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* Register a schema, surviving one AJV refuses.
|
|
118
|
+
*
|
|
119
|
+
* `addSchema` META-VALIDATES and THROWS, and a throw here escapes the whole
|
|
120
|
+
* analyze pass: one author schema with `minimum: "3"` in it aborted the run
|
|
121
|
+
* with AJV's own unanchored text and took every other diagnostic in the file
|
|
122
|
+
* down with it — including the anchored one that says exactly which keyword is
|
|
123
|
+
* wrong. Registration is a lookup table for `$ref` resolution, so failing to
|
|
124
|
+
* fill one entry costs a reference that could not have resolved anyway.
|
|
125
|
+
*
|
|
126
|
+
* Nothing is swallowed: an unregisterable schema is invalid, and the two
|
|
127
|
+
* checks that report it both run afterwards and both anchor on the offending
|
|
128
|
+
* line — `SCHEMA_VIOLATION` from the `KindSchema` / `JsonSchema7` fragment the
|
|
129
|
+
* slot points at, and `SCHEMA_COMPILE_ERROR` from {@link schemaCompileError},
|
|
130
|
+
* which wraps `compile` for this same reason.
|
|
131
|
+
*/
|
|
132
|
+
tryAddSchema(schema, id) {
|
|
133
|
+
try {
|
|
134
|
+
this.ajv.addSchema(schema, id);
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
115
141
|
/** True when a schema is registered under `id` (a canonical `telo://` type id
|
|
116
142
|
* or a definition `$id`). Used to flag schema `$ref`s that resolve to nothing. */
|
|
117
143
|
hasSchemaId(id) {
|
|
@@ -173,7 +199,10 @@ export class DefinitionRegistry {
|
|
|
173
199
|
if (this.ajv.getSchema(id)) {
|
|
174
200
|
throw new Error(`Duplicate definition schema $id: "${id}" is already registered`);
|
|
175
201
|
}
|
|
176
|
-
|
|
202
|
+
// A schema AJV refuses is left unregistered rather than aborting the pass —
|
|
203
|
+
// see {@link tryAddSchema}. The id stays claimed either way, so a later
|
|
204
|
+
// named type cannot quietly take a kind's place.
|
|
205
|
+
this.tryAddSchema(schema, id);
|
|
177
206
|
this.registeredSchemaIds.add(id);
|
|
178
207
|
this.definitionSchemaIds.add(id);
|
|
179
208
|
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Naming rules for every author-written Telo identifier — resource instances,
|
|
3
|
+
* kinds, modules, import aliases, step names, config declarations and CEL
|
|
4
|
+
* bindings. The single reader, so no surface re-derives the vocabulary; the
|
|
5
|
+
* `ref-slot.ts` / `zone-slot.ts` precedent.
|
|
6
|
+
*
|
|
7
|
+
* **The rules exist because Telo has no lexer.** A name is a YAML scalar, so
|
|
8
|
+
* nothing rejects its shape where it is declared, and every consequence
|
|
9
|
+
* surfaces later at a CEL site that references it — or not at all. Probed
|
|
10
|
+
* against the engine the runtime actually uses (`@marcbachmann/cel-js`):
|
|
11
|
+
*
|
|
12
|
+
* resources.my-server.url → EVALUATES, as `resources.my - server.url`
|
|
13
|
+
* resources.in → ParseError: Expected IDENTIFIER, got IN
|
|
14
|
+
* resources.2fa → ParseError
|
|
15
|
+
* resources.for → parses fine
|
|
16
|
+
*
|
|
17
|
+
* The first line is the one that decides the design. When a bare name is in
|
|
18
|
+
* scope — which `x-telo-bindings-from` deliberately makes possible — a
|
|
19
|
+
* hyphenated resource name yields a wrong number with no diagnostic anywhere.
|
|
20
|
+
* That is a swallowed error in the reference grammar, not a style preference.
|
|
21
|
+
* The last line is why the reserved set here is the whole keyword list rather
|
|
22
|
+
* than the subset today's parser happens to reject in field position: which
|
|
23
|
+
* keywords tokenize there is a property of a dependency, and a name that
|
|
24
|
+
* breaks on a parser upgrade was never safe.
|
|
25
|
+
*
|
|
26
|
+
* **Three tiers, because they fail in three different ways.**
|
|
27
|
+
*
|
|
28
|
+
* 1. `INVALID_NAME` (error, every surface) — not a CEL-safe identifier, or a
|
|
29
|
+
* CEL keyword. Below this line the name is unreferenceable or silently
|
|
30
|
+
* mis-referenced. This subsumes the old dot-only rule, which was the
|
|
31
|
+
* strictest special case of it: `!ref` splits on the first dot.
|
|
32
|
+
*
|
|
33
|
+
* 2. `INVALID_TYPE_NAME` (error) — a type-level name not starting uppercase.
|
|
34
|
+
* An error rather than a warning because half the reference grammar already
|
|
35
|
+
* rejects the alternative: `EXTENDS_ALIAS_PATTERN` in the kernel's manifest
|
|
36
|
+
* schema hard-rejects `extends: foo.Bar`, while nothing rejects the
|
|
37
|
+
* `metadata.name: foo` that produced it. A lowercase kind is a kind nobody
|
|
38
|
+
* can extend, so this only moves an existing failure to where it is
|
|
39
|
+
* fixable.
|
|
40
|
+
*
|
|
41
|
+
* 3. `NAME_CASE_CONVENTION` (warning) — a value-level name not starting
|
|
42
|
+
* lowercase. Warn-only, Rust's `non_snake_case` posture: a name is
|
|
43
|
+
* occasionally dictated from outside, and Telo has no `#[allow]`, so a hard
|
|
44
|
+
* error would leave no escape.
|
|
45
|
+
*
|
|
46
|
+
* **The convention: case encodes what the name denotes.** PascalCase names a
|
|
47
|
+
* *type* — something writable in `kind:` / `extends:` / an `x-telo-ref` or type
|
|
48
|
+
* slot. camelCase names a *value* — something holding data at runtime, read
|
|
49
|
+
* through `resources.` / `steps.` / `variables.` in CEL. That is what
|
|
50
|
+
* distinguishes `kind: Console.WriteLine` from `!ref Console.writeLine`, two
|
|
51
|
+
* character-identical grammars otherwise, and the collision is not
|
|
52
|
+
* hypothetical: it is the sanctioned singleton pattern (declare
|
|
53
|
+
* `kind: Self.WriteLine`, export the instance, withhold the kind).
|
|
54
|
+
*
|
|
55
|
+
* **Only the first character is checked.** A full camelCase pattern would
|
|
56
|
+
* relitigate `httpApi` vs `httpAPI` and `OAuthClient` vs `OauthClient` with no
|
|
57
|
+
* benefit — the first character is what carries the type/value signal, and a
|
|
58
|
+
* stricter rule would fight legitimate names containing acronyms or digits
|
|
59
|
+
* while owning a judgement nobody asked this pass to make. An
|
|
60
|
+
* entirely-acronym type name (`SQL`, `AI`) passes unchanged.
|
|
61
|
+
*
|
|
62
|
+
* **No `DiagnosticFix`.** A fix is a whole-value replacement for ONE node,
|
|
63
|
+
* and a rename is only correct when every reference moves with it — offering
|
|
64
|
+
* one here would rewrite `metadata.name` and break every `!ref` and CEL read
|
|
65
|
+
* of it. Renaming belongs to a refactor that owns the reference graph.
|
|
66
|
+
*
|
|
67
|
+
* Browser-safe: pure string predicates, no I/O, no Node built-ins.
|
|
68
|
+
*/
|
|
69
|
+
import { DiagnosticSeverity } from "./types.js";
|
|
70
|
+
/**
|
|
71
|
+
* CEL keywords. A name matching one is unreachable — `true` lexes as a
|
|
72
|
+
* literal, `in` as an operator — so it is reserved everywhere a name becomes a
|
|
73
|
+
* CEL identifier, which is every surface this file governs.
|
|
74
|
+
*/
|
|
75
|
+
export declare const CEL_RESERVED_WORDS: readonly string[];
|
|
76
|
+
/**
|
|
77
|
+
* Which half of the convention a name falls under.
|
|
78
|
+
*
|
|
79
|
+
* `type` — a name writable in a `kind:` / `extends:` / type slot: a module, a
|
|
80
|
+
* kind, an import alias, or a resource whose capability is `Telo.Type` (a
|
|
81
|
+
* named shape has no runtime instance, so its name denotes a type even though
|
|
82
|
+
* it is declared as a resource).
|
|
83
|
+
*
|
|
84
|
+
* `value` — a name read through a CEL scope: a resource instance, a step, a
|
|
85
|
+
* `variables` / `secrets` / `ports` declaration, a CEL binding.
|
|
86
|
+
*/
|
|
87
|
+
export type NameLevel = "type" | "value";
|
|
88
|
+
/** Document kinds whose `metadata.name` is type-level. Everything else
|
|
89
|
+
* declaring a name is a resource instance, whose level is decided by its
|
|
90
|
+
* kind's capability (see {@link NameLevel}). */
|
|
91
|
+
export declare const TYPE_LEVEL_DOC_KINDS: ReadonlySet<string>;
|
|
92
|
+
export interface NameViolation {
|
|
93
|
+
/** Which tier failed. Callers use it to suppress a tier another check
|
|
94
|
+
* already reports better at that surface (the bindings site owns
|
|
95
|
+
* `reserved`, where it can also say what is being shadowed). */
|
|
96
|
+
tier: "grammar" | "reserved" | "case";
|
|
97
|
+
code: "INVALID_NAME" | "INVALID_TYPE_NAME" | "NAME_CASE_CONVENTION";
|
|
98
|
+
severity: DiagnosticSeverity;
|
|
99
|
+
/** Complete sentence(s), subject included — so every surface words the same
|
|
100
|
+
* rule the same way. */
|
|
101
|
+
message: string;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Check one author-written name.
|
|
105
|
+
*
|
|
106
|
+
* `surface` is the noun phrase naming what was declared ("resource name",
|
|
107
|
+
* "step name", "import alias"), used as the message's subject.
|
|
108
|
+
*
|
|
109
|
+
* Returns the first violation only: the tiers are ordered by how badly the
|
|
110
|
+
* name is broken, and telling an author their unparseable name is also
|
|
111
|
+
* miscased buries the part that matters.
|
|
112
|
+
*/
|
|
113
|
+
export declare function checkName(name: string, level: NameLevel, surface: string): NameViolation | undefined;
|
|
114
|
+
//# sourceMappingURL=identifier-name.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identifier-name.d.ts","sourceRoot":"","sources":["../src/identifier-name.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmEG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEhD;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAAS,MAAM,EAsB/C,CAAC;AAQF;;;;;;;;;;GAUG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;AAEzC;;iDAEiD;AACjD,eAAO,MAAM,oBAAoB,EAAE,WAAW,CAAC,MAAM,CAMnD,CAAC;AAEH,MAAM,WAAW,aAAa;IAC5B;;qEAEiE;IACjE,IAAI,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;IACtC,IAAI,EAAE,cAAc,GAAG,mBAAmB,GAAG,sBAAsB,CAAC;IACpE,QAAQ,EAAE,kBAAkB,CAAC;IAC7B;6BACyB;IACzB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,MAAM,GACd,aAAa,GAAG,SAAS,CA6C3B"}
|