@telorun/analyzer 0.71.0 → 0.73.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +92 -15
- package/dist/builtins.d.ts.map +1 -1
- package/dist/builtins.js +71 -97
- package/dist/catch-scope.d.ts +72 -0
- package/dist/catch-scope.d.ts.map +1 -0
- package/dist/catch-scope.js +102 -0
- package/dist/cel-scope-query.d.ts.map +1 -1
- package/dist/cel-scope-query.js +32 -11
- package/dist/cel-scope.d.ts.map +1 -1
- package/dist/cel-scope.js +1 -0
- package/dist/deprecation.d.ts +21 -0
- package/dist/deprecation.d.ts.map +1 -0
- package/dist/deprecation.js +26 -0
- package/dist/eval-paths.d.ts +36 -5
- package/dist/eval-paths.d.ts.map +1 -1
- package/dist/eval-paths.js +47 -6
- package/dist/extends-resolution.d.ts +12 -0
- package/dist/extends-resolution.d.ts.map +1 -1
- package/dist/extends-resolution.js +23 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/manifest-visitor.d.ts +17 -1
- package/dist/manifest-visitor.d.ts.map +1 -1
- package/dist/manifest-visitor.js +5 -1
- package/dist/migrations/report.d.ts +1 -1
- package/dist/migrations/report.d.ts.map +1 -1
- package/dist/migrations/report.js +5 -0
- package/dist/nearest-name.d.ts +22 -0
- package/dist/nearest-name.d.ts.map +1 -0
- package/dist/nearest-name.js +43 -0
- package/dist/ref-slot.d.ts +15 -0
- package/dist/ref-slot.d.ts.map +1 -1
- package/dist/ref-slot.js +7 -0
- package/dist/release/destinations.d.ts +59 -0
- package/dist/release/destinations.d.ts.map +1 -0
- package/dist/release/destinations.js +75 -0
- package/dist/release/index.d.ts +6 -2
- package/dist/release/index.d.ts.map +1 -1
- package/dist/release/index.js +3 -1
- package/dist/release/ledger.d.ts +20 -11
- package/dist/release/ledger.d.ts.map +1 -1
- package/dist/release/ledger.js +43 -14
- package/dist/release/release-plan.d.ts +3 -2
- package/dist/release/release-plan.d.ts.map +1 -1
- package/dist/release/release-plan.js +12 -19
- package/dist/release/workspace-config.d.ts +114 -34
- package/dist/release/workspace-config.d.ts.map +1 -1
- package/dist/release/workspace-config.js +322 -38
- package/dist/release/workspace-schema.d.ts +41 -0
- package/dist/release/workspace-schema.d.ts.map +1 -0
- package/dist/release/workspace-schema.js +77 -0
- package/dist/resolve-throws-union.d.ts +29 -1
- package/dist/resolve-throws-union.d.ts.map +1 -1
- package/dist/resolve-throws-union.js +111 -16
- package/dist/schema-compat.d.ts.map +1 -1
- package/dist/schema-compat.js +13 -1
- package/dist/schema-error-report.d.ts +7 -0
- package/dist/schema-error-report.d.ts.map +1 -1
- package/dist/schema-error-report.js +57 -8
- package/dist/schema-keywords.d.ts.map +1 -1
- package/dist/schema-keywords.js +3 -1
- package/dist/schema-walk.d.ts +27 -0
- package/dist/schema-walk.d.ts.map +1 -1
- package/dist/schema-walk.js +44 -0
- package/dist/telo-version.d.ts +1 -1
- package/dist/telo-version.js +1 -1
- package/dist/template-body.d.ts +10 -0
- package/dist/template-body.d.ts.map +1 -1
- package/dist/template-body.js +25 -0
- package/dist/types.d.ts +17 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +11 -0
- package/dist/validate-cel-context.d.ts +23 -8
- package/dist/validate-cel-context.d.ts.map +1 -1
- package/dist/validate-cel-context.js +48 -16
- package/dist/validate-exports.d.ts +28 -0
- package/dist/validate-exports.d.ts.map +1 -0
- package/dist/validate-exports.js +146 -0
- package/dist/validate-extends.d.ts.map +1 -1
- package/dist/validate-extends.js +37 -1
- package/dist/validate-identifier-names.d.ts +2 -2
- package/dist/validate-identifier-names.d.ts.map +1 -1
- package/dist/validate-identifier-names.js +22 -7
- package/dist/validate-provider-coherence.d.ts +4 -8
- package/dist/validate-provider-coherence.d.ts.map +1 -1
- package/dist/validate-provider-coherence.js +12 -123
- package/dist/validate-ref-slots.d.ts +1 -1
- package/dist/validate-ref-slots.d.ts.map +1 -1
- package/dist/validate-ref-slots.js +34 -0
- package/dist/validate-references.d.ts.map +1 -1
- package/dist/validate-references.js +168 -63
- package/dist/validate-template-body.d.ts +36 -0
- package/dist/validate-template-body.d.ts.map +1 -0
- package/dist/validate-template-body.js +246 -0
- package/dist/validate-throws-coverage.d.ts.map +1 -1
- package/dist/validate-throws-coverage.js +236 -85
- package/package.json +3 -2
- package/src/analyzer.ts +118 -12
- package/src/builtins.ts +85 -97
- package/src/catch-scope.ts +157 -0
- package/src/cel-scope-query.ts +28 -9
- package/src/cel-scope.ts +1 -0
- package/src/deprecation.ts +36 -0
- package/src/eval-paths.ts +53 -6
- package/src/extends-resolution.ts +24 -0
- package/src/index.ts +9 -1
- package/src/manifest-visitor.ts +19 -2
- package/src/migrations/report.ts +5 -1
- package/src/nearest-name.ts +47 -0
- package/src/ref-slot.ts +19 -0
- package/src/release/destinations.ts +105 -0
- package/src/release/index.ts +33 -2
- package/src/release/ledger.ts +51 -21
- package/src/release/release-plan.ts +16 -26
- package/src/release/workspace-config.ts +483 -47
- package/src/release/workspace-schema.ts +99 -0
- package/src/resolve-throws-union.ts +139 -21
- package/src/schema-compat.ts +13 -0
- package/src/schema-error-report.ts +66 -10
- package/src/schema-keywords.ts +4 -1
- package/src/schema-walk.ts +56 -0
- package/src/telo-version.ts +1 -1
- package/src/template-body.ts +25 -0
- package/src/types.ts +18 -0
- package/src/validate-cel-context.ts +57 -16
- package/src/validate-exports.ts +185 -0
- package/src/validate-extends.ts +43 -0
- package/src/validate-identifier-names.ts +28 -9
- package/src/validate-provider-coherence.ts +17 -127
- package/src/validate-ref-slots.ts +41 -1
- package/src/validate-references.ts +174 -63
- package/src/validate-template-body.ts +274 -0
- package/src/validate-throws-coverage.ts +333 -92
- package/dist/validate-template-dispatch.d.ts +0 -27
- package/dist/validate-template-dispatch.d.ts.map +0 -1
- package/dist/validate-template-dispatch.js +0 -95
- package/src/validate-template-dispatch.ts +0 -99
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { isRefSentinel } from "@telorun/templating";
|
|
2
|
-
import { distance } from "./levenshtein.js";
|
|
3
|
-
import { DiagnosticSeverity } from "./types.js";
|
|
4
|
-
const SOURCE = "telo-analyzer";
|
|
5
|
-
/** The four slots a `Telo.Definition` names its dispatch target in. Each takes
|
|
6
|
-
* the same grammar; which one is legal for a given capability is
|
|
7
|
-
* `validate-provider-coherence`'s question, not this one's. */
|
|
8
|
-
const DISPATCH_FIELDS = ["invoke", "run", "provide", "mount"];
|
|
9
|
-
/**
|
|
10
|
-
* A `!ref` at a definition's dispatch slot must name a sibling `resources:`
|
|
11
|
-
* entry.
|
|
12
|
-
*
|
|
13
|
-
* `!ref` is the one spelling an author — and the editor's rename, completion and
|
|
14
|
-
* go-to-definition — expects to be RESOLVED. But a `Telo.Definition` is in both
|
|
15
|
-
* `REF_VALIDATION_SKIP_KINDS` and `REF_RESOLUTION_SKIP_KINDS`, and the dispatch
|
|
16
|
-
* slots carry no `x-telo-ref` (the accepted targets are the definition's own
|
|
17
|
-
* template-internal entries, not resources of any module), so no reference pass
|
|
18
|
-
* reaches them. Introducing the tag at a slot nothing resolves would be worse
|
|
19
|
-
* than the string form it replaces: a typo that used to be an obvious runtime
|
|
20
|
-
* miss becomes a typo in a construct that advertises static resolution.
|
|
21
|
-
*
|
|
22
|
-
* Decidable only when every sibling name is LITERAL. A template routinely names
|
|
23
|
-
* its entries with CEL (`name: !cel "self.name + '-query'"`), and an expression
|
|
24
|
-
* could expand to the referenced name — so one dynamic sibling switches the
|
|
25
|
-
* check off for that definition rather than inventing a miss.
|
|
26
|
-
*
|
|
27
|
-
* Entry-module-scoped, like every other declaration check: a published
|
|
28
|
-
* dependency's template body is not the consumer's to fix.
|
|
29
|
-
*
|
|
30
|
-
* Browser-safe.
|
|
31
|
-
*/
|
|
32
|
-
export function validateTemplateDispatch(manifests, rootModules) {
|
|
33
|
-
const out = [];
|
|
34
|
-
for (const m of manifests) {
|
|
35
|
-
if (m.kind !== "Telo.Definition")
|
|
36
|
-
continue;
|
|
37
|
-
const meta = m.metadata;
|
|
38
|
-
const name = meta?.name;
|
|
39
|
-
if (!name)
|
|
40
|
-
continue;
|
|
41
|
-
if (meta?.module && !rootModules.has(meta.module))
|
|
42
|
-
continue;
|
|
43
|
-
const bodies = m.resources;
|
|
44
|
-
if (!Array.isArray(bodies))
|
|
45
|
-
continue;
|
|
46
|
-
const siblings = [];
|
|
47
|
-
let anyDynamic = false;
|
|
48
|
-
for (const entry of bodies) {
|
|
49
|
-
const entryName = entry?.metadata?.name;
|
|
50
|
-
if (typeof entryName === "string" && !entryName.includes("${{"))
|
|
51
|
-
siblings.push(entryName);
|
|
52
|
-
else if (entryName !== undefined)
|
|
53
|
-
anyDynamic = true;
|
|
54
|
-
}
|
|
55
|
-
if (anyDynamic)
|
|
56
|
-
continue;
|
|
57
|
-
for (const field of DISPATCH_FIELDS) {
|
|
58
|
-
const value = m[field];
|
|
59
|
-
if (!isRefSentinel(value))
|
|
60
|
-
continue;
|
|
61
|
-
const source = value.source;
|
|
62
|
-
const target = source.startsWith("Self.") ? source.slice("Self.".length) : source;
|
|
63
|
-
if (siblings.includes(target))
|
|
64
|
-
continue;
|
|
65
|
-
const suggestion = nearest(target, siblings);
|
|
66
|
-
out.push({
|
|
67
|
-
severity: DiagnosticSeverity.Error,
|
|
68
|
-
code: "TEMPLATE_DISPATCH_UNKNOWN",
|
|
69
|
-
source: SOURCE,
|
|
70
|
-
message: `${m.kind}/${name}: '${field}: !ref ${source}' names no entry in 'resources:'. ` +
|
|
71
|
-
`Available: ${siblings.join(", ") || "(none)"}.` +
|
|
72
|
-
(suggestion ? ` Did you mean '${suggestion}'?` : ""),
|
|
73
|
-
data: {
|
|
74
|
-
resource: { kind: m.kind, name },
|
|
75
|
-
filePath: meta?.source,
|
|
76
|
-
path: field,
|
|
77
|
-
...(suggestion ? { fix: { replacement: suggestion } } : {}),
|
|
78
|
-
},
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return out;
|
|
83
|
-
}
|
|
84
|
-
/** The closest sibling name, when one is close enough to be a typo rather than a
|
|
85
|
-
* different name. */
|
|
86
|
-
function nearest(target, candidates) {
|
|
87
|
-
let best;
|
|
88
|
-
for (const candidate of candidates) {
|
|
89
|
-
const d = distance(target, candidate);
|
|
90
|
-
if (!best || d < best.d)
|
|
91
|
-
best = { name: candidate, d };
|
|
92
|
-
}
|
|
93
|
-
const limit = Math.max(1, Math.floor(target.length / 3));
|
|
94
|
-
return best && best.d <= limit ? best.name : undefined;
|
|
95
|
-
}
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import type { ResourceManifest } from "@telorun/sdk";
|
|
2
|
-
import { isRefSentinel } from "@telorun/templating";
|
|
3
|
-
import { distance } from "./levenshtein.js";
|
|
4
|
-
import { DiagnosticSeverity, type AnalysisDiagnostic } from "./types.js";
|
|
5
|
-
|
|
6
|
-
const SOURCE = "telo-analyzer";
|
|
7
|
-
|
|
8
|
-
/** The four slots a `Telo.Definition` names its dispatch target in. Each takes
|
|
9
|
-
* the same grammar; which one is legal for a given capability is
|
|
10
|
-
* `validate-provider-coherence`'s question, not this one's. */
|
|
11
|
-
const DISPATCH_FIELDS = ["invoke", "run", "provide", "mount"] as const;
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* A `!ref` at a definition's dispatch slot must name a sibling `resources:`
|
|
15
|
-
* entry.
|
|
16
|
-
*
|
|
17
|
-
* `!ref` is the one spelling an author — and the editor's rename, completion and
|
|
18
|
-
* go-to-definition — expects to be RESOLVED. But a `Telo.Definition` is in both
|
|
19
|
-
* `REF_VALIDATION_SKIP_KINDS` and `REF_RESOLUTION_SKIP_KINDS`, and the dispatch
|
|
20
|
-
* slots carry no `x-telo-ref` (the accepted targets are the definition's own
|
|
21
|
-
* template-internal entries, not resources of any module), so no reference pass
|
|
22
|
-
* reaches them. Introducing the tag at a slot nothing resolves would be worse
|
|
23
|
-
* than the string form it replaces: a typo that used to be an obvious runtime
|
|
24
|
-
* miss becomes a typo in a construct that advertises static resolution.
|
|
25
|
-
*
|
|
26
|
-
* Decidable only when every sibling name is LITERAL. A template routinely names
|
|
27
|
-
* its entries with CEL (`name: !cel "self.name + '-query'"`), and an expression
|
|
28
|
-
* could expand to the referenced name — so one dynamic sibling switches the
|
|
29
|
-
* check off for that definition rather than inventing a miss.
|
|
30
|
-
*
|
|
31
|
-
* Entry-module-scoped, like every other declaration check: a published
|
|
32
|
-
* dependency's template body is not the consumer's to fix.
|
|
33
|
-
*
|
|
34
|
-
* Browser-safe.
|
|
35
|
-
*/
|
|
36
|
-
export function validateTemplateDispatch(
|
|
37
|
-
manifests: ResourceManifest[],
|
|
38
|
-
rootModules: ReadonlySet<string>,
|
|
39
|
-
): AnalysisDiagnostic[] {
|
|
40
|
-
const out: AnalysisDiagnostic[] = [];
|
|
41
|
-
|
|
42
|
-
for (const m of manifests) {
|
|
43
|
-
if (m.kind !== "Telo.Definition") continue;
|
|
44
|
-
const meta = m.metadata as { name?: string; module?: string; source?: string } | undefined;
|
|
45
|
-
const name = meta?.name;
|
|
46
|
-
if (!name) continue;
|
|
47
|
-
if (meta?.module && !rootModules.has(meta.module)) continue;
|
|
48
|
-
|
|
49
|
-
const bodies = (m as Record<string, unknown>).resources;
|
|
50
|
-
if (!Array.isArray(bodies)) continue;
|
|
51
|
-
|
|
52
|
-
const siblings: string[] = [];
|
|
53
|
-
let anyDynamic = false;
|
|
54
|
-
for (const entry of bodies) {
|
|
55
|
-
const entryName = (entry as { metadata?: { name?: unknown } } | undefined)?.metadata?.name;
|
|
56
|
-
if (typeof entryName === "string" && !entryName.includes("${{")) siblings.push(entryName);
|
|
57
|
-
else if (entryName !== undefined) anyDynamic = true;
|
|
58
|
-
}
|
|
59
|
-
if (anyDynamic) continue;
|
|
60
|
-
|
|
61
|
-
for (const field of DISPATCH_FIELDS) {
|
|
62
|
-
const value = (m as Record<string, unknown>)[field];
|
|
63
|
-
if (!isRefSentinel(value)) continue;
|
|
64
|
-
const source = value.source;
|
|
65
|
-
const target = source.startsWith("Self.") ? source.slice("Self.".length) : source;
|
|
66
|
-
if (siblings.includes(target)) continue;
|
|
67
|
-
const suggestion = nearest(target, siblings);
|
|
68
|
-
out.push({
|
|
69
|
-
severity: DiagnosticSeverity.Error,
|
|
70
|
-
code: "TEMPLATE_DISPATCH_UNKNOWN",
|
|
71
|
-
source: SOURCE,
|
|
72
|
-
message:
|
|
73
|
-
`${m.kind}/${name}: '${field}: !ref ${source}' names no entry in 'resources:'. ` +
|
|
74
|
-
`Available: ${siblings.join(", ") || "(none)"}.` +
|
|
75
|
-
(suggestion ? ` Did you mean '${suggestion}'?` : ""),
|
|
76
|
-
data: {
|
|
77
|
-
resource: { kind: m.kind, name },
|
|
78
|
-
filePath: meta?.source,
|
|
79
|
-
path: field,
|
|
80
|
-
...(suggestion ? { fix: { replacement: suggestion } } : {}),
|
|
81
|
-
},
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return out;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/** The closest sibling name, when one is close enough to be a typo rather than a
|
|
90
|
-
* different name. */
|
|
91
|
-
function nearest(target: string, candidates: readonly string[]): string | undefined {
|
|
92
|
-
let best: { name: string; d: number } | undefined;
|
|
93
|
-
for (const candidate of candidates) {
|
|
94
|
-
const d = distance(target, candidate);
|
|
95
|
-
if (!best || d < best.d) best = { name: candidate, d };
|
|
96
|
-
}
|
|
97
|
-
const limit = Math.max(1, Math.floor(target.length / 3));
|
|
98
|
-
return best && best.d <= limit ? best.name : undefined;
|
|
99
|
-
}
|