@telorun/analyzer 0.65.0 → 0.67.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 +1 -1
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +194 -65
- package/dist/builtins.d.ts.map +1 -1
- package/dist/builtins.js +67 -16
- package/dist/call-graph.d.ts.map +1 -1
- package/dist/call-graph.js +7 -1
- package/dist/cel-environment.d.ts +12 -0
- package/dist/cel-environment.d.ts.map +1 -1
- package/dist/cel-environment.js +35 -19
- package/dist/cel-scope.d.ts +8 -0
- package/dist/cel-scope.d.ts.map +1 -1
- package/dist/cel-scope.js +89 -11
- package/dist/definition-registry.d.ts +41 -0
- package/dist/definition-registry.d.ts.map +1 -1
- package/dist/definition-registry.js +76 -0
- package/dist/dependency-graph.d.ts.map +1 -1
- package/dist/dependency-graph.js +65 -0
- package/dist/eval-paths.d.ts +68 -0
- package/dist/eval-paths.d.ts.map +1 -1
- package/dist/eval-paths.js +138 -0
- package/dist/flatten-for-analyzer.d.ts +37 -1
- package/dist/flatten-for-analyzer.d.ts.map +1 -1
- package/dist/flatten-for-analyzer.js +104 -5
- package/dist/import-resolution-diagnostics.d.ts +1 -1
- package/dist/import-resolution-diagnostics.js +1 -1
- package/dist/index.d.ts +12 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -6
- package/dist/inline-imports.d.ts.map +1 -1
- package/dist/inline-imports.js +1 -0
- package/dist/manifest-visitor.d.ts +4 -0
- package/dist/manifest-visitor.d.ts.map +1 -1
- package/dist/manifest-visitor.js +36 -1
- package/dist/migrations/entries/index.d.ts.map +1 -1
- package/dist/migrations/entries/index.js +2 -0
- package/dist/migrations/entries/schema-prepare-bucket.json +27 -0
- package/dist/peer-binding.d.ts +232 -0
- package/dist/peer-binding.d.ts.map +1 -0
- package/dist/peer-binding.js +418 -0
- package/dist/precompile.d.ts.map +1 -1
- package/dist/precompile.js +8 -0
- package/dist/ref-slot.d.ts +13 -0
- package/dist/ref-slot.d.ts.map +1 -1
- package/dist/ref-slot.js +26 -0
- package/dist/reference-field-map.d.ts +28 -0
- package/dist/reference-field-map.d.ts.map +1 -1
- package/dist/reference-field-map.js +25 -0
- package/dist/referrer-rule.d.ts +17 -0
- package/dist/referrer-rule.d.ts.map +1 -1
- package/dist/referrer-rule.js +4 -1
- package/dist/release/index.d.ts +1 -1
- package/dist/release/index.js +1 -1
- package/dist/resolve-ref-sentinels.d.ts.map +1 -1
- package/dist/resolve-ref-sentinels.js +14 -1
- package/dist/resource-input.d.ts +75 -0
- package/dist/resource-input.d.ts.map +1 -0
- package/dist/resource-input.js +90 -0
- package/dist/resource-rule.d.ts +40 -27
- package/dist/resource-rule.d.ts.map +1 -1
- package/dist/resource-rule.js +61 -7
- package/dist/rule-condition.d.ts +11 -0
- package/dist/rule-condition.d.ts.map +1 -1
- package/dist/rule-condition.js +13 -0
- package/dist/schema-projection.d.ts +119 -4
- package/dist/schema-projection.d.ts.map +1 -1
- package/dist/schema-projection.js +213 -18
- package/dist/system-kinds.d.ts +7 -2
- package/dist/system-kinds.d.ts.map +1 -1
- package/dist/system-kinds.js +7 -2
- package/dist/telo-version.d.ts +1 -1
- package/dist/telo-version.js +1 -1
- package/dist/template-body.d.ts +50 -0
- package/dist/template-body.d.ts.map +1 -0
- package/dist/template-body.js +58 -0
- package/dist/validate-cel-context.d.ts +1 -17
- package/dist/validate-cel-context.d.ts.map +1 -1
- package/dist/validate-cel-context.js +73 -78
- package/dist/validate-identifier-names.d.ts.map +1 -1
- package/dist/validate-identifier-names.js +17 -2
- package/dist/validate-reference-forms.d.ts +10 -0
- package/dist/validate-reference-forms.d.ts.map +1 -1
- package/dist/validate-reference-forms.js +23 -0
- package/dist/validate-references.d.ts +17 -0
- package/dist/validate-references.d.ts.map +1 -1
- package/dist/validate-references.js +77 -18
- package/dist/validate-referrer-rules.d.ts +38 -4
- package/dist/validate-referrer-rules.d.ts.map +1 -1
- package/dist/validate-referrer-rules.js +139 -31
- package/dist/validate-resource-inputs.d.ts +35 -0
- package/dist/validate-resource-inputs.d.ts.map +1 -0
- package/dist/validate-resource-inputs.js +319 -0
- package/dist/validate-resource-rules.d.ts +11 -2
- package/dist/validate-resource-rules.d.ts.map +1 -1
- package/dist/validate-resource-rules.js +18 -12
- package/dist/validate-schema-projection.d.ts.map +1 -1
- package/dist/validate-schema-projection.js +33 -2
- package/dist/validate-template-dispatch.d.ts +27 -0
- package/dist/validate-template-dispatch.d.ts.map +1 -0
- package/dist/validate-template-dispatch.js +95 -0
- package/dist/with-synthetic-positions.d.ts +1 -1
- package/dist/with-synthetic-positions.js +1 -1
- package/package.json +3 -3
- package/src/analyzer.ts +236 -70
- package/src/builtins.ts +69 -16
- package/src/call-graph.ts +7 -1
- package/src/cel-environment.ts +48 -19
- package/src/cel-scope.ts +113 -19
- package/src/definition-registry.ts +78 -0
- package/src/dependency-graph.ts +66 -0
- package/src/eval-paths.ts +152 -0
- package/src/flatten-for-analyzer.ts +117 -4
- package/src/import-resolution-diagnostics.ts +1 -1
- package/src/index.ts +57 -4
- package/src/inline-imports.ts +1 -0
- package/src/manifest-visitor.ts +41 -1
- package/src/migrations/entries/index.ts +2 -0
- package/src/migrations/entries/schema-prepare-bucket.json +27 -0
- package/src/peer-binding.ts +641 -0
- package/src/precompile.ts +8 -0
- package/src/ref-slot.ts +36 -0
- package/src/reference-field-map.ts +42 -0
- package/src/referrer-rule.ts +20 -1
- package/src/release/index.ts +1 -1
- package/src/resolve-ref-sentinels.ts +12 -1
- package/src/resource-input.ts +132 -0
- package/src/resource-rule.ts +69 -7
- package/src/rule-condition.ts +15 -0
- package/src/schema-projection.ts +302 -20
- package/src/system-kinds.ts +7 -2
- package/src/telo-version.ts +1 -1
- package/src/template-body.ts +104 -0
- package/src/validate-cel-context.ts +73 -78
- package/src/validate-identifier-names.ts +18 -3
- package/src/validate-reference-forms.ts +22 -0
- package/src/validate-references.ts +85 -16
- package/src/validate-referrer-rules.ts +215 -28
- package/src/validate-resource-inputs.ts +367 -0
- package/src/validate-resource-rules.ts +26 -12
- package/src/validate-schema-projection.ts +50 -1
- package/src/validate-template-dispatch.ts +99 -0
- package/src/with-synthetic-positions.ts +1 -1
|
@@ -2,6 +2,12 @@ import type { ResourceManifest } from "@telorun/sdk";
|
|
|
2
2
|
import type { LoadedGraph, LoadedModule } from "./loaded-types.js";
|
|
3
3
|
import type { LoadedFile } from "./loaded-types.js";
|
|
4
4
|
import { isModuleKind } from "./module-kinds.js";
|
|
5
|
+
import {
|
|
6
|
+
injectedDeclarations,
|
|
7
|
+
readLibraryLifecycle,
|
|
8
|
+
readResourceInputs,
|
|
9
|
+
type ResourceInput,
|
|
10
|
+
} from "./resource-input.js";
|
|
5
11
|
import type { ZoneModuleDocuments } from "./zone-module-documents.js";
|
|
6
12
|
|
|
7
13
|
/** One parsed `exports.resources` / `exports.kinds` entry. `name` is the exported
|
|
@@ -23,7 +29,7 @@ export function parseExportEntry(entry: string): ParsedExportEntry {
|
|
|
23
29
|
}
|
|
24
30
|
|
|
25
31
|
/** The import-boundary forwarding rule, shared by `flattenForAnalyzer` (the
|
|
26
|
-
* CLI / kernel loader path) and
|
|
32
|
+
* CLI / kernel loader path) and telo studio's workspace projection so the
|
|
27
33
|
* two cannot drift. Given one module's stamped manifests and whether that
|
|
28
34
|
* module is the analysis entry (root), returns the manifests that cross into
|
|
29
35
|
* the consumer's flat analysis list:
|
|
@@ -414,6 +420,12 @@ function forwardReExports(graph: LoadedGraph, result: ResourceManifest[]): void
|
|
|
414
420
|
// the kernel parses them. A module that declares none is absent, leaving importers ungated
|
|
415
421
|
// (see stampExportedKinds).
|
|
416
422
|
const declaredKinds = new Map<string, readonly string[]>();
|
|
423
|
+
/** Each library's declared `resources:` block, by module name — the inward
|
|
424
|
+
* half, stamped onto its importers below. */
|
|
425
|
+
const requiredResources = new Map<string, readonly ResourceInput[]>();
|
|
426
|
+
/** Libraries declaring `lifecycle: shared` — a singleton every import
|
|
427
|
+
* resolves to, so a per-import override of it is a contradiction. */
|
|
428
|
+
const sharedModules = new Set<string>();
|
|
417
429
|
for (const [source, mod] of graph.modules) {
|
|
418
430
|
if (source === graph.rootSource) continue; // root is an Application — no exports
|
|
419
431
|
const libDoc = mod.owner.manifests.find((m) => m && isModuleKind(m.kind)) as
|
|
@@ -424,6 +436,9 @@ function forwardReExports(graph: LoadedGraph, result: ResourceManifest[]): void
|
|
|
424
436
|
ownerSourceOf.set(moduleName, mod.owner.source);
|
|
425
437
|
specs.push(...reExportSpecsFromExports(moduleName, libDoc.exports?.resources));
|
|
426
438
|
kindModules.push({ module: moduleName, exportsKinds: libDoc.exports?.kinds });
|
|
439
|
+
const inputs = readResourceInputs(libDoc);
|
|
440
|
+
if (inputs.length > 0) requiredResources.set(moduleName, inputs);
|
|
441
|
+
if (readLibraryLifecycle(libDoc) === "shared") sharedModules.add(moduleName);
|
|
427
442
|
if (libDoc.exports?.kinds !== undefined) {
|
|
428
443
|
declaredKinds.set(moduleName, libDoc.exports.kinds.map((e) => parseExportEntry(e).name));
|
|
429
444
|
}
|
|
@@ -440,15 +455,100 @@ function forwardReExports(graph: LoadedGraph, result: ResourceManifest[]): void
|
|
|
440
455
|
// Telo.Import manifests so the analyzer can register the re-export mappings.
|
|
441
456
|
const exportedKinds = resolveExportedKinds(kindModules, aliasToModule);
|
|
442
457
|
const imports: Array<{ manifest: ResourceManifest; targetModule: string }> = [];
|
|
458
|
+
const sources: Array<{ manifest: ResourceManifest; targetSource: string }> = [];
|
|
443
459
|
for (const m of result) {
|
|
444
460
|
if (m.kind !== "Telo.Import") continue;
|
|
445
461
|
const owner = (m.metadata as { source?: string } | undefined)?.source;
|
|
446
462
|
const alias = m.metadata?.name as string | undefined;
|
|
447
|
-
const
|
|
448
|
-
if (
|
|
463
|
+
const edge = owner && alias ? graph.importEdges.get(owner)?.get(alias) : undefined;
|
|
464
|
+
if (edge?.targetModuleName) imports.push({ manifest: m, targetModule: edge.targetModuleName });
|
|
465
|
+
if (edge?.targetSource) sources.push({ manifest: m, targetSource: edge.targetSource });
|
|
449
466
|
}
|
|
467
|
+
stampResolvedSource(sources);
|
|
450
468
|
stampReExportedKinds(imports, exportedKinds);
|
|
451
469
|
stampExportedKinds(imports, declaredKinds);
|
|
470
|
+
stampRequiredResources(imports, requiredResources, aliasToModule);
|
|
471
|
+
stampSharedLifecycle(imports, sharedModules);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/** Stamp `metadata.resolvedSource` — the canonical resolved URL of an import's
|
|
475
|
+
* target — onto every `Telo.Import`. It is the identity the kernel keys a
|
|
476
|
+
* singleton's registry on, so a check that has to decide whether two imports
|
|
477
|
+
* reach the SAME library has to key on it too: `resolvedModuleName` is the
|
|
478
|
+
* module's own name, which two versions of it share. */
|
|
479
|
+
export function stampResolvedSource(
|
|
480
|
+
imports: ReadonlyArray<{ manifest: ResourceManifest; targetSource: string }>,
|
|
481
|
+
): void {
|
|
482
|
+
for (const { manifest, targetSource } of imports) {
|
|
483
|
+
(manifest.metadata as Record<string, unknown>).resolvedSource = targetSource;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/** Stamp `metadata.sharedLibrary` onto every `Telo.Import` whose target declares
|
|
488
|
+
* `lifecycle: shared`, so the consumer's pass can reject the per-import
|
|
489
|
+
* overrides a singleton has no room for. Stamped on `metadata` for the same
|
|
490
|
+
* reason `exportedKinds` is — the `Telo.Import` schema forbids extra top-level
|
|
491
|
+
* fields. */
|
|
492
|
+
export function stampSharedLifecycle(
|
|
493
|
+
imports: ReadonlyArray<{ manifest: ResourceManifest; targetModule: string }>,
|
|
494
|
+
shared: ReadonlySet<string>,
|
|
495
|
+
): void {
|
|
496
|
+
for (const { manifest, targetModule } of imports) {
|
|
497
|
+
if (!shared.has(targetModule)) continue;
|
|
498
|
+
(manifest.metadata as Record<string, unknown>).sharedLibrary = true;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/** Stamp `metadata.requiredResources` — the target library's declared
|
|
503
|
+
* `resources:` block, with each kind constraint CANONICALIZED in the library's
|
|
504
|
+
* own alias scope — onto every `Telo.Import` whose target declares one.
|
|
505
|
+
*
|
|
506
|
+
* Canonicalized here because this is the only point where the target's own
|
|
507
|
+
* import edges are in hand: the consumer's pass sees the flattened list, from
|
|
508
|
+
* which the library doc and its alias scope are both gone, so an entry written
|
|
509
|
+
* `Sql.Connection` would otherwise be read against whatever the CONSUMER
|
|
510
|
+
* happens to alias `Sql` to. Stamped on `metadata` for the same reason
|
|
511
|
+
* `exportedKinds` is — the `Telo.Import` schema forbids extra top-level
|
|
512
|
+
* fields. An entry whose alias resolves to nothing is stamped with its kind
|
|
513
|
+
* unchanged; `validate-resource-inputs.ts` reports that against the library
|
|
514
|
+
* that wrote it. */
|
|
515
|
+
export function stampRequiredResources(
|
|
516
|
+
imports: ReadonlyArray<{ manifest: ResourceManifest; targetModule: string }>,
|
|
517
|
+
declared: ReadonlyMap<string, readonly ResourceInput[]>,
|
|
518
|
+
aliasToModule: (module: string, alias: string) => string | undefined,
|
|
519
|
+
): void {
|
|
520
|
+
for (const { manifest, targetModule } of imports) {
|
|
521
|
+
const inputs = declared.get(targetModule);
|
|
522
|
+
if (!inputs?.length) continue;
|
|
523
|
+
// A plain name → canonical-kind MAP, deliberately not a list of
|
|
524
|
+
// `{name, kind}` objects: that shape is character-identical to a resolved
|
|
525
|
+
// `!ref`, and every reference walk in the analyzer recognises a reference by
|
|
526
|
+
// exactly those two keys — so the stamp would be read as a malformed
|
|
527
|
+
// reference sitting in `metadata`.
|
|
528
|
+
const table: Record<string, string> = {};
|
|
529
|
+
for (const input of inputs) {
|
|
530
|
+
table[input.name] = canonicalizeInputKind(input.kind, targetModule, aliasToModule);
|
|
531
|
+
}
|
|
532
|
+
(manifest.metadata as Record<string, unknown>).requiredResources = table;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/** `Alias.Kind` → `<owning module>.Kind` in the DECLARING library's scope.
|
|
537
|
+
* `Self.` names the library itself and `Telo.` the kernel built-ins, both of
|
|
538
|
+
* which cross no import edge. An unresolvable prefix is returned unchanged. */
|
|
539
|
+
function canonicalizeInputKind(
|
|
540
|
+
kind: string,
|
|
541
|
+
ownModule: string,
|
|
542
|
+
aliasToModule: (module: string, alias: string) => string | undefined,
|
|
543
|
+
): string {
|
|
544
|
+
const dot = kind.indexOf(".");
|
|
545
|
+
if (dot <= 0) return kind;
|
|
546
|
+
const alias = kind.slice(0, dot);
|
|
547
|
+
const suffix = kind.slice(dot + 1);
|
|
548
|
+
if (alias === "Self") return `${ownModule}.${suffix}`;
|
|
549
|
+
if (alias === "Telo") return kind;
|
|
550
|
+
const module = aliasToModule(ownModule, alias);
|
|
551
|
+
return module ? `${module}.${suffix}` : kind;
|
|
452
552
|
}
|
|
453
553
|
|
|
454
554
|
/** Collect every imported library's FULL document set for the zone stage's
|
|
@@ -498,7 +598,20 @@ function collectModuleManifests(mod: LoadedModule): ResourceManifest[] {
|
|
|
498
598
|
for (const p of mod.partials) {
|
|
499
599
|
partials.push(...stampFile(p, ownerModuleName(mod.owner)));
|
|
500
600
|
}
|
|
501
|
-
|
|
601
|
+
const all = [...owner, ...partials];
|
|
602
|
+
// A library's `resources:` block declares the instances it requires from
|
|
603
|
+
// whoever imports it. Standing a kind-only declaration behind each entry is
|
|
604
|
+
// what makes `!ref connection` resolve and `resources.connection.<field>` type
|
|
605
|
+
// in the library's OWN pass — the only pass that sees its internals, since a
|
|
606
|
+
// consumer's flattened analysis drops the library doc. `selectModuleManifests-
|
|
607
|
+
// ForAnalysis` drops them again for a non-root module (they are not exported),
|
|
608
|
+
// and the kernel's import controller filters them out in favour of the
|
|
609
|
+
// borrowed instance itself.
|
|
610
|
+
const moduleDoc = all.find((m) => isModuleKind(m.kind));
|
|
611
|
+
if (moduleDoc) {
|
|
612
|
+
all.push(...injectedDeclarations(moduleDoc, moduleDoc.metadata?.name as string | undefined));
|
|
613
|
+
}
|
|
614
|
+
return all;
|
|
502
615
|
}
|
|
503
616
|
|
|
504
617
|
function ownerModuleName(file: LoadedFile): string | undefined {
|
|
@@ -46,7 +46,7 @@ function messageFor(e: GraphLoadError, code: ReturnType<typeof classify>): strin
|
|
|
46
46
|
/**
|
|
47
47
|
* Convert a graph's import failures (`graph.errors`) into structured, coded
|
|
48
48
|
* diagnostics. This is the single source of truth for surfacing a broken
|
|
49
|
-
* import — every host (CLI, VS Code, telo
|
|
49
|
+
* import — every host (CLI, VS Code, telo studio) routes these instead of each
|
|
50
50
|
* re-deriving the channel and drifting (the VS Code extension used to drop it
|
|
51
51
|
* entirely, showing nothing for a broken import).
|
|
52
52
|
*
|
package/src/index.ts
CHANGED
|
@@ -21,10 +21,31 @@ export {
|
|
|
21
21
|
selectModuleManifestsForAnalysis,
|
|
22
22
|
stampExportedKinds,
|
|
23
23
|
stampReExportedKinds,
|
|
24
|
+
stampRequiredResources,
|
|
25
|
+
stampResolvedSource,
|
|
26
|
+
stampSharedLifecycle,
|
|
24
27
|
type ParsedExportEntry,
|
|
25
28
|
type ReExportSpec,
|
|
26
29
|
} from "./flatten-for-analyzer.js";
|
|
27
|
-
export {
|
|
30
|
+
export {
|
|
31
|
+
buildEvalPaths,
|
|
32
|
+
celEvalModeAt,
|
|
33
|
+
celEvalSites,
|
|
34
|
+
declaresCelRegion,
|
|
35
|
+
evalPathCovers,
|
|
36
|
+
mergeCelEvalSites,
|
|
37
|
+
pathMatchesScope,
|
|
38
|
+
NO_CEL_EVAL_SITES,
|
|
39
|
+
} from "./eval-paths.js";
|
|
40
|
+
export type { CelEvalSites } from "./eval-paths.js";
|
|
41
|
+
export {
|
|
42
|
+
injectedDeclarations,
|
|
43
|
+
isInjectedDeclaration,
|
|
44
|
+
readLibraryLifecycle,
|
|
45
|
+
readResourceInputs,
|
|
46
|
+
readSuppliedResources,
|
|
47
|
+
} from "./resource-input.js";
|
|
48
|
+
export type { LibraryLifecycle, ResourceInput } from "./resource-input.js";
|
|
28
49
|
export {
|
|
29
50
|
BINDINGS_ANNOTATION,
|
|
30
51
|
bindingContextProperties,
|
|
@@ -96,8 +117,17 @@ export type {
|
|
|
96
117
|
ResourceGraphNode,
|
|
97
118
|
StepGraphNode,
|
|
98
119
|
} from "./call-graph.js";
|
|
99
|
-
export {
|
|
100
|
-
|
|
120
|
+
export {
|
|
121
|
+
buildReferenceFieldMap,
|
|
122
|
+
isRefEntry,
|
|
123
|
+
isScopeEntry,
|
|
124
|
+
satisfiesValueBranch,
|
|
125
|
+
} from "./reference-field-map.js";
|
|
126
|
+
export type {
|
|
127
|
+
ReferenceFieldMap,
|
|
128
|
+
RefFieldEntry,
|
|
129
|
+
ValueBranchValidator,
|
|
130
|
+
} from "./reference-field-map.js";
|
|
101
131
|
export {
|
|
102
132
|
hasDeclaredUse,
|
|
103
133
|
isRefSlot,
|
|
@@ -181,6 +211,8 @@ export {
|
|
|
181
211
|
readRawResourceRules,
|
|
182
212
|
resolveRuleSubjects,
|
|
183
213
|
findDynamicLeaf,
|
|
214
|
+
dynamicNode,
|
|
215
|
+
type DynamicLeaf,
|
|
184
216
|
type ResourceRule,
|
|
185
217
|
type ResourceRuleSeverity,
|
|
186
218
|
type RuleSubject,
|
|
@@ -211,11 +243,32 @@ export {
|
|
|
211
243
|
type ReferrerRuleIssue,
|
|
212
244
|
type ReferrerRuleFinding,
|
|
213
245
|
type ReferrerRuleDiagnostic,
|
|
246
|
+
type ReferrerRuleContext,
|
|
247
|
+
type ReferrerRuleDeclarationContext,
|
|
214
248
|
} from "./validate-referrer-rules.js";
|
|
215
|
-
export {
|
|
249
|
+
export {
|
|
250
|
+
PeerBinder,
|
|
251
|
+
analyzerPeerBinder,
|
|
252
|
+
analyzerPeersTarget,
|
|
253
|
+
entryBoundary,
|
|
254
|
+
navigatePath,
|
|
255
|
+
referenceValueOf,
|
|
256
|
+
shapeMatches,
|
|
257
|
+
type DeclarationLookup,
|
|
258
|
+
type PeerAliasScope,
|
|
259
|
+
type PeerBinderEnv,
|
|
260
|
+
type PeerBinderRegistry,
|
|
261
|
+
type PeerBinding,
|
|
262
|
+
type PeerBindingFailure,
|
|
263
|
+
type PeerBindingResult,
|
|
264
|
+
type PeersTarget,
|
|
265
|
+
} from "./peer-binding.js";
|
|
266
|
+
export { RULE_BUDGET_MS, UNTAGGED_CONDITION } from "./rule-condition.js";
|
|
216
267
|
export {
|
|
217
268
|
readSchemaProjection,
|
|
269
|
+
type ProjectionReference,
|
|
218
270
|
readSchemaMap,
|
|
271
|
+
schemaMapBranch,
|
|
219
272
|
readProjectionFrom,
|
|
220
273
|
readProjectionRef,
|
|
221
274
|
manifestListScope,
|
package/src/inline-imports.ts
CHANGED
|
@@ -54,6 +54,7 @@ export function inlineImportManifests(
|
|
|
54
54
|
source,
|
|
55
55
|
...(entry.variables !== undefined ? { variables: entry.variables } : {}),
|
|
56
56
|
...(entry.secrets !== undefined ? { secrets: entry.secrets } : {}),
|
|
57
|
+
...(entry.resources !== undefined ? { resources: entry.resources } : {}),
|
|
57
58
|
...(entry.runtime !== undefined ? { runtime: entry.runtime } : {}),
|
|
58
59
|
...(entry.logging !== undefined ? { logging: entry.logging } : {}),
|
|
59
60
|
} as unknown as ResourceManifest;
|
package/src/manifest-visitor.ts
CHANGED
|
@@ -16,6 +16,8 @@ import {
|
|
|
16
16
|
type RefFieldEntry,
|
|
17
17
|
type SchemaFromFieldEntry,
|
|
18
18
|
} from "./reference-field-map.js";
|
|
19
|
+
import type { ModuleScopes } from "./alias-resolver.js";
|
|
20
|
+
import { templateBodies, withTemplateSelf } from "./template-body.js";
|
|
19
21
|
import { extractContextsFromSchema, pathMatchesScope } from "./validate-cel-context.js";
|
|
20
22
|
|
|
21
23
|
/**
|
|
@@ -150,6 +152,10 @@ export interface VisitOptions {
|
|
|
150
152
|
* Opt-in: the validators / dependency graph must NOT enable it (those refs
|
|
151
153
|
* are runtime-resolved, not boot dependencies). */
|
|
152
154
|
discoverNestedRefs?: boolean;
|
|
155
|
+
/** Root (consumer-owned) module names, paired with `aliasesByModule` so a
|
|
156
|
+
* nested kind inside an imported library's definition resolves through THAT
|
|
157
|
+
* library's aliases. */
|
|
158
|
+
rootModules?: ReadonlySet<string>;
|
|
153
159
|
}
|
|
154
160
|
|
|
155
161
|
/** Synthetic entry for a value-tree-discovered ref — these carry no declared
|
|
@@ -204,6 +210,15 @@ const pathUnderPrefix = (fieldPath: string, prefix: string): boolean =>
|
|
|
204
210
|
fieldPath.startsWith(prefix + ".") ||
|
|
205
211
|
fieldPath.startsWith(prefix + "[");
|
|
206
212
|
|
|
213
|
+
/** The per-declaring-module alias tables, when the caller threaded them. A
|
|
214
|
+
* nested kind inside an imported library's definition is written through THAT
|
|
215
|
+
* library's aliases. */
|
|
216
|
+
function moduleScopes(options: VisitOptions): ModuleScopes | undefined {
|
|
217
|
+
return options.aliasesByModule && options.rootModules
|
|
218
|
+
? { aliasesByModule: options.aliasesByModule, rootModules: options.rootModules }
|
|
219
|
+
: undefined;
|
|
220
|
+
}
|
|
221
|
+
|
|
207
222
|
export function visitManifest(
|
|
208
223
|
resources: ResourceManifest[],
|
|
209
224
|
registry: DefinitionRegistry,
|
|
@@ -359,7 +374,32 @@ export function visitManifest(
|
|
|
359
374
|
}
|
|
360
375
|
|
|
361
376
|
if (wantsCel) {
|
|
362
|
-
|
|
377
|
+
// The INHERITANCE-RESOLVED schema: an `extends` child is authored against
|
|
378
|
+
// merge(parent, own), so a context region the parent declares is in force
|
|
379
|
+
// on the child. Reading the child's own schema typed the region on
|
|
380
|
+
// whichever kind happened to declare it and left every descendant's
|
|
381
|
+
// expressions unchecked — silently, which for a typing rule means the
|
|
382
|
+
// check simply stops existing.
|
|
383
|
+
const authorSchema = registry.effectiveSchemaOf(definition);
|
|
384
|
+
const contexts = authorSchema ? extractContextsFromSchema(authorSchema) : [];
|
|
385
|
+
// A `Telo.Definition`'s `resources:` entries are DECLARATIONS of another
|
|
386
|
+
// kind, so the CEL inside one belongs to THAT kind — its own
|
|
387
|
+
// `x-telo-context` regions, rebased under the entry's path. `self` is
|
|
388
|
+
// merged into each, since the nested kind knows nothing about the
|
|
389
|
+
// configuration its enclosing template was given. Without this a nested
|
|
390
|
+
// body saw one fixed permissive context: `inputs` and `item` undefined
|
|
391
|
+
// wherever the nested kind declares them, `error` offered everywhere.
|
|
392
|
+
for (const body of templateBodies(r, registry, aliases, moduleScopes(options))) {
|
|
393
|
+
const bodySchema = registry.effectiveSchemaOf(body.definition);
|
|
394
|
+
if (!bodySchema) continue;
|
|
395
|
+
for (const ctx of extractContextsFromSchema(bodySchema, body.scopePrefix)) {
|
|
396
|
+
contexts.push({ scope: ctx.scope, schema: withTemplateSelf(ctx.schema) });
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
// Longest scope wins, as `extractContextsFromSchema` already orders its
|
|
400
|
+
// own: a nested kind's region is deeper than the enclosing definition's
|
|
401
|
+
// blanket `$.resources[*]`, so it takes precedence.
|
|
402
|
+
contexts.sort((a, b) => b.scope.length - a.scope.length);
|
|
363
403
|
walkCelExpressions(r, "", (expr, path, engineName, surface) => {
|
|
364
404
|
let contextSchema: Record<string, any> | undefined;
|
|
365
405
|
let matchedScope: string | undefined;
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
// Source: analyzer/migrations/*.json (lexically ordered).
|
|
3
3
|
import e0 from "./normalize-value-types.json" with { type: "json" };
|
|
4
4
|
import e1 from "./ref-slot-scalar-type.json" with { type: "json" };
|
|
5
|
+
import e2 from "./schema-prepare-bucket.json" with { type: "json" };
|
|
5
6
|
|
|
6
7
|
/** Every entry file, in the order the driver applies them. */
|
|
7
8
|
export const MIGRATION_ENTRY_FILES: ReadonlyArray<readonly [file: string, data: unknown]> = [
|
|
8
9
|
["normalize-value-types.json", e0],
|
|
9
10
|
["ref-slot-scalar-type.json", e1],
|
|
11
|
+
["schema-prepare-bucket.json", e2],
|
|
10
12
|
];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "`inKind` names the two backend schema kinds by their canonical `<module>.<Kind>` spelling, which is what a document's `kind:` carries after alias resolution. `under` is the key itself: the bucket is a top-level field of the resource, so the region and the match are the same node \u2014 the tightest containment this vocabulary can state. NAMING A MODULE'S KIND FROM A CORE ENTRY IS A DEBT, not a pattern: it is the one place the analyzer knows a standard-library kind by name. It is contained because `inKind` is a filter \u2014 an entry naming an absent kind matches nothing \u2014 and it MOVES into `modules/postgres` and `modules/sqlite` when the module-migration surface lands. Do not add another; see analyzer/migrations/README.md.",
|
|
3
|
+
"id": "schema-prepare-bucket",
|
|
4
|
+
"code": "SQL_BEFORE_MIGRATIONS_RENAMED",
|
|
5
|
+
"severity": "warning",
|
|
6
|
+
"reason": "`beforeMigrations:` is now `prepare:`. Every documented use of it was data preparation for a narrowing the reconciliation pass is about to attempt \u2014 backfill before NOT NULL, make values fit before a length reduction, convert before a non-widening type change \u2014 and each is what a refusal already tells the author to write. The old name said where it ran relative to the OTHER bucket; the new one says what it is for, which is what those refusals need to name. Nothing re-runs: the ledger stores the migration key alone, so moving an entry between the two maps changes no history.",
|
|
7
|
+
"rules": [
|
|
8
|
+
{
|
|
9
|
+
"match": {
|
|
10
|
+
"key": "beforeMigrations",
|
|
11
|
+
"inKind": [
|
|
12
|
+
"Postgres.Schema",
|
|
13
|
+
"SQLite.Schema"
|
|
14
|
+
],
|
|
15
|
+
"under": [
|
|
16
|
+
"beforeMigrations"
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
"patch": [
|
|
20
|
+
{
|
|
21
|
+
"op": "rename-key",
|
|
22
|
+
"to": "prepare"
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|