@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
package/src/analyzer.ts
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
buildCelEnvironment,
|
|
21
21
|
buildImportInputCelEnvironment,
|
|
22
22
|
buildTypedCelEnvironment,
|
|
23
|
+
isKindDocument,
|
|
23
24
|
type CelHandlers,
|
|
24
25
|
} from "./cel-environment.js";
|
|
25
26
|
import { DefinitionRegistry } from "./definition-registry.js";
|
|
@@ -78,7 +79,7 @@ import {
|
|
|
78
79
|
type ResourceRuleDiagnostic,
|
|
79
80
|
type ResourceRuleIssue,
|
|
80
81
|
} from "./validate-resource-rules.js";
|
|
81
|
-
import { readResourceRules, type ResourceRule } from "./resource-rule.js";
|
|
82
|
+
import { pointerToPath, readResourceRules, type ResourceRule } from "./resource-rule.js";
|
|
82
83
|
import { readReferrerRules, type ReferrerRule } from "./referrer-rule.js";
|
|
83
84
|
import {
|
|
84
85
|
evaluateReferrerRules,
|
|
@@ -87,11 +88,15 @@ import {
|
|
|
87
88
|
reportUnexercisedReferrerRule,
|
|
88
89
|
validateReferrerRuleDeclarations,
|
|
89
90
|
type Referrer,
|
|
91
|
+
type ReferrerRuleContext,
|
|
90
92
|
type ReferrerRuleDiagnostic,
|
|
91
93
|
type ReferrerRuleIssue,
|
|
92
94
|
} from "./validate-referrer-rules.js";
|
|
95
|
+
import { analyzerPeerBinder, analyzerPeersTarget } from "./peer-binding.js";
|
|
93
96
|
import {
|
|
94
97
|
describeProjectionFailure,
|
|
98
|
+
manifestListScope,
|
|
99
|
+
resolveSchemaProjections,
|
|
95
100
|
type ProjectionFailure,
|
|
96
101
|
} from "./schema-projection.js";
|
|
97
102
|
import {
|
|
@@ -118,14 +123,18 @@ import { collectValueSchemaIssues } from "./validate-value-schema.js";
|
|
|
118
123
|
import { DiagnosticSeverity, type AnalysisDiagnostic, type AnalysisOptions } from "./types.js";
|
|
119
124
|
import {
|
|
120
125
|
extractAccessChains,
|
|
121
|
-
extractCelRegionScopes,
|
|
122
126
|
extractContextsFromSchema,
|
|
123
127
|
getManifestItem,
|
|
124
|
-
pathMatchesScope,
|
|
125
128
|
resolveContextAnnotations,
|
|
126
129
|
resolveTypeFieldToSchema,
|
|
127
130
|
} from "./validate-cel-context.js";
|
|
128
|
-
import {
|
|
131
|
+
import {
|
|
132
|
+
celEvalModeAt,
|
|
133
|
+
celEvalSites,
|
|
134
|
+
mergeCelEvalSites,
|
|
135
|
+
NO_CEL_EVAL_SITES,
|
|
136
|
+
type CelEvalSites,
|
|
137
|
+
} from "./eval-paths.js";
|
|
129
138
|
import {
|
|
130
139
|
BINDINGS_ANNOTATION,
|
|
131
140
|
bindingContextProperties,
|
|
@@ -148,8 +157,11 @@ import { validateInvocationContract } from "./validate-invocation-contract.js";
|
|
|
148
157
|
import { collectRefInputIssues, collectStepInputIssues } from "./validate-step-inputs.js";
|
|
149
158
|
import { validateNestedInlineResources } from "./validate-nested-inline.js";
|
|
150
159
|
import { validateProviderCoherence } from "./validate-provider-coherence.js";
|
|
151
|
-
import { validateReferences } from "./validate-references.js";
|
|
160
|
+
import { kindSatisfies, validateReferences } from "./validate-references.js";
|
|
152
161
|
import { validateReferenceForms } from "./validate-reference-forms.js";
|
|
162
|
+
import { isInjectedDeclaration } from "./resource-input.js";
|
|
163
|
+
import { validateResourceInputs } from "./validate-resource-inputs.js";
|
|
164
|
+
import { validateTemplateDispatch } from "./validate-template-dispatch.js";
|
|
153
165
|
import { validateUnusedDeclarations } from "./validate-unused-declarations.js";
|
|
154
166
|
import { validateThrowsCoverage } from "./validate-throws-coverage.js";
|
|
155
167
|
import { readStepSlot } from "./step-slot.js";
|
|
@@ -706,7 +718,7 @@ export class StaticAnalyzer {
|
|
|
706
718
|
* `DUPLICATE_RESOURCE_NAME` reads those fields to tell a pipeline echo
|
|
707
719
|
* apart from a genuine collision, and downstream diagnostic positioning
|
|
708
720
|
* depends on them too. Real callers stamp positions already (the `Loader`,
|
|
709
|
-
* `flattenForAnalyzer`,
|
|
721
|
+
* `flattenForAnalyzer`, telo studio's `emitDocsFor`, the VSCode
|
|
710
722
|
* extension). Programmatic callers — tests, ad-hoc scripts — should pass
|
|
711
723
|
* their inputs through `withSyntheticPositions(...)` before calling
|
|
712
724
|
* `analyze()`. A missing position throws a clear error rather than
|
|
@@ -941,6 +953,11 @@ export class StaticAnalyzer {
|
|
|
941
953
|
const projectionIssues: SchemaProjectionIssue[] = [];
|
|
942
954
|
const resourceRuleIssues: ResourceRuleIssue[] = [];
|
|
943
955
|
const referrerRuleIssues: ReferrerRuleIssue[] = [];
|
|
956
|
+
/** Definition docs of the entry's own modules that may declare rules. Their
|
|
957
|
+
* referrer-rule declarations are checked after every kind is registered,
|
|
958
|
+
* because a `peers:` pointer is checked against the REFERRER kind's schema
|
|
959
|
+
* and that kind may be declared later in the same file. */
|
|
960
|
+
const ownRuleDeclarers: ResourceManifest[] = [];
|
|
944
961
|
// A rule that never had anything to iterate is never proven — the second way
|
|
945
962
|
// coverage varies invisibly, beside the dynamic-leaf skip. Tracked across the
|
|
946
963
|
// whole run and reported once, since "empty on every resource" is not a fact
|
|
@@ -998,9 +1015,10 @@ export class StaticAnalyzer {
|
|
|
998
1015
|
effectiveAuthorSchema(m as any, (k) => defs.resolve(aliases.resolveKind(k) ?? k) ?? defs.resolve(k)),
|
|
999
1016
|
),
|
|
1000
1017
|
);
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1018
|
+
// Deferred to after the registration loop: the `peers:` half is checked
|
|
1019
|
+
// against the REFERRER kind's schema, and a rule may name a kind
|
|
1020
|
+
// declared later in the same file.
|
|
1021
|
+
ownRuleDeclarers.push(m as unknown as ResourceManifest);
|
|
1004
1022
|
for (const rule of readReferrerRules((m as Record<string, unknown>).schema)) {
|
|
1005
1023
|
referrerRuleExercise.set(`${m.metadata?.module}.${m.metadata?.name}#${rule.code}`, {
|
|
1006
1024
|
manifest: m as unknown as ResourceManifest,
|
|
@@ -1056,6 +1074,25 @@ export class StaticAnalyzer {
|
|
|
1056
1074
|
defs.register(normalized);
|
|
1057
1075
|
}
|
|
1058
1076
|
|
|
1077
|
+
/**
|
|
1078
|
+
* What a peer rule's `peers:` pointer names in the kind its `referrer:`
|
|
1079
|
+
* filters to.
|
|
1080
|
+
*
|
|
1081
|
+
* Liskov in BOTH directions, which is what the check has to be: the filter
|
|
1082
|
+
* is usually an abstract (`Sql.Schema`, so one rule serves every backend)
|
|
1083
|
+
* while the collection is declared by the backends that implement it, so a
|
|
1084
|
+
* pointer resolving on any candidate resolves the rule. Reported only when
|
|
1085
|
+
* NO candidate declares it, or when every candidate that does holds plain
|
|
1086
|
+
* data — the two shapes where the rule would see no declaration at all.
|
|
1087
|
+
*/
|
|
1088
|
+
const peersTarget = analyzerPeersTarget(defs);
|
|
1089
|
+
|
|
1090
|
+
if (!options?.skipValidation) {
|
|
1091
|
+
for (const declarer of ownRuleDeclarers) {
|
|
1092
|
+
referrerRuleIssues.push(...validateReferrerRuleDeclarations(declarer, { peersTarget }));
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1059
1096
|
// Reference-form validation — enforce `!ref` as the only reference shape.
|
|
1060
1097
|
// Runs on the RAW manifests, BEFORE inline extraction and sentinel
|
|
1061
1098
|
// resolution, while an author-written `{kind, name}` is still
|
|
@@ -1498,13 +1535,12 @@ export class StaticAnalyzer {
|
|
|
1498
1535
|
return suppressUnreadableModuleDiagnostics(diagnostics, unreadableFiles);
|
|
1499
1536
|
}
|
|
1500
1537
|
|
|
1501
|
-
//
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
}
|
|
1538
|
+
// ONE binder for the whole run, built beside the binding it serves: it caches
|
|
1539
|
+
// each referrer's resolved collection, which is what keeps a rule over an
|
|
1540
|
+
// n-entry collection from re-resolving that collection once per entry.
|
|
1541
|
+
const referrerRuleContext: ReferrerRuleContext = {
|
|
1542
|
+
peerBinder: analyzerPeerBinder(defs, aliases, allManifests as ResourceManifest[]),
|
|
1543
|
+
};
|
|
1508
1544
|
|
|
1509
1545
|
// Fail loud on definition schemas AJV cannot compile. `validateAgainstSchema`
|
|
1510
1546
|
// and `validateWithRefs` swallow compile failures (returning no issues),
|
|
@@ -1594,6 +1630,16 @@ export class StaticAnalyzer {
|
|
|
1594
1630
|
const runReachable = reportsObservedState
|
|
1595
1631
|
? collectRunReachableNames(getCallGraph())
|
|
1596
1632
|
: new Set<string>();
|
|
1633
|
+
// "Nothing starts this" is DECLARATION-derived, and a library does not
|
|
1634
|
+
// declare its injected inputs — whether the application starts the instance
|
|
1635
|
+
// it hands down is answerable only where that instance is declared. Inside
|
|
1636
|
+
// the library the question has no answer, so the name is treated as
|
|
1637
|
+
// reachable rather than reported on a `targets:` list the author cannot
|
|
1638
|
+
// write. The check still runs at the injection site, against the real
|
|
1639
|
+
// declaration.
|
|
1640
|
+
for (const m of allManifests) {
|
|
1641
|
+
if (isInjectedDeclaration(m)) runReachable.add(m.metadata?.name as string);
|
|
1642
|
+
}
|
|
1597
1643
|
|
|
1598
1644
|
// Build typed kernel globals schema so x-telo-context chain validation
|
|
1599
1645
|
// recognises variables, secrets, resources, env automatically
|
|
@@ -1651,6 +1697,54 @@ export class StaticAnalyzer {
|
|
|
1651
1697
|
observedStateContext,
|
|
1652
1698
|
});
|
|
1653
1699
|
|
|
1700
|
+
/**
|
|
1701
|
+
* The schema a resource of this kind is validated against, per DEFINITION.
|
|
1702
|
+
*
|
|
1703
|
+
* Both halves derive a fresh object — `effectiveAuthorSchema` merges along
|
|
1704
|
+
* `extends`, and the closed-schema branch spreads `kind` / `metadata` in —
|
|
1705
|
+
* so asking per resource handed `validateResourceConfig` a schema object it
|
|
1706
|
+
* had never seen. That registry memoizes its compiled AJV validator by
|
|
1707
|
+
* object IDENTITY, precisely because every resource of a kind is checked
|
|
1708
|
+
* against the same one at keystroke time, so a fresh object per resource
|
|
1709
|
+
* recompiled the whole kind schema per resource. Keyed on the definition,
|
|
1710
|
+
* which is stable for the run.
|
|
1711
|
+
*/
|
|
1712
|
+
const authorSchemaCache = new WeakMap<object, Record<string, any>>();
|
|
1713
|
+
const validationSchemaFor = (def: ResourceDefinition): Record<string, any> => {
|
|
1714
|
+
const cached = authorSchemaCache.get(def as unknown as object);
|
|
1715
|
+
if (cached) return cached;
|
|
1716
|
+
const authorSchema = effectiveAuthorSchema(def, (k) =>
|
|
1717
|
+
defs.resolve(aliases.resolveKind(k) ?? k) ?? defs.resolve(k),
|
|
1718
|
+
);
|
|
1719
|
+
// `kind` and `metadata` are implicit on every resource — inject them so
|
|
1720
|
+
// module authors don't have to repeat them under `additionalProperties:
|
|
1721
|
+
// false`.
|
|
1722
|
+
const schema =
|
|
1723
|
+
authorSchema.additionalProperties === false
|
|
1724
|
+
? {
|
|
1725
|
+
...authorSchema,
|
|
1726
|
+
properties: {
|
|
1727
|
+
kind: { type: "string" },
|
|
1728
|
+
metadata: { type: "object" },
|
|
1729
|
+
...authorSchema.properties,
|
|
1730
|
+
},
|
|
1731
|
+
}
|
|
1732
|
+
: authorSchema;
|
|
1733
|
+
authorSchemaCache.set(def as unknown as object, schema);
|
|
1734
|
+
return schema;
|
|
1735
|
+
};
|
|
1736
|
+
|
|
1737
|
+
// One scope for the whole run: it closes over the manifest list and the
|
|
1738
|
+
// registry, neither of which changes per resource, and it is asked once per
|
|
1739
|
+
// schema-valued slot that carries a projection.
|
|
1740
|
+
const resourceProjectionScope = manifestListScope(
|
|
1741
|
+
allManifests as Record<string, any>[],
|
|
1742
|
+
(kind) =>
|
|
1743
|
+
(defs.resolve(kind) ?? defs.resolve(aliases.resolveKind(kind) ?? kind)) as
|
|
1744
|
+
| Record<string, any>
|
|
1745
|
+
| undefined,
|
|
1746
|
+
);
|
|
1747
|
+
|
|
1654
1748
|
// Validate each non-definition, non-system resource
|
|
1655
1749
|
for (const m of allManifests) {
|
|
1656
1750
|
const filePath = (m.metadata as { source?: string } | undefined)?.source;
|
|
@@ -1681,6 +1775,15 @@ export class StaticAnalyzer {
|
|
|
1681
1775
|
continue;
|
|
1682
1776
|
}
|
|
1683
1777
|
|
|
1778
|
+
// A kind-only stand-in for a `resources:` entry is a DECLARATION, not an
|
|
1779
|
+
// instantiation: its kind is routinely an abstract and its configuration
|
|
1780
|
+
// is the importer's to supply, so validating it here would report a
|
|
1781
|
+
// non-instantiable kind and a page of missing required fields against a
|
|
1782
|
+
// block that is correct. Its kind is checked where it was written, by
|
|
1783
|
+
// `validate-resource-inputs`; it participates here only as a resolution
|
|
1784
|
+
// target and as a CEL type.
|
|
1785
|
+
if (isInjectedDeclaration(m)) continue;
|
|
1786
|
+
|
|
1684
1787
|
const resource = { kind: m.kind, name: m.metadata?.name as string };
|
|
1685
1788
|
|
|
1686
1789
|
// Resolve kind through alias if needed; direct lookup takes priority so that
|
|
@@ -1749,39 +1852,59 @@ export class StaticAnalyzer {
|
|
|
1749
1852
|
}
|
|
1750
1853
|
|
|
1751
1854
|
// Validate resource config against the definition's AUTHOR-FACING schema —
|
|
1752
|
-
// inheritance-resolved
|
|
1753
|
-
//
|
|
1754
|
-
//
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
// authors don't have to repeat them when using additionalProperties: false.
|
|
1758
|
-
const authorSchema = effectiveAuthorSchema(definition, (k) =>
|
|
1759
|
-
defs.resolve(aliases.resolveKind(k) ?? k) ?? defs.resolve(k),
|
|
1760
|
-
);
|
|
1761
|
-
if (authorSchema && Object.keys(authorSchema).length > 0) {
|
|
1762
|
-
const schema =
|
|
1763
|
-
authorSchema.additionalProperties === false
|
|
1764
|
-
? {
|
|
1765
|
-
...authorSchema,
|
|
1766
|
-
properties: {
|
|
1767
|
-
kind: { type: "string" },
|
|
1768
|
-
metadata: { type: "object" },
|
|
1769
|
-
...authorSchema.properties,
|
|
1770
|
-
},
|
|
1771
|
-
}
|
|
1772
|
-
: authorSchema;
|
|
1855
|
+
// inheritance-resolved, with `kind` / `metadata` injected. See
|
|
1856
|
+
// `validationSchemaFor`, which is where both derivations and the reason
|
|
1857
|
+
// they are memoized per definition live.
|
|
1858
|
+
const schema = validationSchemaFor(definition);
|
|
1859
|
+
if (Object.keys(schema).length > 0) {
|
|
1773
1860
|
// Phase 1: collect the pure-CEL leaves and the schema of the slot each
|
|
1774
1861
|
// flows into. The expression's own type is resolved later, by the
|
|
1775
1862
|
// engine walk that owns type-checking; this half only knows the target.
|
|
1776
1863
|
for (const slot of collectCelValueSlots(m, schema, "")) {
|
|
1777
1864
|
celReturnSlots.push({ manifest: m, resource, filePath, ...slot });
|
|
1778
1865
|
}
|
|
1866
|
+
// A kind's own schema may point a slot at a PROJECTION — of a resource it
|
|
1867
|
+
// references, or (the empty pointer) of this very declaration, which is
|
|
1868
|
+
// what types a table's seed rows against its own `columns:`. Resolved
|
|
1869
|
+
// PER RESOURCE, because a projection is declaration-derived: the same
|
|
1870
|
+
// kind schema yields a different row shape for every table.
|
|
1871
|
+
//
|
|
1872
|
+
// A failure here is REPORTED, never dropped. An entry that could not be
|
|
1873
|
+
// read vanishes from the projected shape, so the slot typed from it then
|
|
1874
|
+
// rejects a field the author did declare ("'status' is not allowed") with
|
|
1875
|
+
// nothing saying why — the projection's own failure mode, blaming the
|
|
1876
|
+
// wrong line. Entry-module-scoped, like every other schema issue.
|
|
1877
|
+
const projectionFailures: ProjectionFailure[] = [];
|
|
1878
|
+
const projected = resolveSchemaProjections(
|
|
1879
|
+
schema,
|
|
1880
|
+
m as Record<string, any>,
|
|
1881
|
+
resourceProjectionScope,
|
|
1882
|
+
projectionFailures,
|
|
1883
|
+
) as Record<string, any>;
|
|
1884
|
+
if (!ownModule || rootModules.has(ownModule)) {
|
|
1885
|
+
for (const failure of projectionFailures) {
|
|
1886
|
+
// A projection through a library's own resource INPUT is
|
|
1887
|
+
// unanswerable here — the entries belong to the declaration the
|
|
1888
|
+
// importer supplies — so it is not a defect in the block that named
|
|
1889
|
+
// it. The check runs at the injection site instead.
|
|
1890
|
+
if (failure.reason === "injected") continue;
|
|
1891
|
+
diagnostics.push({
|
|
1892
|
+
severity: DiagnosticSeverity.Error,
|
|
1893
|
+
code: "SCHEMA_PROJECTION_FROM_UNRESOLVED",
|
|
1894
|
+
source: SOURCE,
|
|
1895
|
+
message: `${m.kind}/${resource.name}: ${describeProjectionFailure(failure)}`,
|
|
1896
|
+
data: { resource, filePath, path: pointerToPath(failure.pointer) },
|
|
1897
|
+
});
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1779
1900
|
// Phase 2+3: AJV on substituted data — CEL fields replaced with typed
|
|
1780
1901
|
// placeholders. Through the REGISTRY, so a kind whose schema references
|
|
1781
1902
|
// a shape declared elsewhere is checked on the instance that holds it.
|
|
1782
1903
|
const ajvIssues = defs.validateResourceConfig(
|
|
1783
|
-
substituteCelFields(m,
|
|
1784
|
-
|
|
1904
|
+
substituteCelFields(m, projected, undefined, {
|
|
1905
|
+
external: (ref) => defs.schemaForId(ref),
|
|
1906
|
+
}),
|
|
1907
|
+
projected,
|
|
1785
1908
|
);
|
|
1786
1909
|
// Phase 4: value slots that must satisfy a type declared elsewhere on
|
|
1787
1910
|
// the resource (`x-telo-value-schema-from`) — e.g. every row of a
|
|
@@ -1816,12 +1939,12 @@ export class StaticAnalyzer {
|
|
|
1816
1939
|
for (const report of reportResourceRules(
|
|
1817
1940
|
m as unknown as ResourceManifest,
|
|
1818
1941
|
definition as unknown as ResourceManifest,
|
|
1819
|
-
evaluateResourceRules(m as unknown as ResourceManifest,
|
|
1942
|
+
evaluateResourceRules(m as unknown as ResourceManifest, schema),
|
|
1820
1943
|
!ruleDeclarer || rootModules.has(ruleDeclarer),
|
|
1821
1944
|
)) {
|
|
1822
1945
|
diagnostics.push(resourceRuleDiagnostic(report));
|
|
1823
1946
|
}
|
|
1824
|
-
for (const rule of readResourceRules(
|
|
1947
|
+
for (const rule of readResourceRules(schema)) {
|
|
1825
1948
|
const key = `${definition.metadata?.module}.${definition.metadata?.name}#${rule.code}`;
|
|
1826
1949
|
const tracked = ruleExercise.get(key);
|
|
1827
1950
|
if (!tracked) continue;
|
|
@@ -1835,7 +1958,7 @@ export class StaticAnalyzer {
|
|
|
1835
1958
|
// literal appears on the referring side, where the spelling would be the
|
|
1836
1959
|
// consumer's import alias rather than anything the rule's author controls.
|
|
1837
1960
|
// A consumer of the shared call graph, never a second traversal.
|
|
1838
|
-
const referrerRules = readReferrerRules(
|
|
1961
|
+
const referrerRules = readReferrerRules(schema);
|
|
1839
1962
|
if (referrerRules.length > 0) {
|
|
1840
1963
|
const referrers = referrersOf(m as unknown as ResourceManifest, getCallGraph());
|
|
1841
1964
|
for (const report of reportReferrerRules(
|
|
@@ -1843,9 +1966,10 @@ export class StaticAnalyzer {
|
|
|
1843
1966
|
definition as unknown as ResourceManifest,
|
|
1844
1967
|
evaluateReferrerRules(
|
|
1845
1968
|
m as unknown as ResourceManifest,
|
|
1846
|
-
|
|
1969
|
+
schema,
|
|
1847
1970
|
referrers,
|
|
1848
1971
|
kindMatches,
|
|
1972
|
+
referrerRuleContext,
|
|
1849
1973
|
),
|
|
1850
1974
|
!ruleDeclarer || rootModules.has(ruleDeclarer),
|
|
1851
1975
|
)) {
|
|
@@ -1857,13 +1981,25 @@ export class StaticAnalyzer {
|
|
|
1857
1981
|
continue;
|
|
1858
1982
|
}
|
|
1859
1983
|
diagnostics.push(referrerRuleDiagnostic(report));
|
|
1984
|
+
// A rule that VIOLATED plainly ran, whatever its peer set held. The
|
|
1985
|
+
// unexercised report exists to catch silence — a `peers:` naming
|
|
1986
|
+
// nothing makes every `!peers.exists(…)` pass vacuously — so a finding
|
|
1987
|
+
// is exactly the evidence it asks for.
|
|
1988
|
+
if (report.code === "REFERRER_RULE_VIOLATED") {
|
|
1989
|
+
const violated = referrerRuleExercise.get(
|
|
1990
|
+
`${definition.metadata?.module}.${definition.metadata?.name}#${report.rule}`,
|
|
1991
|
+
);
|
|
1992
|
+
if (violated) violated.exercised = true;
|
|
1993
|
+
}
|
|
1860
1994
|
}
|
|
1861
1995
|
for (const rule of referrerRules) {
|
|
1862
1996
|
const key = `${definition.metadata?.module}.${definition.metadata?.name}#${rule.code}`;
|
|
1863
1997
|
const tracked = referrerRuleExercise.get(key);
|
|
1864
1998
|
if (!tracked) continue;
|
|
1865
1999
|
tracked.seen = true;
|
|
1866
|
-
if (referrerRuleExercised(rule, referrers, kindMatches))
|
|
2000
|
+
if (referrerRuleExercised(rule, referrers, kindMatches, referrerRuleContext)) {
|
|
2001
|
+
tracked.exercised = true;
|
|
2002
|
+
}
|
|
1867
2003
|
}
|
|
1868
2004
|
}
|
|
1869
2005
|
|
|
@@ -2065,18 +2201,15 @@ export class StaticAnalyzer {
|
|
|
2065
2201
|
// same schema an expression is typed against.
|
|
2066
2202
|
let celStepContextSchema: Record<string, any> | undefined;
|
|
2067
2203
|
let celErrorScopes: ReadonlyMap<string, Record<string, any>> = new Map();
|
|
2068
|
-
//
|
|
2069
|
-
//
|
|
2070
|
-
//
|
|
2071
|
-
//
|
|
2072
|
-
|
|
2204
|
+
// Where this kind says its values are evaluated — `x-telo-eval` paths (own +
|
|
2205
|
+
// capability) and the regions covering their contents. A `!cel` outside every
|
|
2206
|
+
// one of them is read as a literal, and one under a compile path resolves at
|
|
2207
|
+
// startup, where observed state cannot exist yet. Both questions are
|
|
2208
|
+
// `celEvalModeAt`, which the editor asks of the same sites.
|
|
2209
|
+
let celSites: CelEvalSites = NO_CEL_EVAL_SITES;
|
|
2073
2210
|
// The bindings field this kind declares (if any), read by the CEL sites that
|
|
2074
2211
|
// see the names it introduces.
|
|
2075
2212
|
let celBindingSites: BindingSites | undefined;
|
|
2076
|
-
// The compile half alone: a field that resolves at startup, where observed
|
|
2077
|
-
// state cannot exist yet.
|
|
2078
|
-
let celCompilePaths: string[] = [];
|
|
2079
|
-
let celRegionScopes: string[] = [];
|
|
2080
2213
|
let celRuleApplies = false;
|
|
2081
2214
|
|
|
2082
2215
|
visitManifest(
|
|
@@ -2231,22 +2364,28 @@ export class StaticAnalyzer {
|
|
|
2231
2364
|
celRuleApplies =
|
|
2232
2365
|
!!e.definition?.schema && capability !== undefined && capability !== "Telo.Template";
|
|
2233
2366
|
if (celRuleApplies) {
|
|
2234
|
-
|
|
2235
|
-
|
|
2367
|
+
// The INHERITANCE-RESOLVED schema, not the kind's own: without
|
|
2368
|
+
// `base:`, an `extends` child is authored against merge(parent, own),
|
|
2369
|
+
// so a CEL-bearing field the parent declares is a legal field on the
|
|
2370
|
+
// child and the kernel expands it — it stamps the merged schema at
|
|
2371
|
+
// definition registration and builds eval paths from that. Reading
|
|
2372
|
+
// the own schema here reported `CEL_IN_NON_EVAL_FIELD` for an
|
|
2373
|
+
// expression the runtime evaluates correctly, which is the two halves
|
|
2374
|
+
// disagreeing about what the manifest means.
|
|
2375
|
+
const ownSchema = effectiveAuthorSchema(
|
|
2376
|
+
e.definition as unknown as ResourceDefinition,
|
|
2377
|
+
(k) => defs.resolve(aliases.resolveKind(k) ?? k) ?? defs.resolve(k),
|
|
2378
|
+
) as Record<string, any>;
|
|
2236
2379
|
const capabilityDef = capability ? defs.resolve(capability) : undefined;
|
|
2237
|
-
const parent = capabilityDef?.schema
|
|
2238
|
-
? buildEvalPaths(capabilityDef.schema as Record<string, any>)
|
|
2239
|
-
: { compile: [], runtime: [] };
|
|
2240
|
-
celEvalPaths = [...own.compile, ...own.runtime, ...parent.compile, ...parent.runtime];
|
|
2241
2380
|
// A `Telo.Provider`'s fields are implicitly compile-eval — the
|
|
2242
2381
|
// capability abstract carries the root annotation — so its reads are
|
|
2243
2382
|
// covered here without the provider restating anything.
|
|
2244
|
-
|
|
2245
|
-
|
|
2383
|
+
celSites = mergeCelEvalSites(
|
|
2384
|
+
celEvalSites(ownSchema),
|
|
2385
|
+
celEvalSites(capabilityDef?.schema as Record<string, any> | undefined),
|
|
2386
|
+
);
|
|
2246
2387
|
} else {
|
|
2247
|
-
|
|
2248
|
-
celCompilePaths = [];
|
|
2249
|
-
celRegionScopes = [];
|
|
2388
|
+
celSites = NO_CEL_EVAL_SITES;
|
|
2250
2389
|
}
|
|
2251
2390
|
},
|
|
2252
2391
|
onCel: (e) => {
|
|
@@ -2264,8 +2403,7 @@ export class StaticAnalyzer {
|
|
|
2264
2403
|
celRuleApplies &&
|
|
2265
2404
|
engineName === "cel" &&
|
|
2266
2405
|
celScope.invocationContextSchema === undefined &&
|
|
2267
|
-
|
|
2268
|
-
!celRegionScopes.some((scope) => pathMatchesScope(path, scope)) &&
|
|
2406
|
+
celEvalModeAt(celSites, path) === null &&
|
|
2269
2407
|
!pathCrossesNestedResource(m, path)
|
|
2270
2408
|
) {
|
|
2271
2409
|
diagnostics.push({
|
|
@@ -2293,7 +2431,7 @@ export class StaticAnalyzer {
|
|
|
2293
2431
|
read.alias ? `${read.alias}.${read.name}` : read.name,
|
|
2294
2432
|
);
|
|
2295
2433
|
|
|
2296
|
-
if (celRuleApplies &&
|
|
2434
|
+
if (celRuleApplies && celEvalModeAt(celSites, path) === "compile") {
|
|
2297
2435
|
diagnostics.push({
|
|
2298
2436
|
severity: DiagnosticSeverity.Error,
|
|
2299
2437
|
code: "OBSERVED_STATE_IN_STARTUP_FIELD",
|
|
@@ -2340,7 +2478,19 @@ export class StaticAnalyzer {
|
|
|
2340
2478
|
matchedScope,
|
|
2341
2479
|
});
|
|
2342
2480
|
|
|
2343
|
-
const result = engine.analyze(expr, {
|
|
2481
|
+
const result = engine.analyze(expr, {
|
|
2482
|
+
celEnv: typedEnv,
|
|
2483
|
+
contextSchema: effectiveContext,
|
|
2484
|
+
// `scopeFor` registers every kernel global and every name the site's
|
|
2485
|
+
// context declares, so a root this environment does not know is one
|
|
2486
|
+
// nothing puts in scope. Two places where the CEL belongs to another
|
|
2487
|
+
// scope, both already recognised by the non-eval-field check: a kind
|
|
2488
|
+
// document, whose CEL is written for whoever instantiates the kind,
|
|
2489
|
+
// and anything below a nested inline `{ kind }`, whose CEL the
|
|
2490
|
+
// nested kind evaluates — and which is analyzed again, in its own
|
|
2491
|
+
// scope, as the resource it was extracted into.
|
|
2492
|
+
rootsDeclared: !isKindDocument(m) && !pathCrossesNestedResource(m, path),
|
|
2493
|
+
});
|
|
2344
2494
|
|
|
2345
2495
|
if (result.type !== undefined) {
|
|
2346
2496
|
let byPath = celTypeByPath.get(m);
|
|
@@ -2377,7 +2527,7 @@ export class StaticAnalyzer {
|
|
|
2377
2527
|
// intent (a boot timestamp, a run id), so it warns rather than
|
|
2378
2528
|
// blocking. The engine reports which calls re-evaluate; the eval mode
|
|
2379
2529
|
// is manifest policy and stays here.
|
|
2380
|
-
if (celRuleApplies &&
|
|
2530
|
+
if (celRuleApplies && celEvalModeAt(celSites, path) === "compile") {
|
|
2381
2531
|
const volatile = [
|
|
2382
2532
|
...new Set(result.calls.filter((c) => c.deterministic === false).map((c) => c.name)),
|
|
2383
2533
|
].sort();
|
|
@@ -2433,7 +2583,7 @@ export class StaticAnalyzer {
|
|
|
2433
2583
|
}
|
|
2434
2584
|
},
|
|
2435
2585
|
},
|
|
2436
|
-
{ aliases },
|
|
2586
|
+
{ aliases, aliasesByModule, rootModules },
|
|
2437
2587
|
);
|
|
2438
2588
|
|
|
2439
2589
|
// The two halves of "does this expression fit the slot it flows into" meet
|
|
@@ -2522,6 +2672,22 @@ export class StaticAnalyzer {
|
|
|
2522
2672
|
// Warn about declared variables / secrets / ports that no CEL references.
|
|
2523
2673
|
diagnostics.push(...validateUnusedDeclarations(allManifests, this.celEnv));
|
|
2524
2674
|
|
|
2675
|
+
// A `!ref` at a definition's dispatch slot must name a sibling `resources:`
|
|
2676
|
+
// entry — the slot no reference pass reaches, so the tag would otherwise
|
|
2677
|
+
// advertise a resolution nothing performs.
|
|
2678
|
+
diagnostics.push(...validateTemplateDispatch(allManifests, rootModules));
|
|
2679
|
+
|
|
2680
|
+
// A library's declared resource inputs, and every import that supplies them.
|
|
2681
|
+
diagnostics.push(
|
|
2682
|
+
...validateResourceInputs(
|
|
2683
|
+
allManifests,
|
|
2684
|
+
defs,
|
|
2685
|
+
aliases,
|
|
2686
|
+
rootModules,
|
|
2687
|
+
(supplied, required) => kindSatisfies(supplied, required, defs),
|
|
2688
|
+
),
|
|
2689
|
+
);
|
|
2690
|
+
|
|
2525
2691
|
// Reroute diagnostics on synthetic (inline-extracted) resources back to
|
|
2526
2692
|
// the chain root so position-index lookups land on the parent doc.
|
|
2527
2693
|
return rewriteSyntheticOrigins(
|
package/src/builtins.ts
CHANGED
|
@@ -232,6 +232,35 @@ const ROOT_LOGGING_SCHEMA = {
|
|
|
232
232
|
additionalProperties: false,
|
|
233
233
|
};
|
|
234
234
|
|
|
235
|
+
/** A `Telo.Library`'s declared resource inputs — the instances it requires from
|
|
236
|
+
* whoever imports it, the inward half of the symmetry `exports.resources`
|
|
237
|
+
* already had outward. Each entry is constrained by KIND ONLY, through the same
|
|
238
|
+
* alias-qualified grammar `extends:` and `x-telo-ref` use; there is no `use:`,
|
|
239
|
+
* because the boundary is a dependency edge for init order whatever the library
|
|
240
|
+
* does with the instance. See `analyzer/nodejs/src/resource-input.ts`. */
|
|
241
|
+
const LIBRARY_RESOURCE_INPUTS_SCHEMA = {
|
|
242
|
+
type: "object",
|
|
243
|
+
additionalProperties: {
|
|
244
|
+
type: "object",
|
|
245
|
+
required: ["kind"],
|
|
246
|
+
properties: {
|
|
247
|
+
kind: { type: "string" },
|
|
248
|
+
description: { type: "string" },
|
|
249
|
+
},
|
|
250
|
+
additionalProperties: false,
|
|
251
|
+
},
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
/** The importer's side of the same block: entry name → `!ref` to the instance
|
|
255
|
+
* supplied for it. Left open because the accepted KIND is declared by the
|
|
256
|
+
* target library, not by this schema — the constraint is checked by
|
|
257
|
+
* `validate-resource-inputs.ts`, which reads the target's declared block off
|
|
258
|
+
* the `metadata.requiredResources` stamp. */
|
|
259
|
+
const IMPORT_RESOURCE_INPUTS_SCHEMA = {
|
|
260
|
+
type: "object",
|
|
261
|
+
additionalProperties: {},
|
|
262
|
+
};
|
|
263
|
+
|
|
235
264
|
export const KERNEL_BUILTINS: ResourceDefinition[] = [
|
|
236
265
|
{ kind: "Telo.Abstract", metadata: { name: "Template", module: "Telo" } },
|
|
237
266
|
// "Control can be transferred to this" — the parent of Invocable and Runnable,
|
|
@@ -427,28 +456,26 @@ export const KERNEL_BUILTINS: ResourceDefinition[] = [
|
|
|
427
456
|
items: {
|
|
428
457
|
type: "object",
|
|
429
458
|
additionalProperties: true,
|
|
430
|
-
//
|
|
431
|
-
//
|
|
432
|
-
//
|
|
433
|
-
//
|
|
434
|
-
//
|
|
459
|
+
// A `resources:` entry is a DECLARATION of another kind, so the
|
|
460
|
+
// CEL inside it belongs to THAT kind: its `x-telo-context` regions
|
|
461
|
+
// are rebased under this entry's path and take precedence (they are
|
|
462
|
+
// deeper), which is what puts `inputs`, `item`, `request`, `steps`
|
|
463
|
+
// and a `catch:`'s `error` in scope exactly where the nested kind
|
|
464
|
+
// declares them — see `analyzer/nodejs/src/template-body.ts`.
|
|
435
465
|
//
|
|
436
|
-
//
|
|
437
|
-
//
|
|
438
|
-
//
|
|
439
|
-
//
|
|
440
|
-
//
|
|
441
|
-
//
|
|
442
|
-
//
|
|
466
|
+
// What stays here is `self` alone, in force throughout the entry:
|
|
467
|
+
// it is how a body reaches the configuration its enclosing template
|
|
468
|
+
// was given, and no nested kind knows about it. The four names that
|
|
469
|
+
// used to sit beside it (`request` / `result` / `steps` / `error`)
|
|
470
|
+
// were a fixed permissive stand-in for the nested kind's own
|
|
471
|
+
// regions — which is why `error` was offered outside every `catch:`
|
|
472
|
+
// while `inputs` and `item` were undefined wherever a body actually
|
|
473
|
+
// reads them.
|
|
443
474
|
"x-telo-context": {
|
|
444
475
|
type: "object",
|
|
445
476
|
additionalProperties: false,
|
|
446
477
|
properties: {
|
|
447
478
|
self: { "x-telo-context-from-root": "schema" },
|
|
448
|
-
request: {},
|
|
449
|
-
result: {},
|
|
450
|
-
steps: {},
|
|
451
|
-
error: {},
|
|
452
479
|
},
|
|
453
480
|
},
|
|
454
481
|
},
|
|
@@ -611,6 +638,7 @@ export const KERNEL_BUILTINS: ResourceDefinition[] = [
|
|
|
611
638
|
integrity: { type: "string" },
|
|
612
639
|
variables: { type: "object" },
|
|
613
640
|
secrets: { type: "object" },
|
|
641
|
+
resources: IMPORT_RESOURCE_INPUTS_SCHEMA,
|
|
614
642
|
runtime: {
|
|
615
643
|
oneOf: [
|
|
616
644
|
{ type: "string" },
|
|
@@ -757,6 +785,7 @@ export const KERNEL_BUILTINS: ResourceDefinition[] = [
|
|
|
757
785
|
integrity: { type: "string" },
|
|
758
786
|
variables: { type: "object" },
|
|
759
787
|
secrets: { type: "object" },
|
|
788
|
+
resources: IMPORT_RESOURCE_INPUTS_SCHEMA,
|
|
760
789
|
runtime: {
|
|
761
790
|
oneOf: [
|
|
762
791
|
{ type: "string" },
|
|
@@ -872,6 +901,29 @@ export const KERNEL_BUILTINS: ResourceDefinition[] = [
|
|
|
872
901
|
},
|
|
873
902
|
variables: { type: "object" },
|
|
874
903
|
secrets: { type: "object" },
|
|
904
|
+
// How many times this library is instantiated in one application.
|
|
905
|
+
//
|
|
906
|
+
// `isolated` (the default) is what every published module was written
|
|
907
|
+
// against: each import declaration builds its own child scope with its
|
|
908
|
+
// own instances, so two libraries importing a third get two of
|
|
909
|
+
// everything in it. `shared` makes the library a SINGLETON — every
|
|
910
|
+
// import of it resolves to one instantiation, owned by the root and
|
|
911
|
+
// torn down after everything that borrowed it.
|
|
912
|
+
//
|
|
913
|
+
// Default `isolated` rather than `shared` — the opposite of the
|
|
914
|
+
// Application field's — because flipping it would silently collapse
|
|
915
|
+
// every existing app's resource graph and turn per-import `variables:`
|
|
916
|
+
// into a conflict. The `exports.kinds` precedent: private-by-default is
|
|
917
|
+
// the better end state and still needs the ecosystem republished first.
|
|
918
|
+
lifecycle: {
|
|
919
|
+
type: "string",
|
|
920
|
+
enum: ["shared", "isolated"],
|
|
921
|
+
default: "isolated",
|
|
922
|
+
},
|
|
923
|
+
// The inward half of `exports.resources`: instances this library
|
|
924
|
+
// requires from whoever imports it. Library-only — an Application is a
|
|
925
|
+
// root with no importer, so it owns its instances outright.
|
|
926
|
+
resources: LIBRARY_RESOURCE_INPUTS_SCHEMA,
|
|
875
927
|
include: {
|
|
876
928
|
type: "array",
|
|
877
929
|
items: { type: "string" },
|
|
@@ -902,6 +954,7 @@ export const KERNEL_BUILTINS: ResourceDefinition[] = [
|
|
|
902
954
|
integrity: { type: "string" },
|
|
903
955
|
variables: { type: "object" },
|
|
904
956
|
secrets: { type: "object" },
|
|
957
|
+
resources: IMPORT_RESOURCE_INPUTS_SCHEMA,
|
|
905
958
|
runtime: {
|
|
906
959
|
oneOf: [
|
|
907
960
|
{ type: "string" },
|