@intentius/chant 0.20.0 → 0.21.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/cli/commands/check-lexicon-intrinsics.d.ts +17 -0
- package/dist/cli/commands/check-lexicon-intrinsics.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
- package/dist/codegen/docs-types.d.ts +2 -0
- package/dist/codegen/docs-types.d.ts.map +1 -1
- package/dist/declarable.d.ts +16 -0
- package/dist/declarable.d.ts.map +1 -1
- package/dist/discovery/entity-wire-codec.d.ts.map +1 -1
- package/dist/discovery/fold-import.d.ts +30 -1
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/index.d.ts.map +1 -1
- package/dist/fold/fold.d.ts +89 -16
- package/dist/fold/fold.d.ts.map +1 -1
- package/dist/fold/foldable-helpers.d.ts +121 -0
- package/dist/fold/foldable-helpers.d.ts.map +1 -0
- package/dist/fold/subset.d.ts +35 -3
- package/dist/fold/subset.d.ts.map +1 -1
- package/dist/lexicon-schema.d.ts +2 -0
- package/dist/lexicon-schema.d.ts.map +1 -1
- package/dist/lexicon.d.ts +73 -23
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/runtime.d.ts +10 -1
- package/dist/runtime.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/cli/commands/check-lexicon-intrinsics.test.ts +35 -1
- package/src/cli/commands/check-lexicon-intrinsics.ts +38 -2
- package/src/cli/commands/check-lexicon.ts +18 -0
- package/src/codegen/docs-sections.test.ts +7 -1
- package/src/codegen/docs-sections.ts +1 -1
- package/src/codegen/docs-types.ts +2 -0
- package/src/declarable.ts +20 -0
- package/src/discovery/entity-wire-codec.ts +9 -7
- package/src/discovery/fold-import.test.ts +572 -0
- package/src/discovery/fold-import.ts +229 -36
- package/src/discovery/index.ts +9 -0
- package/src/fold/fold.test.ts +277 -0
- package/src/fold/fold.ts +213 -56
- package/src/fold/foldable-helpers.ts +171 -0
- package/src/fold/subset-doc-parity.test.ts +27 -0
- package/src/fold/subset.test.ts +111 -0
- package/src/fold/subset.ts +109 -28
- package/src/lexicon-schema.test.ts +43 -0
- package/src/lexicon-schema.ts +5 -0
- package/src/lexicon.ts +74 -24
- package/src/runtime.ts +11 -2
package/dist/lexicon.d.ts
CHANGED
|
@@ -142,36 +142,86 @@ export interface IntrinsicDef {
|
|
|
142
142
|
* `../cli/commands/check-lexicon-intrinsics.ts`.
|
|
143
143
|
*/
|
|
144
144
|
readonly isTag: boolean;
|
|
145
|
+
/**
|
|
146
|
+
* chant #1044 — opt this intrinsic's PLAIN-CALL form into folding
|
|
147
|
+
* (`Ref(bucket)`, `Concat(a, b)` reduce to their intrinsic node instead of
|
|
148
|
+
* falling the whole file back to the run path).
|
|
149
|
+
*
|
|
150
|
+
* Optional, and OFF unless a lexicon writes `true`. That default is the
|
|
151
|
+
* point: `fold()` has no general `CallExpression` case by construction
|
|
152
|
+
* (epic #1019), and this field is the only thing that admits one. It is a
|
|
153
|
+
* closed, lexicon-declared allowlist, decided one intrinsic at a time —
|
|
154
|
+
* never inferred from `isTag`, from the name, or from the call's shape. An
|
|
155
|
+
* intrinsic with no `foldsAsCall` behaves exactly as it did before #1044.
|
|
156
|
+
*
|
|
157
|
+
* Only set it when calling the intrinsic is a pure function of its
|
|
158
|
+
* arguments that builds a deterministic data envelope — the whole
|
|
159
|
+
* correctness argument is that invoking it while folding is
|
|
160
|
+
* indistinguishable from invoking it during a real run of the file. An
|
|
161
|
+
* intrinsic that reads the environment, mutates state, or depends on
|
|
162
|
+
* anything but its arguments does not qualify, and neither does a tagged
|
|
163
|
+
* template (see {@link isTag}: the two forms are mutually exclusive, and
|
|
164
|
+
* `chant dev check-lexicon` rejects `isTag: true` + `foldsAsCall: true`).
|
|
165
|
+
*
|
|
166
|
+
* Registration is by name. It is not permission to invoke whatever that
|
|
167
|
+
* name happens to be bound to: `fold()` reduces the call to a symbolic
|
|
168
|
+
* envelope executing nothing, and `../discovery/fold-import.ts` resolves
|
|
169
|
+
* the name through the folding FILE'S OWN imports before invoking the real
|
|
170
|
+
* function — so the function that runs while folding is the same one the
|
|
171
|
+
* run path would have called, from the module the source itself named.
|
|
172
|
+
*/
|
|
173
|
+
readonly foldsAsCall?: boolean;
|
|
145
174
|
}
|
|
146
175
|
/**
|
|
147
|
-
* Whether `chant build --fold` can ever fold a
|
|
148
|
-
* (chant #1062, epic #1019)
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
* a
|
|
153
|
-
*
|
|
176
|
+
* Whether `chant build --fold` can ever fold a use of this intrinsic
|
|
177
|
+
* (chant #1062, epic #1019) — in EITHER authored form.
|
|
178
|
+
*
|
|
179
|
+
* Two disjoint ways to qualify, one per form:
|
|
180
|
+
*
|
|
181
|
+
* - a registered tagged-template intrinsic (`Sub\`...\``) folds because
|
|
182
|
+
* `foldTaggedTemplate` recognizes its tag and recurses into the interior
|
|
183
|
+
* ({@link intrinsicTagFolds});
|
|
184
|
+
* - a registered plain-call intrinsic (`Ref(...)`, `Concat(...)`) folds
|
|
185
|
+
* only when its lexicon opted it in with `foldsAsCall`
|
|
186
|
+
* ({@link intrinsicCallFolds}, chant #1044). Before #1044 no plain call
|
|
187
|
+
* folded at all, whatever it was named or registered as.
|
|
154
188
|
*
|
|
155
|
-
* This function is the single predicate
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
* foldable; every caller keeps working unchanged, and the generated matrix
|
|
162
|
-
* updates the moment a lexicon's registration says a given intrinsic now
|
|
163
|
-
* folds — no doc rewrite, no second code path to remember.
|
|
189
|
+
* This function is the single predicate the generated per-lexicon intrinsics
|
|
190
|
+
* page (`../codegen/docs-sections.ts`'s "Folds?" column) calls — never a
|
|
191
|
+
* restated copy that could silently drift from the code. `fold()` itself
|
|
192
|
+
* calls the two form-specific predicates below rather than this one, because
|
|
193
|
+
* it always knows which form it is looking at, and a tag must not fold as a
|
|
194
|
+
* call (or vice versa) merely because the other form was opted in.
|
|
164
195
|
*
|
|
165
|
-
* Takes `{ isTag
|
|
166
|
-
* deliberately: `IntrinsicDef.isTag` is required
|
|
167
|
-
* (chant #1067), but
|
|
168
|
-
* possibly-older parsed JSON (`ManifestJSON` in
|
|
169
|
-
* on disk as a published lexicon's
|
|
170
|
-
*
|
|
171
|
-
* did — not a tag
|
|
196
|
+
* Takes a structural `{ isTag?, foldsAsCall? }` rather than
|
|
197
|
+
* `Pick<IntrinsicDef, ...>` deliberately: `IntrinsicDef.isTag` is required
|
|
198
|
+
* for new registrations (chant #1067), but these predicates also read off
|
|
199
|
+
* untrusted, possibly-older parsed JSON (`ManifestJSON` in
|
|
200
|
+
* `./codegen/docs-types.ts`, on disk as a published lexicon's
|
|
201
|
+
* `dist/manifest.json`) that may predate either field. `undefined` there
|
|
202
|
+
* means what it always did — not a tag, not opted in.
|
|
172
203
|
*/
|
|
173
204
|
export declare function intrinsicFolds(def: {
|
|
174
205
|
isTag?: boolean;
|
|
206
|
+
foldsAsCall?: boolean;
|
|
207
|
+
}): boolean;
|
|
208
|
+
/** True when this intrinsic's TAGGED-TEMPLATE form folds (`Sub\`...\``) — see {@link intrinsicFolds}. */
|
|
209
|
+
export declare function intrinsicTagFolds(def: {
|
|
210
|
+
isTag?: boolean;
|
|
211
|
+
}): boolean;
|
|
212
|
+
/**
|
|
213
|
+
* True when this intrinsic's PLAIN-CALL form folds (`Ref(...)`) — i.e. the
|
|
214
|
+
* lexicon opted it in via {@link IntrinsicDef.foldsAsCall} (chant #1044).
|
|
215
|
+
*
|
|
216
|
+
* `isTag: true` disqualifies regardless: a tagged template is invoked as
|
|
217
|
+
* `` Name`...` ``, so a call to it isn't the registered authoring form at
|
|
218
|
+
* all. Keeping that here rather than trusting registrations means a lexicon
|
|
219
|
+
* that declares both flags cannot quietly widen `fold()`'s call case — and
|
|
220
|
+
* `chant dev check-lexicon` fails the registration outright.
|
|
221
|
+
*/
|
|
222
|
+
export declare function intrinsicCallFolds(def: {
|
|
223
|
+
isTag?: boolean;
|
|
224
|
+
foldsAsCall?: boolean;
|
|
175
225
|
}): boolean;
|
|
176
226
|
/**
|
|
177
227
|
* Options passed to a MigrationSource by `chant migrate`.
|
package/dist/lexicon.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lexicon.d.ts","sourceRoot":"","sources":["../src/lexicon.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"lexicon.d.ts","sourceRoot":"","sources":["../src/lexicon.ts"],"names":[],"mappings":"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"}
|
package/dist/runtime.d.ts
CHANGED
|
@@ -18,6 +18,15 @@ import { type Declarable } from "./declarable.js";
|
|
|
18
18
|
export declare function createResource(type: string, lexicon: string, attrMap: Record<string, string>): new (props: Record<string, unknown>, attributes?: Record<string, unknown>) => Declarable & Record<string, string>;
|
|
19
19
|
/**
|
|
20
20
|
* Create a property-kind class for a given property type.
|
|
21
|
+
*
|
|
22
|
+
* Instances carry DECLARABLE_MARKER/lexicon/entityType/kind at runtime (set
|
|
23
|
+
* via defineProperty below), so they already satisfy `Declarable` — the
|
|
24
|
+
* return type just needs to say so. Before this, the signature was
|
|
25
|
+
* `Record<string, unknown>` with no `Declarable`, so any composite that
|
|
26
|
+
* returned a property-kind instance as a top-level member only type-checked
|
|
27
|
+
* by accident: either the caller went through an untyped `require()` (losing
|
|
28
|
+
* the type entirely) or never assigned the instance where its `Declarable`-ness
|
|
29
|
+
* was checked statically. See chant #1068.
|
|
21
30
|
*/
|
|
22
|
-
export declare function createProperty(type: string, lexicon: string): new (props: Record<string, unknown>) => Record<string, unknown>;
|
|
31
|
+
export declare function createProperty(type: string, lexicon: string): new (props: Record<string, unknown>) => Declarable & Record<string, unknown>;
|
|
23
32
|
//# sourceMappingURL=runtime.d.ts.map
|
package/dist/runtime.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAqB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAGlE;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,KAAK,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA4BnH;AAED
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAqB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAGlE;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,KAAK,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA4BnH;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,KAAK,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAY9E"}
|
package/package.json
CHANGED
|
@@ -28,6 +28,8 @@ function writeFixture(dir: string): void {
|
|
|
28
28
|
{ name: "Mismatch1", description: "claims tag but is a plain call", isTag: true },
|
|
29
29
|
{ name: "Mismatch2", description: "claims plain but is a tagged template", isTag: false },
|
|
30
30
|
{ name: "Missing1", description: "registered but never exported", isTag: false },
|
|
31
|
+
{ name: "Plain2", description: "a plain call opted into call-form folding", isTag: false, foldsAsCall: true },
|
|
32
|
+
{ name: "Tag2", description: "a tagged template wrongly opted into call-form folding", isTag: true, foldsAsCall: true },
|
|
31
33
|
];
|
|
32
34
|
},
|
|
33
35
|
};
|
|
@@ -36,7 +38,7 @@ function writeFixture(dir: string): void {
|
|
|
36
38
|
|
|
37
39
|
writeFileSync(
|
|
38
40
|
join(dir, "src/index.ts"),
|
|
39
|
-
`export { Tag1, Plain1, Mismatch1, Mismatch2 } from "./intrinsics";
|
|
41
|
+
`export { Tag1, Plain1, Mismatch1, Mismatch2, Plain2, Tag2 } from "./intrinsics";
|
|
40
42
|
`,
|
|
41
43
|
);
|
|
42
44
|
|
|
@@ -61,6 +63,16 @@ export function Mismatch1(x: string): string {
|
|
|
61
63
|
export function Mismatch2(strings: TemplateStringsArray, ...values: unknown[]): string {
|
|
62
64
|
return strings.join("");
|
|
63
65
|
}
|
|
66
|
+
|
|
67
|
+
export function Plain2(x: string): string {
|
|
68
|
+
return x;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// chant #1044 — registered with foldsAsCall: true above, but authored as a
|
|
72
|
+
// tagged template, so there is no plain-call form to opt in.
|
|
73
|
+
export function Tag2(strings: TemplateStringsArray, ...values: unknown[]): string {
|
|
74
|
+
return strings.join("");
|
|
75
|
+
}
|
|
64
76
|
`,
|
|
65
77
|
);
|
|
66
78
|
}
|
|
@@ -112,6 +124,28 @@ describe("auditIntrinsics", () => {
|
|
|
112
124
|
expect(item?.detail).toMatch(/not exported from src\/index\.ts/);
|
|
113
125
|
});
|
|
114
126
|
|
|
127
|
+
test("a plain call opted into call-form folding passes (chant #1044)", () => {
|
|
128
|
+
const items = auditIntrinsics(dir);
|
|
129
|
+
const item = items.find((i) => i.name === "Plain2");
|
|
130
|
+
expect(item).toMatchObject({ exported: true, actualIsTag: false, ok: true, declaredFoldsAsCall: true, callFormOk: true });
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("a tagged template registered with foldsAsCall: true fails — the opt-in is for plain calls only (chant #1044)", () => {
|
|
134
|
+
const items = auditIntrinsics(dir);
|
|
135
|
+
const item = items.find((i) => i.name === "Tag2");
|
|
136
|
+
// The isTag half is fine (it really is a tag); the call-form half is not.
|
|
137
|
+
expect(item?.ok).toBe(true);
|
|
138
|
+
expect(item?.callFormOk).toBe(false);
|
|
139
|
+
expect(item?.callFormDetail).toMatch(/authored as a tagged template.*foldsAsCall: true/);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test("an intrinsic with no foldsAsCall at all is simply not opted in — absent, not false (chant #1044)", () => {
|
|
143
|
+
const items = auditIntrinsics(dir);
|
|
144
|
+
const item = items.find((i) => i.name === "Plain1");
|
|
145
|
+
expect(item?.declaredFoldsAsCall).toBeUndefined();
|
|
146
|
+
expect(item?.callFormOk).toBe(true);
|
|
147
|
+
});
|
|
148
|
+
|
|
115
149
|
test("returns [] for a lexicon with no intrinsics() method", () => {
|
|
116
150
|
const emptyDir = mkdtempSync(join(tmpdir(), "chant-check-lexicon-intrinsics-empty-"));
|
|
117
151
|
try {
|
|
@@ -24,6 +24,13 @@
|
|
|
24
24
|
* tag (see ../../fold/fold.ts). Anything else (a plain function, a class,
|
|
25
25
|
* a const object/proxy) cannot be invoked as `` Name`...` `` and must be
|
|
26
26
|
* `isTag: false`.
|
|
27
|
+
*
|
|
28
|
+
* chant #1044 adds a third question, for the same reason the first two
|
|
29
|
+
* exist: `foldsAsCall` opts an intrinsic's PLAIN-CALL form into folding, so
|
|
30
|
+
* declaring it on something authored as a tagged template claims a form that
|
|
31
|
+
* cannot be called that way. The two flags are mutually exclusive, and a
|
|
32
|
+
* registration setting both is a failure here rather than a silently ignored
|
|
33
|
+
* field.
|
|
27
34
|
*/
|
|
28
35
|
|
|
29
36
|
import { existsSync, readFileSync } from "fs";
|
|
@@ -36,6 +43,8 @@ export interface IntrinsicAuditItem {
|
|
|
36
43
|
name: string;
|
|
37
44
|
/** The `isTag` value as registered in `src/plugin.ts`'s `intrinsics()`. */
|
|
38
45
|
declaredIsTag: boolean | undefined;
|
|
46
|
+
/** The `foldsAsCall` opt-in as registered in `src/plugin.ts` (chant #1044); `undefined` when absent, which means "not opted in". */
|
|
47
|
+
declaredFoldsAsCall: boolean | undefined;
|
|
39
48
|
/** Whether `name` resolves to a real export of `src/index.ts`. */
|
|
40
49
|
exported: boolean;
|
|
41
50
|
/**
|
|
@@ -50,11 +59,20 @@ export interface IntrinsicAuditItem {
|
|
|
50
59
|
/** True only when exported AND the authored shape matches `declaredIsTag`. */
|
|
51
60
|
ok: boolean;
|
|
52
61
|
detail?: string;
|
|
62
|
+
/**
|
|
63
|
+
* chant #1044 — false only when `foldsAsCall: true` is registered on
|
|
64
|
+
* something authored as a tagged template. Tracked separately from
|
|
65
|
+
* {@link ok} so the two failures report as the two different registration
|
|
66
|
+
* mistakes they are, rather than one message covering both.
|
|
67
|
+
*/
|
|
68
|
+
callFormOk: boolean;
|
|
69
|
+
callFormDetail?: string;
|
|
53
70
|
}
|
|
54
71
|
|
|
55
72
|
interface DeclaredIntrinsic {
|
|
56
73
|
name: string;
|
|
57
74
|
isTag: boolean | undefined;
|
|
75
|
+
foldsAsCall: boolean | undefined;
|
|
58
76
|
}
|
|
59
77
|
|
|
60
78
|
interface ExportTarget {
|
|
@@ -80,7 +98,7 @@ function parseFile(path: string): ts.SourceFile | undefined {
|
|
|
80
98
|
/**
|
|
81
99
|
* Find `intrinsics(): IntrinsicDef[] { return [ ... ]; }` (or the arrow-
|
|
82
100
|
* function-property equivalent) in a plugin.ts source file and extract each
|
|
83
|
-
* registered `{ name, isTag }`
|
|
101
|
+
* registered `{ name, isTag, foldsAsCall }` triple from the array literal. Returns
|
|
84
102
|
* `undefined` when no `intrinsics` method exists at all (lexicons with no
|
|
85
103
|
* intrinsics, e.g. gcp/k8s, still return `[]` — that's a real empty array,
|
|
86
104
|
* not `undefined`).
|
|
@@ -127,6 +145,7 @@ function extractDeclaredIntrinsics(pluginPath: string): DeclaredIntrinsic[] | un
|
|
|
127
145
|
if (!ts.isObjectLiteralExpression(el)) continue;
|
|
128
146
|
let name: string | undefined;
|
|
129
147
|
let isTag: boolean | undefined;
|
|
148
|
+
let foldsAsCall: boolean | undefined;
|
|
130
149
|
|
|
131
150
|
for (const prop of el.properties) {
|
|
132
151
|
if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name)) continue;
|
|
@@ -136,10 +155,13 @@ function extractDeclaredIntrinsics(pluginPath: string): DeclaredIntrinsic[] | un
|
|
|
136
155
|
} else if (key === "isTag") {
|
|
137
156
|
if (prop.initializer.kind === ts.SyntaxKind.TrueKeyword) isTag = true;
|
|
138
157
|
else if (prop.initializer.kind === ts.SyntaxKind.FalseKeyword) isTag = false;
|
|
158
|
+
} else if (key === "foldsAsCall") {
|
|
159
|
+
if (prop.initializer.kind === ts.SyntaxKind.TrueKeyword) foldsAsCall = true;
|
|
160
|
+
else if (prop.initializer.kind === ts.SyntaxKind.FalseKeyword) foldsAsCall = false;
|
|
139
161
|
}
|
|
140
162
|
}
|
|
141
163
|
|
|
142
|
-
if (name !== undefined) result.push({ name, isTag });
|
|
164
|
+
if (name !== undefined) result.push({ name, isTag, foldsAsCall });
|
|
143
165
|
}
|
|
144
166
|
|
|
145
167
|
return result;
|
|
@@ -271,10 +293,12 @@ export function auditIntrinsics(lexiconDir: string): IntrinsicAuditItem[] {
|
|
|
271
293
|
items.push({
|
|
272
294
|
name: d.name,
|
|
273
295
|
declaredIsTag: d.isTag,
|
|
296
|
+
declaredFoldsAsCall: d.foldsAsCall,
|
|
274
297
|
exported: false,
|
|
275
298
|
actualIsTag: undefined,
|
|
276
299
|
ok: false,
|
|
277
300
|
detail: `"${d.name}" is registered in plugin.ts intrinsics() but is not exported from src/index.ts`,
|
|
301
|
+
callFormOk: true,
|
|
278
302
|
});
|
|
279
303
|
continue;
|
|
280
304
|
}
|
|
@@ -284,22 +308,34 @@ export function auditIntrinsics(lexiconDir: string): IntrinsicAuditItem[] {
|
|
|
284
308
|
items.push({
|
|
285
309
|
name: d.name,
|
|
286
310
|
declaredIsTag: d.isTag,
|
|
311
|
+
declaredFoldsAsCall: d.foldsAsCall,
|
|
287
312
|
exported: true,
|
|
288
313
|
actualIsTag: undefined,
|
|
289
314
|
ok: false,
|
|
290
315
|
detail: `could not locate the declaration of "${d.name}" (exported from ${target.modulePath}) to verify it against isTag`,
|
|
316
|
+
callFormOk: true,
|
|
291
317
|
});
|
|
292
318
|
continue;
|
|
293
319
|
}
|
|
294
320
|
|
|
295
321
|
const declaredTag = d.isTag === true;
|
|
296
322
|
const ok = resolved.isTag === declaredTag;
|
|
323
|
+
// chant #1044 — `foldsAsCall` opts the PLAIN-CALL form in, so it is
|
|
324
|
+
// meaningless (and, if honored, wrong) on a tagged template. Judged
|
|
325
|
+
// against how the export is really authored, not against the sibling
|
|
326
|
+
// `isTag` claim, which may itself be the thing that's wrong.
|
|
327
|
+
const callFormOk = !(d.foldsAsCall === true && resolved.isTag === true);
|
|
297
328
|
items.push({
|
|
298
329
|
name: d.name,
|
|
299
330
|
declaredIsTag: d.isTag,
|
|
331
|
+
declaredFoldsAsCall: d.foldsAsCall,
|
|
300
332
|
exported: true,
|
|
301
333
|
actualIsTag: resolved.isTag,
|
|
302
334
|
ok,
|
|
335
|
+
callFormOk,
|
|
336
|
+
callFormDetail: callFormOk
|
|
337
|
+
? undefined
|
|
338
|
+
: `"${d.name}" is authored as a tagged template but registered with foldsAsCall: true — the call-form opt-in applies to plain-call intrinsics only`,
|
|
303
339
|
detail: ok
|
|
304
340
|
? undefined
|
|
305
341
|
: resolved.isTag
|
|
@@ -243,6 +243,24 @@ export async function checkLexicon(dir: string): Promise<CheckResult> {
|
|
|
243
243
|
: undefined,
|
|
244
244
|
});
|
|
245
245
|
|
|
246
|
+
// chant #1044 — the call-form opt-in (`foldsAsCall`) admits a plain call
|
|
247
|
+
// into `fold()`, which has no general CallExpression case. Declaring it on
|
|
248
|
+
// a tagged template claims a form the intrinsic cannot be invoked in, so
|
|
249
|
+
// it fails here rather than being quietly ignored — the same reasoning as
|
|
250
|
+
// the isTag check above.
|
|
251
|
+
const badCallForm = intrinsicAudit.filter((i) => !i.callFormOk);
|
|
252
|
+
items.push({
|
|
253
|
+
name: "Registered intrinsics' foldsAsCall opt-in is only on plain calls",
|
|
254
|
+
tier: 1,
|
|
255
|
+
pass: badCallForm.length === 0,
|
|
256
|
+
detail:
|
|
257
|
+
badCallForm.length > 0
|
|
258
|
+
? badCallForm.map((i) => i.callFormDetail).join(" | ")
|
|
259
|
+
: intrinsicAudit.length > 0
|
|
260
|
+
? `${intrinsicAudit.length} intrinsic(s) checked`
|
|
261
|
+
: undefined,
|
|
262
|
+
});
|
|
263
|
+
|
|
246
264
|
const hasPluginTest = findFiles(join(dir, "src"), (n) => n === "plugin.test.ts").length > 0;
|
|
247
265
|
items.push({
|
|
248
266
|
name: "plugin.test.ts exists",
|
|
@@ -32,11 +32,16 @@ describe("generateIntrinsics — Folds? column", () => {
|
|
|
32
32
|
expect(page).toContain("| `Sub` | — | `Sub` | Yes | Yes |");
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
-
test("a plain-call intrinsic does not fold
|
|
35
|
+
test("a plain-call intrinsic its lexicon never opted in does not fold", () => {
|
|
36
36
|
const page = generateIntrinsics(config, manifestWith([{ name: "Ref", isTag: false }]));
|
|
37
37
|
expect(page).toContain("| `Ref` | — | `Ref` | No | No |");
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
+
test("a plain-call intrinsic opted into call-form folding does fold (chant #1044)", () => {
|
|
41
|
+
const page = generateIntrinsics(config, manifestWith([{ name: "Ref", isTag: false, foldsAsCall: true }]));
|
|
42
|
+
expect(page).toContain("| `Ref` | — | `Ref` | No | Yes |");
|
|
43
|
+
});
|
|
44
|
+
|
|
40
45
|
test("an intrinsic with isTag omitted does not fold (same as isTag: false)", () => {
|
|
41
46
|
const page = generateIntrinsics(config, manifestWith([{ name: "reference", outputKey: "!reference" }]));
|
|
42
47
|
expect(page).toContain("| `reference` | — | `!reference` | No | No |");
|
|
@@ -47,6 +52,7 @@ describe("generateIntrinsics — Folds? column", () => {
|
|
|
47
52
|
{ name: "Sub", isTag: true },
|
|
48
53
|
{ name: "Ref" },
|
|
49
54
|
{ name: "GetAtt", isTag: false },
|
|
55
|
+
{ name: "Join", isTag: false, foldsAsCall: true },
|
|
50
56
|
];
|
|
51
57
|
const page = generateIntrinsics(config, manifestWith(intrinsics));
|
|
52
58
|
for (const fn of intrinsics) {
|
|
@@ -95,7 +95,7 @@ export function generateIntrinsics(
|
|
|
95
95
|
"",
|
|
96
96
|
`The ${config.displayName} lexicon provides **${intrinsics.length}** intrinsic functions.`,
|
|
97
97
|
"",
|
|
98
|
-
`**Tag?** shows how an intrinsic is authored: a genuine tagged template (\`Sub\\\`...\\\`\`) or a plain function call (\`Ref(...)\`). **Folds?** shows whether [\`chant build --fold\`](/chant/concepts/typescript-as-data/#folded-vs-run) can reduce a
|
|
98
|
+
`**Tag?** shows how an intrinsic is authored: a genuine tagged template (\`Sub\\\`...\\\`\`) or a plain function call (\`Ref(...)\`). **Folds?** shows whether [\`chant build --fold\`](/chant/concepts/typescript-as-data/#folded-vs-run) can reduce a use of this intrinsic today, without running the file — generated directly from this lexicon's registration, not restated by hand. A tagged template folds once it is registered. A plain call folds only where this lexicon has opted that intrinsic in one at a time (\`foldsAsCall\`), so a \`No\` in this column means this intrinsic has not been opted in, not that calls in general cannot fold.`,
|
|
99
99
|
"",
|
|
100
100
|
"| Function | Description | Output Key | Tag? | Folds? |",
|
|
101
101
|
"|----------|-------------|------------|------|--------|",
|
|
@@ -55,6 +55,8 @@ export interface ManifestJSON {
|
|
|
55
55
|
description?: string;
|
|
56
56
|
outputKey?: string;
|
|
57
57
|
isTag?: boolean;
|
|
58
|
+
/** chant #1044 — the call-form fold opt-in, as published in the lexicon's manifest. Absent in any manifest built before #1044, which reads the same as "not opted in". */
|
|
59
|
+
foldsAsCall?: boolean;
|
|
58
60
|
}>;
|
|
59
61
|
pseudoParameters?: Record<string, string>;
|
|
60
62
|
}
|
package/src/declarable.ts
CHANGED
|
@@ -13,6 +13,26 @@ export interface Declarable {
|
|
|
13
13
|
readonly [DECLARABLE_MARKER]: true;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* A `Declarable` that carries a resource payload — the `props`/`attributes`
|
|
18
|
+
* fields that most lexicon serializers read to produce output. Not every
|
|
19
|
+
* `Declarable` has one (outputs and parameters genuinely don't), so this is
|
|
20
|
+
* kept as a sub-interface rather than widening the base type. See chant #1049.
|
|
21
|
+
*/
|
|
22
|
+
export interface ResourceDeclarable extends Declarable {
|
|
23
|
+
readonly props: unknown;
|
|
24
|
+
readonly attributes?: unknown;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Type guard for `ResourceDeclarable` — replaces the ad-hoc `"props" in x`
|
|
29
|
+
* checks that were previously repeated (with an `as unknown as` cast) at every
|
|
30
|
+
* call site that reads `props`/`attributes` off a `Declarable`.
|
|
31
|
+
*/
|
|
32
|
+
export function isResourceDeclarable(value: Declarable): value is ResourceDeclarable {
|
|
33
|
+
return "props" in value;
|
|
34
|
+
}
|
|
35
|
+
|
|
16
36
|
/**
|
|
17
37
|
* Core parameter type for lexicon-agnostic parameters
|
|
18
38
|
*/
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
* today.
|
|
55
55
|
*/
|
|
56
56
|
|
|
57
|
-
import { DECLARABLE_MARKER, type Declarable } from "../declarable";
|
|
57
|
+
import { DECLARABLE_MARKER, isResourceDeclarable, type Declarable } from "../declarable";
|
|
58
58
|
import { AttrRef } from "../attrref";
|
|
59
59
|
import { INTRINSIC_MARKER, type Intrinsic } from "../intrinsic";
|
|
60
60
|
import { isAttrRefLike } from "../utils";
|
|
@@ -256,7 +256,7 @@ function encodeValue(value: unknown, entityNames: Map<unknown, string>): WireVal
|
|
|
256
256
|
// directly rather than walking `resource` as a Declarable reference).
|
|
257
257
|
// Inline exactly that, discarding the unresolvable (and, in every corpus
|
|
258
258
|
// entry today, unread) identity layer.
|
|
259
|
-
const props =
|
|
259
|
+
const props = isResourceDeclarable(decl) ? decl.props : undefined;
|
|
260
260
|
return { __property: { lexicon: decl.lexicon, entityType: decl.entityType, props: props !== undefined ? encodeValue(props, entityNames) : undefined } };
|
|
261
261
|
}
|
|
262
262
|
|
|
@@ -280,11 +280,13 @@ function encodeDeclarable(entity: Declarable, entityNames: Map<unknown, string>)
|
|
|
280
280
|
const wire: Omit<WireDeclarableEntity, "form" | "name"> = { lexicon: entity.lexicon, entityType: entity.entityType, markers: [] };
|
|
281
281
|
if (entity.kind !== undefined) wire.kind = entity.kind;
|
|
282
282
|
|
|
283
|
-
if (
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
283
|
+
if (isResourceDeclarable(entity)) {
|
|
284
|
+
if (entity.props !== undefined) {
|
|
285
|
+
wire.props = encodeValue(entity.props, entityNames);
|
|
286
|
+
}
|
|
287
|
+
if (entity.attributes !== undefined) {
|
|
288
|
+
wire.attributes = encodeValue(entity.attributes, entityNames);
|
|
289
|
+
}
|
|
288
290
|
}
|
|
289
291
|
|
|
290
292
|
const markers: string[] = [];
|