@intentius/chant 0.109.0 → 0.110.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/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/param-deps.d.ts +30 -2
- package/dist/discovery/param-deps.d.ts.map +1 -1
- package/dist/fold/subset.d.ts +9 -2
- package/dist/fold/subset.d.ts.map +1 -1
- package/dist/fold-provenance.d.ts +14 -2
- package/dist/fold-provenance.d.ts.map +1 -1
- package/dist/import/ir-utils.d.ts.map +1 -1
- package/dist/import/parser.d.ts +8 -0
- package/dist/import/parser.d.ts.map +1 -1
- package/dist/provenance.d.ts +11 -0
- package/dist/provenance.d.ts.map +1 -1
- package/dist/serializer-walker.d.ts.map +1 -1
- package/dist/stack-output.d.ts +5 -0
- package/dist/stack-output.d.ts.map +1 -1
- package/dist/yaml.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/cli/commands/import.test.ts +5 -4
- package/src/discovery/fold-composite.test.ts +22 -0
- package/src/discovery/fold-host-composite.test.ts +23 -0
- package/src/discovery/fold-import.ts +73 -21
- package/src/discovery/fold-project-provenance.test.ts +52 -0
- package/src/discovery/param-deps.test.ts +43 -2
- package/src/discovery/param-deps.ts +101 -2
- package/src/fold/subset.ts +9 -2
- package/src/fold-provenance.test.ts +11 -0
- package/src/fold-provenance.ts +22 -2
- package/src/import/ir-utils.ts +6 -1
- package/src/import/parser.ts +8 -0
- package/src/provenance.ts +13 -1
- package/src/serializer-walker.test.ts +10 -0
- package/src/serializer-walker.ts +17 -1
- package/src/stack-output.ts +6 -1
- package/src/yaml.test.ts +6 -0
- package/src/yaml.ts +4 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fold-import.d.ts","sourceRoot":"","sources":["../../src/discovery/fold-import.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAMjC,OAAO,EAAsC,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AACpF,OAAO,EAAkC,KAAK,iBAAiB,EAAyB,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"fold-import.d.ts","sourceRoot":"","sources":["../../src/discovery/fold-import.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
import * as ts from "typescript";
|
|
2
|
-
import type { ArgumentLocation, PathOrigin, SourceLocation } from "../provenance.js";
|
|
2
|
+
import type { ArgumentLocation, HostOriginReason, PathOrigin, SourceLocation } from "../provenance.js";
|
|
3
|
+
/**
|
|
4
|
+
* What a file binds to host code, for {@link hostReadOf} (INTENTIUS/typescript-as-data#248).
|
|
5
|
+
*/
|
|
6
|
+
export interface HostBindings {
|
|
7
|
+
/** Local names bound to a value a lexicon package exports. */
|
|
8
|
+
values: ReadonlySet<string>;
|
|
9
|
+
/** Local names of eager lexicon helpers: a call to one is evaluated by host code at fold time. */
|
|
10
|
+
eagerCalls: ReadonlySet<string>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The first host read in `expr`, following this file's own top-level consts,
|
|
14
|
+
* or `undefined` when it reads none (INTENTIUS/typescript-as-data#248).
|
|
15
|
+
*
|
|
16
|
+
* A method called on a receiver is `host-call` whatever the receiver is, since
|
|
17
|
+
* fold calls the real method on it; so is a call to an eager lexicon helper. An
|
|
18
|
+
* identifier bound to a lexicon export is `host-value`. A call fold reduces to
|
|
19
|
+
* an envelope (an authoring helper, a call-form intrinsic) or evaluates itself
|
|
20
|
+
* (a project function) is not host code, and only its arguments are read.
|
|
21
|
+
*
|
|
22
|
+
* Syntactic, like {@link readParams}, so it over-reports in one place: both
|
|
23
|
+
* arms of a conditional are read although only one is taken. That errs toward
|
|
24
|
+
* `unknown`, which never licenses an edit `direct` would not.
|
|
25
|
+
*/
|
|
26
|
+
export declare function hostReadOf(expr: ts.Expression, consts: ReadonlyMap<string, ts.Expression>, paramLocals: ReadonlySet<string>, host: HostBindings): HostOriginReason | undefined;
|
|
3
27
|
/**
|
|
4
28
|
* Path → build-parameter origin for one resource's props object literal.
|
|
5
29
|
*
|
|
@@ -12,8 +36,12 @@ import type { ArgumentLocation, PathOrigin, SourceLocation } from "../provenance
|
|
|
12
36
|
* A spread is attributed to the object it spreads INTO, at that object's own
|
|
13
37
|
* path (the entity root for a top-level spread), since which keys it
|
|
14
38
|
* contributes is not knowable here.
|
|
39
|
+
*
|
|
40
|
+
* With `host`, a path whose expression reads host code ({@link hostReadOf})
|
|
41
|
+
* is recorded `host` instead, and that outranks a build parameter it also
|
|
42
|
+
* reads: the value is what host code returned, whatever the parameter was.
|
|
15
43
|
*/
|
|
16
|
-
export declare function collectParamDependencies(props: ts.ObjectLiteralExpression, consts: ReadonlyMap<string, ts.Expression>, paramLocals: ReadonlySet<string
|
|
44
|
+
export declare function collectParamDependencies(props: ts.ObjectLiteralExpression, consts: ReadonlyMap<string, ts.Expression>, paramLocals: ReadonlySet<string>, host?: HostBindings): Record<string, PathOrigin>;
|
|
17
45
|
/**
|
|
18
46
|
* The factory-parameter names in scope inside one composite body (chant #2161).
|
|
19
47
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"param-deps.d.ts","sourceRoot":"","sources":["../../src/discovery/param-deps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AACjC,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"param-deps.d.ts","sourceRoot":"","sources":["../../src/discovery/param-deps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AACjC,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAsHpG;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,8DAA8D;IAC9D,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC5B,kGAAkG;IAClG,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACjC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,EAAE,CAAC,UAAU,EACnB,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,EAC1C,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,IAAI,EAAE,YAAY,GACjB,gBAAgB,GAAG,SAAS,CAyD9B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,EAAE,CAAC,uBAAuB,EACjC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,EAC1C,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,IAAI,CAAC,EAAE,YAAY,GAClB,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CA8C5B;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,mBAAmB;IAClC,oEAAoE;IACpE,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC3B,oFAAoF;IACpF,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC3C;AAkGD;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC;CACzB;AAED,0DAA0D;AAC1D,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,cAAc,CAI5E;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,GAAG,gBAAgB,CAmB7F;AAOD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,EAAE,CAAC,uBAAuB,EACjC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,EAC1C,KAAK,EAAE,mBAAmB,EAC1B,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,iBAAiB,GACvB,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAkD5B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAC/B,cAAc,EAAE,SAAS,EAAE,CAAC,UAAU,EAAE,EACxC,MAAM,EAAE,aAAa,CAAC,SAAS,MAAM,EAAE,CAAC,EACxC,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,EAC1C,KAAK,EAAE,mBAAmB,EAC1B,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,iBAAiB,GACvB,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAqB5B"}
|
package/dist/fold/subset.d.ts
CHANGED
|
@@ -176,7 +176,7 @@ import { type IntrinsicDef } from "../lexicon.js";
|
|
|
176
176
|
* `spec/VERSION` in the specification repository carries the same string, and
|
|
177
177
|
* the conformance adapter reads this one to fill its `specVersion` field.
|
|
178
178
|
*
|
|
179
|
-
* ## Why 2.
|
|
179
|
+
* ## Why 2.3, and what each version since 1.0 asked for (chant#2445)
|
|
180
180
|
*
|
|
181
181
|
* Raising this is the last step of adopting a rule set, so each version was
|
|
182
182
|
* checked against what chant does rather than against whether the suite is
|
|
@@ -225,6 +225,13 @@ import { type IntrinsicDef } from "../lexicon.js";
|
|
|
225
225
|
* chant already did: a call-bound local exported by name (`export { x }`)
|
|
226
226
|
* resolves by F-Call as the single declarator does, and a same-file call's
|
|
227
227
|
* result read inside an F-Call argument resolves once per file (#3329).
|
|
228
|
+
* - **2.3** says a value host code produced, written at an export or into a
|
|
229
|
+
* field, has an unknown origin and never a direct one. chant reports
|
|
230
|
+
* `host-call` and `host-value` for resource fields since
|
|
231
|
+
* typescript-as-data#248. 2.3 also lets `F-Host-Composite` interpret a
|
|
232
|
+
* composite an active package publishes as TypeScript source, which chant
|
|
233
|
+
* has done since #3247, and adds fixtures for a call result read inside an
|
|
234
|
+
* argument, which chant passes since #3610.
|
|
228
235
|
*
|
|
229
236
|
* `scripts/check-docs-citations.ts` refuses to run when this constant and the
|
|
230
237
|
* rules it loads disagree, so this and the `@intentius/tsad-conformance`
|
|
@@ -236,7 +243,7 @@ import { type IntrinsicDef } from "../lexicon.js";
|
|
|
236
243
|
* Until chant#2470 the rules came from a commit `docs-check.yml` checked out;
|
|
237
244
|
* now they come from the published package, so bumping it is what moves this.
|
|
238
245
|
*/
|
|
239
|
-
export declare const SPEC_VERSION = "2.
|
|
246
|
+
export declare const SPEC_VERSION = "2.3";
|
|
240
247
|
/** The two EVL rule ids a shape violation can be attributed to. */
|
|
241
248
|
export type SubsetRuleId = "EVL001" | "EVL003";
|
|
242
249
|
/** A located, shape-level rejection: the offending node, the EVL rule id it maps to, and a message. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subset.d.ts","sourceRoot":"","sources":["../../src/fold/subset.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAEjC,OAAO,EAAiD,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAE9F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwKG;AAEH
|
|
1
|
+
{"version":3,"file":"subset.d.ts","sourceRoot":"","sources":["../../src/fold/subset.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAEjC,OAAO,EAAiD,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAE9F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwKG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyEG;AACH,eAAO,MAAM,YAAY,QAAQ,CAAC;AAElC,mEAAmE;AACnE,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE/C,uGAAuG;AACvG,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC;IACd,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD,0FAA0F;AAC1F,eAAO,MAAM,0BAA0B,EAAE,WAAW,CAAC,EAAE,CAAC,UAAU,CAchE,CAAC;AAEH,oFAAoF;AACpF,eAAO,MAAM,yBAAyB,EAAE,WAAW,CAAC,EAAE,CAAC,UAAU,CAG/D,CAAC;AAEH,gHAAgH;AAChH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,EAAE,CAAC,YAAY,GACpB,IAAI,IAAI,EAAE,CAAC,UAAU,GAAG,EAAE,CAAC,aAAa,GAAG,EAAE,CAAC,cAAc,CAE9D;AAED,6GAA6G;AAC7G,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,GAAG,IAAI,IAAI,EAAE,CAAC,aAAa,GAAG,EAAE,CAAC,cAAc,CAErG;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,SAAS,SAAK,GAAG,MAAM,CAGnE;AAMD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,GAAG,WAAW,CAAC,MAAM,CAAC,CAoDpF;AAgCD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,GAAG,MAAM,CAEzE;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,GAAG,MAAM,CAE1E;AAED,eAAO,MAAM,iCAAiC,8BAA8B,CAAC;AAE7E,eAAO,MAAM,yBAAyB,sBAAsB,CAAC;AAE7D,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,GAAG,MAAM,CAEtE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,GAAG,MAAM,CAErE;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,MAAM,CAElE;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,EAAE,CAAC,wBAAwB,EACjC,UAAU,CAAC,EAAE,SAAS,YAAY,EAAE,GACnC,eAAe,GAAG,SAAS,CAc7B;AAWD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,UAAU,CAAC,EAAE,SAAS,YAAY,EAAE,GACnC,eAAe,GAAG,SAAS,CAkO7B"}
|
|
@@ -71,7 +71,11 @@
|
|
|
71
71
|
import { type Declarable } from "./declarable.js";
|
|
72
72
|
import { type ArgumentLocation, type EntityProvenance, type PathOrigin, type SourceLocation } from "./provenance.js";
|
|
73
73
|
import type { DeepEntityDrift } from "./lifecycle/deep-diff.js";
|
|
74
|
-
/**
|
|
74
|
+
/**
|
|
75
|
+
* Why a field's origin could not be determined. The first two are facts about
|
|
76
|
+
* the BUILD; the host reasons are facts about the expression, and match the
|
|
77
|
+
* strings the specification's reference implementation reports.
|
|
78
|
+
*/
|
|
75
79
|
export type UnknownOriginReason =
|
|
76
80
|
/**
|
|
77
81
|
* A composite expanded the entity and this build did not interpret its body,
|
|
@@ -85,7 +89,15 @@ export type UnknownOriginReason =
|
|
|
85
89
|
* composite make it" is answerable. A sandboxed child's entities arrive this
|
|
86
90
|
* way: `discovery/entity-wire-codec.ts` drops build metadata over the wire.
|
|
87
91
|
*/
|
|
88
|
-
| "no-provenance"
|
|
92
|
+
| "no-provenance"
|
|
93
|
+
/**
|
|
94
|
+
* INTENTIUS/typescript-as-data#248: host code computed the value, by a method
|
|
95
|
+
* called on a real receiver (`"x".toUpperCase()`, `[1, 2].join("-")`) or an
|
|
96
|
+
* eager lexicon helper. The file wrote the call, not the value.
|
|
97
|
+
*/
|
|
98
|
+
| "host-call"
|
|
99
|
+
/** A value a lexicon package exports, bound by an import (`AWS.Region`, `S3Actions.GetObject`). */
|
|
100
|
+
| "host-value";
|
|
89
101
|
/**
|
|
90
102
|
* What produced one emitted property path.
|
|
91
103
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fold-provenance.d.ts","sourceRoot":"","sources":["../src/fold-provenance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqEG;AAEH,OAAO,EAAwB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAErE,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,cAAc,EACpB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,uBAAuB,CAAC;AAE5E
|
|
1
|
+
{"version":3,"file":"fold-provenance.d.ts","sourceRoot":"","sources":["../src/fold-provenance.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ir-utils.d.ts","sourceRoot":"","sources":["../../src/import/ir-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAkBzE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"ir-utils.d.ts","sourceRoot":"","sources":["../../src/import/ir-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAkBzE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAsBrE;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,OAAO,EACd,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,GAAG,IAAI,GAC5D,GAAG,CAAC,MAAM,CAAC,CAIb"}
|
package/dist/import/parser.d.ts
CHANGED
|
@@ -8,6 +8,9 @@ export interface ParameterIR {
|
|
|
8
8
|
readonly description?: string;
|
|
9
9
|
readonly defaultValue?: unknown;
|
|
10
10
|
readonly required?: boolean;
|
|
11
|
+
/** What the value is checked against, under the source format's own keys
|
|
12
|
+
* and as written (CloudFormation `AllowedValues`, `MinLength`, `NoEcho`). */
|
|
13
|
+
readonly constraints?: Readonly<Record<string, unknown>>;
|
|
11
14
|
}
|
|
12
15
|
/**
|
|
13
16
|
* Intermediate representation of a template resource
|
|
@@ -20,6 +23,11 @@ export interface ResourceIR {
|
|
|
20
23
|
/** Name of the condition gating this resource (CloudFormation `Condition`
|
|
21
24
|
* key, or equivalent), when the source template declares one (#2069). */
|
|
22
25
|
readonly condition?: string;
|
|
26
|
+
/** Resource-level attributes other than the condition, under the source
|
|
27
|
+
* format's own keys (CloudFormation `DependsOn`, `DeletionPolicy`,
|
|
28
|
+
* `UpdateReplacePolicy`, `UpdatePolicy`, `CreationPolicy`). Values are
|
|
29
|
+
* parsed value trees, like {@link properties}. */
|
|
30
|
+
readonly attributes?: Readonly<Record<string, unknown>>;
|
|
23
31
|
}
|
|
24
32
|
/**
|
|
25
33
|
* Intermediate representation of a declared template condition — a named
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/import/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAE1D;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/import/parser.ts"],"names":[],"mappings":"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"}
|
package/dist/provenance.d.ts
CHANGED
|
@@ -83,6 +83,12 @@ export interface EntityProvenance {
|
|
|
83
83
|
* expression for this path reads no parameter at all. The composite fixes
|
|
84
84
|
* this field, and no argument at the call site moves it.
|
|
85
85
|
*
|
|
86
|
+
* - `host` — the authored expression for this path reads a value host code
|
|
87
|
+
* produced (INTENTIUS/typescript-as-data#248): a method called on a real
|
|
88
|
+
* receiver or an eager lexicon helper (`host-call`), or a value a lexicon
|
|
89
|
+
* package exports (`host-value`). The author wrote the call, not the value,
|
|
90
|
+
* so ./fold-provenance.ts answers `unknown` rather than `direct`.
|
|
91
|
+
*
|
|
86
92
|
* The coarse `composite` and the two fine kinds are not alternatives. A build
|
|
87
93
|
* records `composite` when it expanded a composite without interpreting its
|
|
88
94
|
* body (the run path, an inadmissible factory), and that is why
|
|
@@ -111,7 +117,12 @@ export type PathOrigin = {
|
|
|
111
117
|
} | {
|
|
112
118
|
kind: "composite-literal";
|
|
113
119
|
composite: string;
|
|
120
|
+
} | {
|
|
121
|
+
kind: "host";
|
|
122
|
+
reason: HostOriginReason;
|
|
114
123
|
};
|
|
124
|
+
/** Which host code produced a value: a call it ran, or a value its package exports. */
|
|
125
|
+
export type HostOriginReason = "host-call" | "host-value";
|
|
115
126
|
/**
|
|
116
127
|
* A place in a source file. `file` is absolute, as
|
|
117
128
|
* {@link EntityProvenance.sourceFile} is; `line` and `column` are 1-based, the
|
package/dist/provenance.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provenance.d.ts","sourceRoot":"","sources":["../src/provenance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,MAAM,WAAW,gBAAgB;IAC/B,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,cAAc,CAAC;IAC/B;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CACpC;AAED
|
|
1
|
+
{"version":3,"file":"provenance.d.ts","sourceRoot":"","sources":["../src/provenance.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serializer-walker.d.ts","sourceRoot":"","sources":["../src/serializer-walker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAO/C,MAAM,WAAW,iBAAiB;IAChC,4DAA4D;IAC5D,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;IACzD,mEAAmE;IACnE,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1C,+DAA+D;IAC/D,kBAAkB,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC;CAChF;
|
|
1
|
+
{"version":3,"file":"serializer-walker.d.ts","sourceRoot":"","sources":["../src/serializer-walker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAO/C,MAAM,WAAW,iBAAiB;IAChC,4DAA4D;IAC5D,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;IACzD,mEAAmE;IACnE,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1C,+DAA+D;IAC/D,kBAAkB,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC;CAChF;AAkBD;;;GAGG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,OAAO,EACd,WAAW,EAAE,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,EACpC,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAyFT"}
|
package/dist/stack-output.d.ts
CHANGED
|
@@ -33,6 +33,10 @@ export interface StackOutput extends Declarable {
|
|
|
33
33
|
* `Output.Condition`) — a condition name, or the condition Declarable
|
|
34
34
|
* itself, resolved to its logical name at serialization (#2068/#2069). */
|
|
35
35
|
readonly condition?: string | Declarable;
|
|
36
|
+
/** The output's key in the template, when it is not the export name. A
|
|
37
|
+
* template may use one key for an output and a parameter or resource; a
|
|
38
|
+
* module cannot export both under that name (#3604). */
|
|
39
|
+
readonly name?: string;
|
|
36
40
|
}
|
|
37
41
|
/**
|
|
38
42
|
* Type guard for StackOutput.
|
|
@@ -61,5 +65,6 @@ export declare function stackOutput(ref: AttrRef | Intrinsic | string, options?:
|
|
|
61
65
|
exportName?: string;
|
|
62
66
|
lexicon?: string;
|
|
63
67
|
condition?: string | Declarable;
|
|
68
|
+
name?: string;
|
|
64
69
|
}): StackOutput;
|
|
65
70
|
//# sourceMappingURL=stack-output.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stack-output.d.ts","sourceRoot":"","sources":["../src/stack-output.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,iBAAiB,EAAgB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAChF,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAG1D;;GAEG;AACH,eAAO,MAAM,mBAAmB,eAAkC,CAAC;AAEnE;;;GAGG;AACH,MAAM,WAAW,WAAY,SAAQ,UAAU;IAC7C,QAAQ,CAAC,CAAC,mBAAmB,CAAC,EAAE,IAAI,CAAC;IACrC,QAAQ,CAAC,CAAC,iBAAiB,CAAC,EAAE,IAAI,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB;wEACoE;IACpE,QAAQ,CAAC,SAAS,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACjD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;gFAC4E;IAC5E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B;;8EAE0E;IAC1E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"stack-output.d.ts","sourceRoot":"","sources":["../src/stack-output.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,iBAAiB,EAAgB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAChF,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAG1D;;GAEG;AACH,eAAO,MAAM,mBAAmB,eAAkC,CAAC;AAEnE;;;GAGG;AACH,MAAM,WAAW,WAAY,SAAQ,UAAU;IAC7C,QAAQ,CAAC,CAAC,mBAAmB,CAAC,EAAE,IAAI,CAAC;IACrC,QAAQ,CAAC,CAAC,iBAAiB,CAAC,EAAE,IAAI,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB;wEACoE;IACpE,QAAQ,CAAC,SAAS,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACjD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;gFAC4E;IAC5E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B;;8EAE0E;IAC1E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IACzC;;4DAEwD;IACxD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AA2CD;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,CAOlE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,EACjC,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACxH,WAAW,CA2Cb"}
|
package/dist/yaml.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yaml.d.ts","sourceRoot":"","sources":["../src/yaml.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAqCH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"yaml.d.ts","sourceRoot":"","sources":["../src/yaml.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAqCH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CA0H/D;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,SAAI,GAAG,MAAM,CAG7E;AAMD;;;GAGG;AACH,qBAAa,cAAe,SAAQ,KAAK;IACvC,gEAAgE;IAChE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,YAAY,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAIxC;CACF;AAmID;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQlE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAO1D;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAc5D;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAwBlD"}
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
import { listInstalledLexicons } from "../plugins";
|
|
10
10
|
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
11
11
|
import { existsSync, readFileSync } from "node:fs";
|
|
12
|
-
import { join } from "node:path";
|
|
12
|
+
import { basename, join } from "node:path";
|
|
13
13
|
import { tmpdir } from "node:os";
|
|
14
14
|
|
|
15
15
|
describe("importCommand", () => {
|
|
@@ -269,7 +269,7 @@ describe("importCommand", () => {
|
|
|
269
269
|
expect(content).toContain("Bucket");
|
|
270
270
|
});
|
|
271
271
|
|
|
272
|
-
test("
|
|
272
|
+
test("writes a large CloudFormation template to one main.ts", async () => {
|
|
273
273
|
const template = {
|
|
274
274
|
AWSTemplateFormatVersion: "2010-09-09",
|
|
275
275
|
Resources: {
|
|
@@ -289,8 +289,9 @@ describe("importCommand", () => {
|
|
|
289
289
|
});
|
|
290
290
|
|
|
291
291
|
expect(result.success).toBe(true);
|
|
292
|
-
//
|
|
293
|
-
|
|
292
|
+
// The aws generator owns its layout: split files would each need the
|
|
293
|
+
// declarations the others hold.
|
|
294
|
+
expect(result.generatedFiles.map((f) => basename(f))).toEqual(["main.ts"]);
|
|
294
295
|
});
|
|
295
296
|
|
|
296
297
|
test("creates index.ts for organized imports", async () => {
|
|
@@ -353,6 +353,28 @@ describe("composite factory interpretation (chant #1023)", () => {
|
|
|
353
353
|
expect(JSON.parse(folded).readersReader.props.Description).toEqual({ GetAtt: ["webBucket", "Arn"] });
|
|
354
354
|
});
|
|
355
355
|
|
|
356
|
+
test("a same-file call result read in an argument is bound for that argument only (chant#3610)", async () => {
|
|
357
|
+
await writeComposite(
|
|
358
|
+
ADMISSIBLE_BODY,
|
|
359
|
+
`export const Reader = Composite((props) => {
|
|
360
|
+
const reader = new Role({ RoleName: props.name, Description: props.bucket.Arn });
|
|
361
|
+
return { reader };
|
|
362
|
+
}, "Reader");`,
|
|
363
|
+
);
|
|
364
|
+
// `plain` reads `web` outside any argument. Under F-Call step 6 that read
|
|
365
|
+
// does not resolve, whichever declarator comes first, so the file runs.
|
|
366
|
+
await writeMain(`
|
|
367
|
+
import { Reader, WebApp } from "../composites";
|
|
368
|
+
export const web = WebApp({ name: "data" });
|
|
369
|
+
export const readers = Reader({ name: "readers", bucket: web.bucket });
|
|
370
|
+
export const plain = { inner: web.bucket };
|
|
371
|
+
`);
|
|
372
|
+
|
|
373
|
+
const result = await build(srcDir, [specSerializer], undefined, { fold: true, lexicons: [LEXICON_NAME] });
|
|
374
|
+
|
|
375
|
+
expect(result.foldDecisions.map((d) => d.mode)).toEqual(["run"]);
|
|
376
|
+
});
|
|
377
|
+
|
|
356
378
|
test("provenance is stamped from the source's own composite name", async () => {
|
|
357
379
|
await writeComposite(ADMISSIBLE_BODY);
|
|
358
380
|
await writeMain(CALL_WEBAPP);
|
|
@@ -86,6 +86,29 @@ describe("a host's composite registration form (chant#2442)", () => {
|
|
|
86
86
|
});
|
|
87
87
|
});
|
|
88
88
|
|
|
89
|
+
test("a host composite's result read inside an argument folds (chant#3610)", async () => {
|
|
90
|
+
writeFileSync(
|
|
91
|
+
join(root, "shapes.ts"),
|
|
92
|
+
'import { Bucket, Composite } from "@tsad/shapes";\n' +
|
|
93
|
+
'export const Store = Composite(({ name }) => ({ bucket: new Bucket({ name }) }), "Store");\n' +
|
|
94
|
+
'export const Wrap = Composite(({ inner }) => ({ inner }), "Wrap");\n',
|
|
95
|
+
);
|
|
96
|
+
const file = app(
|
|
97
|
+
'import { Store, Wrap } from "./shapes";\n' +
|
|
98
|
+
'export const s = Store({ name: "a" });\n' +
|
|
99
|
+
"export const w = Wrap({ inner: s.bucket });\n",
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
const verdict = (
|
|
103
|
+
await foldProject([file], [], { lexiconPackages: ["@tsad/shapes"], sandbox: true })
|
|
104
|
+
).get(file)!;
|
|
105
|
+
|
|
106
|
+
expect(verdict.verdict).toBe("fold");
|
|
107
|
+
const exports = Object.fromEntries(verdict.exports!) as Record<string, { bucket?: unknown; inner?: unknown }>;
|
|
108
|
+
// One instance per file: the argument reads the declarator's own result.
|
|
109
|
+
expect(exports.w.inner).toBe(exports.s.bucket);
|
|
110
|
+
});
|
|
111
|
+
|
|
89
112
|
test("a factory outside the subset is still refused rather than invoked", async () => {
|
|
90
113
|
// `S-FactoryParams`: two parameters is outside it, so interpretation
|
|
91
114
|
// declines and the invocation arm refuses under the sandbox.
|
|
@@ -55,6 +55,7 @@ import {
|
|
|
55
55
|
sourceLocationOf,
|
|
56
56
|
type CompositeCallSite,
|
|
57
57
|
type CompositeParamScope,
|
|
58
|
+
type HostBindings,
|
|
58
59
|
} from "./param-deps";
|
|
59
60
|
import { getInterpolationFields, getProvenance, setPathProvenance, setProvenance } from "../provenance";
|
|
60
61
|
import { foldProvenanceOfEntities, type FoldProvenance } from "../fold-provenance";
|
|
@@ -1380,6 +1381,13 @@ interface ResolveCtx {
|
|
|
1380
1381
|
* failure as before #1020 — this is strictly additive.
|
|
1381
1382
|
*/
|
|
1382
1383
|
externals: Map<string, unknown>;
|
|
1384
|
+
/**
|
|
1385
|
+
* INTENTIUS/typescript-as-data#248 — the names in {@link externals} a
|
|
1386
|
+
* lexicon package's export supplied. A props expression that reads one is a
|
|
1387
|
+
* `host-value` origin rather than the file's own `direct` one. Absent on a
|
|
1388
|
+
* context that never records direct-entity provenance.
|
|
1389
|
+
*/
|
|
1390
|
+
hostValues?: ReadonlySet<string>;
|
|
1383
1391
|
/**
|
|
1384
1392
|
* chant #1020 — for a `file`-local import name whose cross-file
|
|
1385
1393
|
* resolution attempt failed, WHY (a located, human-readable reason —
|
|
@@ -1923,16 +1931,22 @@ async function resolveCallArguments(
|
|
|
1923
1931
|
const args: unknown[] = [];
|
|
1924
1932
|
for (const argNode of node.arguments) {
|
|
1925
1933
|
const live = await resolveLiveValue(argNode, ctx);
|
|
1926
|
-
if (live
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
//
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1934
|
+
if (live !== undefined) {
|
|
1935
|
+
args.push(live.value);
|
|
1936
|
+
continue;
|
|
1937
|
+
}
|
|
1938
|
+
// chant#3610 — the bindings hold for this argument only, so a read of the
|
|
1939
|
+
// same name outside any argument still refuses, whatever the declarator order.
|
|
1940
|
+
const bound = await resolveSameFileCallReferences(argNode, ctx);
|
|
1941
|
+
try {
|
|
1942
|
+
// chant #1039 — a folded (non-live) argument may itself contain a
|
|
1943
|
+
// registered intrinsic tagged template; revive it into the real value
|
|
1944
|
+
// before the composite factory actually runs on it (see the "Intrinsic
|
|
1945
|
+
// revival" section below `resolveResourceEntity` uses the same way).
|
|
1946
|
+
args.push(await reviveFoldedValue(fold(argNode, ctx.consts, ctx.intrinsics, ctx.externals), ctx, helperArgs));
|
|
1947
|
+
} finally {
|
|
1948
|
+
for (const name of bound) ctx.externals.delete(name);
|
|
1949
|
+
}
|
|
1936
1950
|
}
|
|
1937
1951
|
return args;
|
|
1938
1952
|
}
|
|
@@ -1954,8 +1968,12 @@ async function resolveCallArguments(
|
|
|
1954
1968
|
* resolution that fails, or gives anything but a Declarable or a composite
|
|
1955
1969
|
* instance, is left alone too, so the reference rejects with the message it
|
|
1956
1970
|
* always had. Inside a factory body `locals` is empty, so nothing here applies.
|
|
1971
|
+
*
|
|
1972
|
+
* chant#3610 — returns the names it bound, which the caller removes from
|
|
1973
|
+
* `externals` once the argument has folded. A host composite's instance
|
|
1974
|
+
* counts as a composite instance here, as it does everywhere else.
|
|
1957
1975
|
*/
|
|
1958
|
-
async function resolveSameFileCallReferences(node: ts.Node, ctx: ResolveCtx): Promise<
|
|
1976
|
+
async function resolveSameFileCallReferences(node: ts.Node, ctx: ResolveCtx): Promise<string[]> {
|
|
1959
1977
|
const names = new Set<string>();
|
|
1960
1978
|
const visit = (n: ts.Node): void => {
|
|
1961
1979
|
if (ts.isIdentifier(n)) {
|
|
@@ -1971,6 +1989,7 @@ async function resolveSameFileCallReferences(node: ts.Node, ctx: ResolveCtx): Pr
|
|
|
1971
1989
|
ts.forEachChild(n, visit);
|
|
1972
1990
|
};
|
|
1973
1991
|
visit(node);
|
|
1992
|
+
const bound: string[] = [];
|
|
1974
1993
|
for (const name of names) {
|
|
1975
1994
|
let resolved: LiveResolution;
|
|
1976
1995
|
try {
|
|
@@ -1978,10 +1997,17 @@ async function resolveSameFileCallReferences(node: ts.Node, ctx: ResolveCtx): Pr
|
|
|
1978
1997
|
} catch {
|
|
1979
1998
|
continue;
|
|
1980
1999
|
}
|
|
1981
|
-
if (
|
|
2000
|
+
if (
|
|
2001
|
+
resolved &&
|
|
2002
|
+
(isDeclarable(resolved.value) ||
|
|
2003
|
+
isCompositeInstance(resolved.value) ||
|
|
2004
|
+
hostCompositeName(resolved.value) !== undefined)
|
|
2005
|
+
) {
|
|
1982
2006
|
ctx.externals.set(name, resolved.value);
|
|
2007
|
+
bound.push(name);
|
|
1983
2008
|
}
|
|
1984
2009
|
}
|
|
2010
|
+
return bound;
|
|
1985
2011
|
}
|
|
1986
2012
|
|
|
1987
2013
|
/** A same-file `const name = Callee(...)` that `fold()` would refuse as a function call used as a value. */
|
|
@@ -3919,13 +3945,19 @@ function paramLocalNames(ctx: ResolveCtx): Set<string> {
|
|
|
3919
3945
|
/**
|
|
3920
3946
|
* chant #1443 — record which build parameters each of a resource's authored
|
|
3921
3947
|
* property expressions reads, before fold substitutes them away. Best-effort
|
|
3922
|
-
* and additive: a
|
|
3923
|
-
*
|
|
3948
|
+
* and additive: a constructor called with no object literal records nothing.
|
|
3949
|
+
*
|
|
3950
|
+
* INTENTIUS/typescript-as-data#248 — and which of them read host code, a
|
|
3951
|
+
* method call, an eager lexicon helper or a lexicon export, so fold provenance
|
|
3952
|
+
* reports those `unknown` rather than `direct`.
|
|
3924
3953
|
*/
|
|
3925
3954
|
function stampParamDependencies(entity: unknown, node: ts.NewExpression, ctx: ResolveCtx): void {
|
|
3926
3955
|
if (typeof entity !== "object" || entity === null) return;
|
|
3927
3956
|
const paramLocals = paramLocalNames(ctx);
|
|
3928
|
-
|
|
3957
|
+
const host: HostBindings = {
|
|
3958
|
+
values: ctx.hostValues ?? new Set(),
|
|
3959
|
+
eagerCalls: new Set(ctx.intrinsics.filter((i) => intrinsicCallFoldsEagerly(i)).map((i) => i.name)),
|
|
3960
|
+
};
|
|
3929
3961
|
// The same argument `foldResource` treats as props: the first object literal.
|
|
3930
3962
|
let propsArg: ts.ObjectLiteralExpression | undefined;
|
|
3931
3963
|
for (const argument of node.arguments ?? []) {
|
|
@@ -3935,7 +3967,7 @@ function stampParamDependencies(entity: unknown, node: ts.NewExpression, ctx: Re
|
|
|
3935
3967
|
}
|
|
3936
3968
|
}
|
|
3937
3969
|
if (!propsArg) return;
|
|
3938
|
-
for (const [path, origin] of Object.entries(collectParamDependencies(propsArg, ctx.consts, paramLocals))) {
|
|
3970
|
+
for (const [path, origin] of Object.entries(collectParamDependencies(propsArg, ctx.consts, paramLocals, host))) {
|
|
3939
3971
|
setPathProvenance(entity, path, origin);
|
|
3940
3972
|
}
|
|
3941
3973
|
}
|
|
@@ -4175,13 +4207,20 @@ async function buildExternals(
|
|
|
4175
4207
|
* a path lexicon's are, never folded as project files.
|
|
4176
4208
|
*/
|
|
4177
4209
|
extraLexiconRoots: readonly string[] = [],
|
|
4178
|
-
): Promise<{
|
|
4210
|
+
): Promise<{
|
|
4211
|
+
externals: Map<string, unknown>;
|
|
4212
|
+
failures: Map<string, string>;
|
|
4213
|
+
liveSources: Set<string>;
|
|
4214
|
+
/** Local names bound to a lexicon package's export (INTENTIUS/typescript-as-data#248). */
|
|
4215
|
+
hostValues: Set<string>;
|
|
4216
|
+
}> {
|
|
4179
4217
|
const lexiconRoots =
|
|
4180
4218
|
extraLexiconRoots.length === 0 ? session.lexiconRoots : [...session.lexiconRoots, ...extraLexiconRoots];
|
|
4181
4219
|
const externals = new Map<string, unknown>();
|
|
4182
4220
|
const failures = new Map<string, string>();
|
|
4183
4221
|
// chant #1044 — see `FoldFileResult.liveSources`.
|
|
4184
4222
|
const liveSources = new Set<string>();
|
|
4223
|
+
const hostValues = new Set<string>();
|
|
4185
4224
|
|
|
4186
4225
|
for (const [localName, binding] of imports) {
|
|
4187
4226
|
// chant #1064 — a named `params` import that resolves to chant-core's own
|
|
@@ -4258,6 +4297,7 @@ async function buildExternals(
|
|
|
4258
4297
|
const lexiconExport = await resolveActiveLexiconExport(binding, file, session);
|
|
4259
4298
|
if (lexiconExport) {
|
|
4260
4299
|
externals.set(localName, lexiconExport.value);
|
|
4300
|
+
hostValues.add(localName);
|
|
4261
4301
|
continue;
|
|
4262
4302
|
}
|
|
4263
4303
|
// Every other bare specifier (a non-lexicon vendor package, a lexicon
|
|
@@ -4292,7 +4332,10 @@ async function buildExternals(
|
|
|
4292
4332
|
// with no `liveSources` edge for the same reason.
|
|
4293
4333
|
if (session.lexiconModules.has(targetPath)) {
|
|
4294
4334
|
const lexiconExport = await resolveActiveLexiconExport(binding, file, session);
|
|
4295
|
-
if (lexiconExport)
|
|
4335
|
+
if (lexiconExport) {
|
|
4336
|
+
externals.set(localName, lexiconExport.value);
|
|
4337
|
+
hostValues.add(localName);
|
|
4338
|
+
}
|
|
4296
4339
|
continue;
|
|
4297
4340
|
}
|
|
4298
4341
|
// chant#2590 — another file of a multi-file path lexicon is a lexicon
|
|
@@ -4310,7 +4353,10 @@ async function buildExternals(
|
|
|
4310
4353
|
// constructor or composite resolves through the import path.
|
|
4311
4354
|
if (inPathLexiconRoot(targetPath, extraLexiconRoots)) {
|
|
4312
4355
|
const value = await packageDataExport(targetPath, binding.imported, session);
|
|
4313
|
-
if (value)
|
|
4356
|
+
if (value) {
|
|
4357
|
+
externals.set(localName, value.value);
|
|
4358
|
+
hostValues.add(localName);
|
|
4359
|
+
}
|
|
4314
4360
|
continue;
|
|
4315
4361
|
}
|
|
4316
4362
|
if (inPathLexiconRoot(targetPath, lexiconRoots)) continue;
|
|
@@ -4359,7 +4405,7 @@ async function buildExternals(
|
|
|
4359
4405
|
}
|
|
4360
4406
|
}
|
|
4361
4407
|
|
|
4362
|
-
return { externals, failures, liveSources };
|
|
4408
|
+
return { externals, failures, liveSources, hostValues };
|
|
4363
4409
|
}
|
|
4364
4410
|
|
|
4365
4411
|
/**
|
|
@@ -4435,7 +4481,12 @@ async function tryFoldFileCore(file: string, session: FoldSession): Promise<Fold
|
|
|
4435
4481
|
if (scan.declarators.length === 0) return { ok: false, reason: "no foldable resource exports" };
|
|
4436
4482
|
|
|
4437
4483
|
const collected = collectImports(sourceFile);
|
|
4438
|
-
const { externals, failures, liveSources } = await buildExternals(
|
|
4484
|
+
const { externals, failures, liveSources, hostValues } = await buildExternals(
|
|
4485
|
+
file,
|
|
4486
|
+
collected.named,
|
|
4487
|
+
collected.namespaces,
|
|
4488
|
+
session,
|
|
4489
|
+
);
|
|
4439
4490
|
|
|
4440
4491
|
const ctx: ResolveCtx = {
|
|
4441
4492
|
file,
|
|
@@ -4446,6 +4497,7 @@ async function tryFoldFileCore(file: string, session: FoldSession): Promise<Fold
|
|
|
4446
4497
|
memo: new Map(),
|
|
4447
4498
|
intrinsics: session.intrinsics,
|
|
4448
4499
|
externals,
|
|
4500
|
+
hostValues,
|
|
4449
4501
|
crossFileFailures: failures,
|
|
4450
4502
|
importCache: session.importCache,
|
|
4451
4503
|
resolvePathCache: session.resolvePathCache,
|
|
@@ -530,3 +530,55 @@ describe("a member destructured from a called chant composite is unknown (chant#
|
|
|
530
530
|
expectAllUnknown(built.foldProvenance, ["namespace", "resourceQuota", "sharedNamespace", "sharedResourceQuota"]);
|
|
531
531
|
});
|
|
532
532
|
});
|
|
533
|
+
|
|
534
|
+
describe("a value host code produced is unknown, never direct (typescript-as-data#248)", () => {
|
|
535
|
+
let testDir: string;
|
|
536
|
+
let srcDir: string;
|
|
537
|
+
let file: string;
|
|
538
|
+
|
|
539
|
+
beforeAll(async () => {
|
|
540
|
+
const dir = join(repoRoot, ".cache", `chant-tsad-248-${process.pid}`);
|
|
541
|
+
await rm(dir, { recursive: true, force: true });
|
|
542
|
+
await mkdir(join(dir, "src"), { recursive: true });
|
|
543
|
+
testDir = await realpath(dir);
|
|
544
|
+
srcDir = join(testDir, "src");
|
|
545
|
+
file = join(srcDir, "main.ts");
|
|
546
|
+
await writeFile(
|
|
547
|
+
file,
|
|
548
|
+
`
|
|
549
|
+
import { Bucket, AWS } from ${JSON.stringify(LEXICON)};
|
|
550
|
+
const upper = "logs".toUpperCase();
|
|
551
|
+
export const bucket = new Bucket({
|
|
552
|
+
BucketName: "x".toUpperCase(),
|
|
553
|
+
Tags: [{ Key: "n", Value: [1, 2].join("-") }],
|
|
554
|
+
ObjectLockEnabled: true,
|
|
555
|
+
});
|
|
556
|
+
export const logs = new Bucket({ BucketName: upper, AccelerateConfiguration: { AccelerationStatus: AWS.Region } });
|
|
557
|
+
`,
|
|
558
|
+
);
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
afterAll(async () => {
|
|
562
|
+
await rm(testDir, { recursive: true, force: true });
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
test("a host call and a host value report unknown with the reference's reasons, as build() does", async () => {
|
|
566
|
+
const verdict = (await foldProject([file], [], { lexicons: [LEXICON_NAME] })).get(file)!;
|
|
567
|
+
expect(verdict.verdict).toBe("fold");
|
|
568
|
+
const fromFold = verdict.foldProvenance!;
|
|
569
|
+
expect(fromFold.bucket.fields).toEqual({
|
|
570
|
+
BucketName: { kind: "unknown", reason: "host-call" },
|
|
571
|
+
ObjectLockEnabled: { kind: "direct" },
|
|
572
|
+
Tags: { kind: "unknown", reason: "host-call" },
|
|
573
|
+
});
|
|
574
|
+
expect(fromFold.logs.fields).toEqual({
|
|
575
|
+
"AccelerateConfiguration.AccelerationStatus": { kind: "unknown", reason: "host-value" },
|
|
576
|
+
BucketName: { kind: "unknown", reason: "host-call" },
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
const built = await build(srcDir, [namesSerializer], undefined, { fold: true, lexicons: [LEXICON_NAME] });
|
|
580
|
+
expect(built.errors).toEqual([]);
|
|
581
|
+
expect(built.foldProvenance.bucket).toEqual(fromFold.bucket);
|
|
582
|
+
expect(built.foldProvenance.logs).toEqual(fromFold.logs);
|
|
583
|
+
});
|
|
584
|
+
});
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
collectParamDependencies,
|
|
8
8
|
collectTagOrigins,
|
|
9
9
|
type CompositeCallSite,
|
|
10
|
+
type HostBindings,
|
|
10
11
|
} from "./param-deps";
|
|
11
12
|
import type { PathOrigin } from "../provenance";
|
|
12
13
|
|
|
@@ -14,7 +15,7 @@ import type { PathOrigin } from "../provenance";
|
|
|
14
15
|
* Collect dependencies for the props of the file's single
|
|
15
16
|
* `export const x = new Type({...})`, which is the shape every case here uses.
|
|
16
17
|
*/
|
|
17
|
-
function depsOf(source: string, paramLocals = ["params"]): Record<string, PathOrigin> {
|
|
18
|
+
function depsOf(source: string, paramLocals = ["params"], host?: HostBindings): Record<string, PathOrigin> {
|
|
18
19
|
const file = ts.createSourceFile("fixture.ts", source, ts.ScriptTarget.Latest, true);
|
|
19
20
|
const consts = collectConsts(file);
|
|
20
21
|
let props: ts.ObjectLiteralExpression | undefined;
|
|
@@ -32,7 +33,7 @@ function depsOf(source: string, paramLocals = ["params"]): Record<string, PathOr
|
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
35
|
if (!props) throw new Error("fixture has no `const x = new Type({...})`");
|
|
35
|
-
return collectParamDependencies(props, consts, new Set(paramLocals));
|
|
36
|
+
return collectParamDependencies(props, consts, new Set(paramLocals), host);
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
const param = (...names: string[]): PathOrigin => ({ kind: "build-param", params: names });
|
|
@@ -411,3 +412,43 @@ describe("argumentLocation (#3597)", () => {
|
|
|
411
412
|
});
|
|
412
413
|
});
|
|
413
414
|
});
|
|
415
|
+
|
|
416
|
+
describe("collectParamDependencies with host bindings (typescript-as-data#248)", () => {
|
|
417
|
+
const host: HostBindings = { values: new Set(["AWS"]), eagerCalls: new Set(["matrix"]) };
|
|
418
|
+
const hostCall: PathOrigin = { kind: "host", reason: "host-call" };
|
|
419
|
+
const hostValue: PathOrigin = { kind: "host", reason: "host-value" };
|
|
420
|
+
|
|
421
|
+
test("a method call on a receiver is a host call, at its own path", () => {
|
|
422
|
+
const source = `export const x = new Thing({ name: "x".toUpperCase(), spec: { tag: [1, 2].join("-") }, fixed: "k" });`;
|
|
423
|
+
expect(depsOf(source, [], host)).toEqual({ name: hostCall, "spec.tag": hostCall });
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
test("an eager lexicon helper is a host call, and a project function is not", () => {
|
|
427
|
+
const source = `export const x = new Thing({ a: matrix("os"), b: helper("os") });`;
|
|
428
|
+
expect(depsOf(source, [], host)).toEqual({ a: hostCall });
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
test("a lexicon export is a host value, through a const and an operator", () => {
|
|
432
|
+
const source = [`const region = AWS.Region;`, "export const x = new Thing({ a: `${region}-x`, b: AWS });"].join("\n");
|
|
433
|
+
expect(depsOf(source, [], host)).toEqual({ a: hostValue, b: hostValue });
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
test("a host read outranks a build parameter the same expression reads", () => {
|
|
437
|
+
const source = `export const x = new Thing({ name: params.name.toUpperCase(), size: params.size });`;
|
|
438
|
+
expect(depsOf(source, ["params"], host)).toEqual({ name: hostCall, size: param("size") });
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
test("a sibling resource, a member name and a property key are not host reads", () => {
|
|
442
|
+
const source = [
|
|
443
|
+
`const logs = new Bucket({ name: "x".toUpperCase() });`,
|
|
444
|
+
`const AWS2 = 1;`,
|
|
445
|
+
`export const x = new Thing({ a: logs.Arn, b: { AWS: 1 }, c: thing.AWS });`,
|
|
446
|
+
].join("\n");
|
|
447
|
+
expect(depsOf(source, [], host)).toEqual({});
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
test("a tag is not read, its interpolations are", () => {
|
|
451
|
+
const source = "export const x = new Thing({ a: Sub`${AWS.Region}`, b: Sub`plain` });";
|
|
452
|
+
expect(depsOf(source, [], { values: new Set(["AWS", "Sub"]), eagerCalls: new Set() })).toEqual({ a: hostValue });
|
|
453
|
+
});
|
|
454
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as ts from "typescript";
|
|
2
|
-
import type { ArgumentLocation, PathOrigin, SourceLocation } from "../provenance";
|
|
2
|
+
import type { ArgumentLocation, HostOriginReason, PathOrigin, SourceLocation } from "../provenance";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Which build parameters an authored props expression READS, per path (chant
|
|
@@ -117,6 +117,94 @@ function readParams(
|
|
|
117
117
|
visit(expr);
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
/**
|
|
121
|
+
* What a file binds to host code, for {@link hostReadOf} (INTENTIUS/typescript-as-data#248).
|
|
122
|
+
*/
|
|
123
|
+
export interface HostBindings {
|
|
124
|
+
/** Local names bound to a value a lexicon package exports. */
|
|
125
|
+
values: ReadonlySet<string>;
|
|
126
|
+
/** Local names of eager lexicon helpers: a call to one is evaluated by host code at fold time. */
|
|
127
|
+
eagerCalls: ReadonlySet<string>;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* The first host read in `expr`, following this file's own top-level consts,
|
|
132
|
+
* or `undefined` when it reads none (INTENTIUS/typescript-as-data#248).
|
|
133
|
+
*
|
|
134
|
+
* A method called on a receiver is `host-call` whatever the receiver is, since
|
|
135
|
+
* fold calls the real method on it; so is a call to an eager lexicon helper. An
|
|
136
|
+
* identifier bound to a lexicon export is `host-value`. A call fold reduces to
|
|
137
|
+
* an envelope (an authoring helper, a call-form intrinsic) or evaluates itself
|
|
138
|
+
* (a project function) is not host code, and only its arguments are read.
|
|
139
|
+
*
|
|
140
|
+
* Syntactic, like {@link readParams}, so it over-reports in one place: both
|
|
141
|
+
* arms of a conditional are read although only one is taken. That errs toward
|
|
142
|
+
* `unknown`, which never licenses an edit `direct` would not.
|
|
143
|
+
*/
|
|
144
|
+
export function hostReadOf(
|
|
145
|
+
expr: ts.Expression,
|
|
146
|
+
consts: ReadonlyMap<string, ts.Expression>,
|
|
147
|
+
paramLocals: ReadonlySet<string>,
|
|
148
|
+
host: HostBindings,
|
|
149
|
+
): HostOriginReason | undefined {
|
|
150
|
+
const followed = new Set<string>();
|
|
151
|
+
let found: HostOriginReason | undefined;
|
|
152
|
+
|
|
153
|
+
const visit = (node: ts.Node): void => {
|
|
154
|
+
if (found) return;
|
|
155
|
+
if (ts.isCallExpression(node)) {
|
|
156
|
+
const callee = unwrap(node.expression);
|
|
157
|
+
if (ts.isPropertyAccessExpression(callee) || ts.isElementAccessExpression(callee)) {
|
|
158
|
+
found = "host-call";
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (ts.isIdentifier(callee) && !consts.has(callee.text) && host.eagerCalls.has(callee.text)) {
|
|
162
|
+
found = "host-call";
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
for (const argument of node.arguments) visit(argument);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
170
|
+
// The member name is not a reference.
|
|
171
|
+
visit(node.expression);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (ts.isIdentifier(node)) {
|
|
176
|
+
if (paramLocals.has(node.text)) return;
|
|
177
|
+
const initializer = consts.get(node.text);
|
|
178
|
+
if (initializer) {
|
|
179
|
+
// A sibling resource is a reference to it, not a read of its props.
|
|
180
|
+
if (ts.isNewExpression(unwrap(initializer)) || followed.has(node.text)) return;
|
|
181
|
+
followed.add(node.text);
|
|
182
|
+
visit(initializer);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (host.values.has(node.text)) found = "host-value";
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (ts.isPropertyAssignment(node)) {
|
|
190
|
+
visit(node.initializer);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// A tag is an intrinsic the lexicon registered, and only its
|
|
195
|
+
// interpolations are read.
|
|
196
|
+
if (ts.isTaggedTemplateExpression(node)) {
|
|
197
|
+
visit(node.template);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
ts.forEachChild(node, visit);
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
visit(expr);
|
|
205
|
+
return found;
|
|
206
|
+
}
|
|
207
|
+
|
|
120
208
|
/**
|
|
121
209
|
* Path → build-parameter origin for one resource's props object literal.
|
|
122
210
|
*
|
|
@@ -129,16 +217,27 @@ function readParams(
|
|
|
129
217
|
* A spread is attributed to the object it spreads INTO, at that object's own
|
|
130
218
|
* path (the entity root for a top-level spread), since which keys it
|
|
131
219
|
* contributes is not knowable here.
|
|
220
|
+
*
|
|
221
|
+
* With `host`, a path whose expression reads host code ({@link hostReadOf})
|
|
222
|
+
* is recorded `host` instead, and that outranks a build parameter it also
|
|
223
|
+
* reads: the value is what host code returned, whatever the parameter was.
|
|
132
224
|
*/
|
|
133
225
|
export function collectParamDependencies(
|
|
134
226
|
props: ts.ObjectLiteralExpression,
|
|
135
227
|
consts: ReadonlyMap<string, ts.Expression>,
|
|
136
228
|
paramLocals: ReadonlySet<string>,
|
|
229
|
+
host?: HostBindings,
|
|
137
230
|
): Record<string, PathOrigin> {
|
|
138
231
|
const out: Record<string, PathOrigin> = {};
|
|
139
|
-
if (paramLocals.size === 0) return out;
|
|
232
|
+
if (paramLocals.size === 0 && !host) return out;
|
|
140
233
|
|
|
141
234
|
const record = (path: string, expr: ts.Expression): void => {
|
|
235
|
+
if (out[path]?.kind === "host") return;
|
|
236
|
+
const reason = host ? hostReadOf(expr, consts, paramLocals, host) : undefined;
|
|
237
|
+
if (reason) {
|
|
238
|
+
out[path] = { kind: "host", reason };
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
142
241
|
const found = new Set<string>();
|
|
143
242
|
readParams(expr, consts, paramLocals, found);
|
|
144
243
|
if (found.size === 0) return;
|
package/src/fold/subset.ts
CHANGED
|
@@ -179,7 +179,7 @@ import { intrinsicCallFolds, intrinsicCallFoldsEagerly, type IntrinsicDef } from
|
|
|
179
179
|
* `spec/VERSION` in the specification repository carries the same string, and
|
|
180
180
|
* the conformance adapter reads this one to fill its `specVersion` field.
|
|
181
181
|
*
|
|
182
|
-
* ## Why 2.
|
|
182
|
+
* ## Why 2.3, and what each version since 1.0 asked for (chant#2445)
|
|
183
183
|
*
|
|
184
184
|
* Raising this is the last step of adopting a rule set, so each version was
|
|
185
185
|
* checked against what chant does rather than against whether the suite is
|
|
@@ -228,6 +228,13 @@ import { intrinsicCallFolds, intrinsicCallFoldsEagerly, type IntrinsicDef } from
|
|
|
228
228
|
* chant already did: a call-bound local exported by name (`export { x }`)
|
|
229
229
|
* resolves by F-Call as the single declarator does, and a same-file call's
|
|
230
230
|
* result read inside an F-Call argument resolves once per file (#3329).
|
|
231
|
+
* - **2.3** says a value host code produced, written at an export or into a
|
|
232
|
+
* field, has an unknown origin and never a direct one. chant reports
|
|
233
|
+
* `host-call` and `host-value` for resource fields since
|
|
234
|
+
* typescript-as-data#248. 2.3 also lets `F-Host-Composite` interpret a
|
|
235
|
+
* composite an active package publishes as TypeScript source, which chant
|
|
236
|
+
* has done since #3247, and adds fixtures for a call result read inside an
|
|
237
|
+
* argument, which chant passes since #3610.
|
|
231
238
|
*
|
|
232
239
|
* `scripts/check-docs-citations.ts` refuses to run when this constant and the
|
|
233
240
|
* rules it loads disagree, so this and the `@intentius/tsad-conformance`
|
|
@@ -239,7 +246,7 @@ import { intrinsicCallFolds, intrinsicCallFoldsEagerly, type IntrinsicDef } from
|
|
|
239
246
|
* Until chant#2470 the rules came from a commit `docs-check.yml` checked out;
|
|
240
247
|
* now they come from the published package, so bumping it is what moves this.
|
|
241
248
|
*/
|
|
242
|
-
export const SPEC_VERSION = "2.
|
|
249
|
+
export const SPEC_VERSION = "2.3";
|
|
243
250
|
|
|
244
251
|
/** The two EVL rule ids a shape violation can be attributed to. */
|
|
245
252
|
export type SubsetRuleId = "EVL001" | "EVL003";
|
|
@@ -103,6 +103,17 @@ describe("classifyFieldOrigin", () => {
|
|
|
103
103
|
});
|
|
104
104
|
});
|
|
105
105
|
|
|
106
|
+
test("a host origin is unknown with that reason, never a direct declaration (typescript-as-data#248)", () => {
|
|
107
|
+
expect(classifyFieldOrigin({ kind: "host", reason: "host-call" }, authored)).toEqual({
|
|
108
|
+
kind: "unknown",
|
|
109
|
+
reason: "host-call",
|
|
110
|
+
});
|
|
111
|
+
expect(classifyFieldOrigin({ kind: "host", reason: "host-value" }, authored)).toEqual({
|
|
112
|
+
kind: "unknown",
|
|
113
|
+
reason: "host-value",
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
106
117
|
test("no origin on an entity no composite expanded is a direct declaration", () => {
|
|
107
118
|
expect(classifyFieldOrigin(undefined, authored)).toEqual({ kind: "direct" });
|
|
108
119
|
});
|
package/src/fold-provenance.ts
CHANGED
|
@@ -80,7 +80,11 @@ import {
|
|
|
80
80
|
} from "./provenance";
|
|
81
81
|
import type { DeepEntityDrift, PropertyDrift } from "./lifecycle/deep-diff";
|
|
82
82
|
|
|
83
|
-
/**
|
|
83
|
+
/**
|
|
84
|
+
* Why a field's origin could not be determined. The first two are facts about
|
|
85
|
+
* the BUILD; the host reasons are facts about the expression, and match the
|
|
86
|
+
* strings the specification's reference implementation reports.
|
|
87
|
+
*/
|
|
84
88
|
export type UnknownOriginReason =
|
|
85
89
|
/**
|
|
86
90
|
* A composite expanded the entity and this build did not interpret its body,
|
|
@@ -94,7 +98,15 @@ export type UnknownOriginReason =
|
|
|
94
98
|
* composite make it" is answerable. A sandboxed child's entities arrive this
|
|
95
99
|
* way: `discovery/entity-wire-codec.ts` drops build metadata over the wire.
|
|
96
100
|
*/
|
|
97
|
-
| "no-provenance"
|
|
101
|
+
| "no-provenance"
|
|
102
|
+
/**
|
|
103
|
+
* INTENTIUS/typescript-as-data#248: host code computed the value, by a method
|
|
104
|
+
* called on a real receiver (`"x".toUpperCase()`, `[1, 2].join("-")`) or an
|
|
105
|
+
* eager lexicon helper. The file wrote the call, not the value.
|
|
106
|
+
*/
|
|
107
|
+
| "host-call"
|
|
108
|
+
/** A value a lexicon package exports, bound by an import (`AWS.Region`, `S3Actions.GetObject`). */
|
|
109
|
+
| "host-value";
|
|
98
110
|
|
|
99
111
|
/**
|
|
100
112
|
* What produced one emitted property path.
|
|
@@ -231,6 +243,10 @@ export function classifyFieldOrigin(
|
|
|
231
243
|
return provenance.composite
|
|
232
244
|
? { kind: "unknown", reason: "composite-not-interpreted" }
|
|
233
245
|
: { kind: "direct" };
|
|
246
|
+
case "host":
|
|
247
|
+
// INTENTIUS/typescript-as-data#248 — host code produced the value, so
|
|
248
|
+
// editing the declaration edits a call, not the value it returned.
|
|
249
|
+
return { kind: "unknown", reason: origin.reason };
|
|
234
250
|
case "build-param":
|
|
235
251
|
// A build parameter governs the expression the AUTHOR wrote in their own
|
|
236
252
|
// source, so the declaration is still theirs to edit.
|
|
@@ -307,6 +323,10 @@ export function unknownOriginText(reason: UnknownOriginReason): string {
|
|
|
307
323
|
return "expanded by a composite whose factory this build did not interpret";
|
|
308
324
|
case "no-provenance":
|
|
309
325
|
return "this build recorded no provenance for the entity";
|
|
326
|
+
case "host-call":
|
|
327
|
+
return "the value is what a host call returned";
|
|
328
|
+
case "host-value":
|
|
329
|
+
return "the value is one a host package exports";
|
|
310
330
|
}
|
|
311
331
|
}
|
|
312
332
|
|
package/src/import/ir-utils.ts
CHANGED
|
@@ -36,10 +36,15 @@ export function hasIntrinsicInValue(value: unknown, name: string): boolean {
|
|
|
36
36
|
*/
|
|
37
37
|
export function irUsesIntrinsic(ir: TemplateIR, name: string): boolean {
|
|
38
38
|
for (const resource of ir.resources) {
|
|
39
|
-
if (
|
|
39
|
+
if (
|
|
40
|
+
hasIntrinsicInValue(resource.properties, name) ||
|
|
41
|
+
hasIntrinsicInValue(resource.metadata, name) ||
|
|
42
|
+
hasIntrinsicInValue(resource.attributes, name)
|
|
43
|
+
) {
|
|
40
44
|
return true;
|
|
41
45
|
}
|
|
42
46
|
}
|
|
47
|
+
if (hasIntrinsicInValue(ir.metadata, name)) return true;
|
|
43
48
|
for (const condition of ir.conditions ?? []) {
|
|
44
49
|
if (hasIntrinsicInValue(condition.expression, name)) {
|
|
45
50
|
return true;
|
package/src/import/parser.ts
CHANGED
|
@@ -9,6 +9,9 @@ export interface ParameterIR {
|
|
|
9
9
|
readonly description?: string;
|
|
10
10
|
readonly defaultValue?: unknown;
|
|
11
11
|
readonly required?: boolean;
|
|
12
|
+
/** What the value is checked against, under the source format's own keys
|
|
13
|
+
* and as written (CloudFormation `AllowedValues`, `MinLength`, `NoEcho`). */
|
|
14
|
+
readonly constraints?: Readonly<Record<string, unknown>>;
|
|
12
15
|
}
|
|
13
16
|
|
|
14
17
|
/**
|
|
@@ -22,6 +25,11 @@ export interface ResourceIR {
|
|
|
22
25
|
/** Name of the condition gating this resource (CloudFormation `Condition`
|
|
23
26
|
* key, or equivalent), when the source template declares one (#2069). */
|
|
24
27
|
readonly condition?: string;
|
|
28
|
+
/** Resource-level attributes other than the condition, under the source
|
|
29
|
+
* format's own keys (CloudFormation `DependsOn`, `DeletionPolicy`,
|
|
30
|
+
* `UpdateReplacePolicy`, `UpdatePolicy`, `CreationPolicy`). Values are
|
|
31
|
+
* parsed value trees, like {@link properties}. */
|
|
32
|
+
readonly attributes?: Readonly<Record<string, unknown>>;
|
|
25
33
|
}
|
|
26
34
|
|
|
27
35
|
/**
|
package/src/provenance.ts
CHANGED
|
@@ -87,6 +87,12 @@ export interface EntityProvenance {
|
|
|
87
87
|
* expression for this path reads no parameter at all. The composite fixes
|
|
88
88
|
* this field, and no argument at the call site moves it.
|
|
89
89
|
*
|
|
90
|
+
* - `host` — the authored expression for this path reads a value host code
|
|
91
|
+
* produced (INTENTIUS/typescript-as-data#248): a method called on a real
|
|
92
|
+
* receiver or an eager lexicon helper (`host-call`), or a value a lexicon
|
|
93
|
+
* package exports (`host-value`). The author wrote the call, not the value,
|
|
94
|
+
* so ./fold-provenance.ts answers `unknown` rather than `direct`.
|
|
95
|
+
*
|
|
90
96
|
* The coarse `composite` and the two fine kinds are not alternatives. A build
|
|
91
97
|
* records `composite` when it expanded a composite without interpreting its
|
|
92
98
|
* body (the run path, an inadmissible factory), and that is why
|
|
@@ -108,7 +114,11 @@ export type PathOrigin =
|
|
|
108
114
|
*/
|
|
109
115
|
arguments?: ArgumentLocation[];
|
|
110
116
|
}
|
|
111
|
-
| { kind: "composite-literal"; composite: string }
|
|
117
|
+
| { kind: "composite-literal"; composite: string }
|
|
118
|
+
| { kind: "host"; reason: HostOriginReason };
|
|
119
|
+
|
|
120
|
+
/** Which host code produced a value: a call it ran, or a value its package exports. */
|
|
121
|
+
export type HostOriginReason = "host-call" | "host-value";
|
|
112
122
|
|
|
113
123
|
/**
|
|
114
124
|
* A place in a source file. `file` is absolute, as
|
|
@@ -270,6 +280,8 @@ export function describePathOrigin(origin: PathOrigin): string {
|
|
|
270
280
|
return `composite ${origin.composite} parameter ${origin.parameters.join(", ")}`;
|
|
271
281
|
case "composite-literal":
|
|
272
282
|
return `composite ${origin.composite} literal`;
|
|
283
|
+
case "host":
|
|
284
|
+
return origin.reason;
|
|
273
285
|
}
|
|
274
286
|
}
|
|
275
287
|
|
|
@@ -118,6 +118,16 @@ describe("walkValue", () => {
|
|
|
118
118
|
});
|
|
119
119
|
});
|
|
120
120
|
|
|
121
|
+
test("an __attrRef envelope naming a property reads the attribute that property's AttrRef carries", () => {
|
|
122
|
+
// A fold writes `db.Endpoint_Address` as the property name; the attribute
|
|
123
|
+
// is `Endpoint.Address`.
|
|
124
|
+
const TestDb = createResource("Test::Db", "test", { Endpoint_Address: "Endpoint.Address" });
|
|
125
|
+
const db = new TestDb({}) as unknown as Declarable;
|
|
126
|
+
const names = new Map<Declarable, string>([[db, "MyDB"]]);
|
|
127
|
+
const value = { __attrRef: { entity: "MyDB", attribute: "Endpoint_Address" } };
|
|
128
|
+
expect(walkValue(value, names, mockVisitor)).toEqual({ __getAtt: ["MyDB", "Endpoint.Address"] });
|
|
129
|
+
});
|
|
130
|
+
|
|
121
131
|
test("resolves standalone __attrRef envelope in plain object", () => {
|
|
122
132
|
const names = new Map<Declarable, string>();
|
|
123
133
|
const value = { __attrRef: { entity: "MyBucket", attribute: "DomainName" } };
|
package/src/serializer-walker.ts
CHANGED
|
@@ -21,6 +21,22 @@ export interface SerializerVisitor {
|
|
|
21
21
|
propertyDeclarable(entity: Declarable, walk: (v: unknown) => unknown): unknown;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* The attribute an `{__attrRef}` envelope names. A fold writes the envelope
|
|
26
|
+
* with the property it read (`db.Endpoint_Address`), and the property's own
|
|
27
|
+
* AttrRef carries the attribute (`Endpoint.Address`); they differ when the
|
|
28
|
+
* attribute has a dot. The envelope's name is kept when the entity or
|
|
29
|
+
* property is not found.
|
|
30
|
+
*/
|
|
31
|
+
function envelopeAttribute(entityName: string, property: string, entityNames: Map<Declarable, string>): string {
|
|
32
|
+
for (const [entity, name] of entityNames) {
|
|
33
|
+
if (name !== entityName) continue;
|
|
34
|
+
const held = (entity as unknown as Record<string, unknown>)[property];
|
|
35
|
+
return isAttrRefLike(held) ? held.attribute : property;
|
|
36
|
+
}
|
|
37
|
+
return property;
|
|
38
|
+
}
|
|
39
|
+
|
|
24
40
|
/**
|
|
25
41
|
* Recursively walk a value, converting AttrRefs, Intrinsics, Declarables,
|
|
26
42
|
* arrays, and objects using the provided visitor.
|
|
@@ -100,7 +116,7 @@ export function walkValue(
|
|
|
100
116
|
// Handle serialized AttrRef envelopes (produced by AttrRef.toJSON() inside intrinsics)
|
|
101
117
|
if (typeof value === "object" && "__attrRef" in value) {
|
|
102
118
|
const ref = (value as { __attrRef: { entity: string; attribute: string } }).__attrRef;
|
|
103
|
-
return visitor.attrRef(ref.entity, ref.attribute);
|
|
119
|
+
return visitor.attrRef(ref.entity, envelopeAttribute(ref.entity, ref.attribute, entityNames));
|
|
104
120
|
}
|
|
105
121
|
|
|
106
122
|
// Handle objects
|
package/src/stack-output.ts
CHANGED
|
@@ -37,6 +37,10 @@ export interface StackOutput extends Declarable {
|
|
|
37
37
|
* `Output.Condition`) — a condition name, or the condition Declarable
|
|
38
38
|
* itself, resolved to its logical name at serialization (#2068/#2069). */
|
|
39
39
|
readonly condition?: string | Declarable;
|
|
40
|
+
/** The output's key in the template, when it is not the export name. A
|
|
41
|
+
* template may use one key for an output and a parameter or resource; a
|
|
42
|
+
* module cannot export both under that name (#3604). */
|
|
43
|
+
readonly name?: string;
|
|
40
44
|
}
|
|
41
45
|
|
|
42
46
|
/** What a wrapping intrinsic's lexicon gets derived from: either a nested
|
|
@@ -112,7 +116,7 @@ export function isStackOutput(value: unknown): value is StackOutput {
|
|
|
112
116
|
*/
|
|
113
117
|
export function stackOutput(
|
|
114
118
|
ref: AttrRef | Intrinsic | string,
|
|
115
|
-
options?: { description?: string; exportName?: string; lexicon?: string; condition?: string | Declarable },
|
|
119
|
+
options?: { description?: string; exportName?: string; lexicon?: string; condition?: string | Declarable; name?: string },
|
|
116
120
|
): StackOutput {
|
|
117
121
|
// Duck-type, not `instanceof` (chant #1137): AttrRef also implements
|
|
118
122
|
// Intrinsic (a global-symbol marker), so `isIntrinsic(ref)` alone already
|
|
@@ -152,6 +156,7 @@ export function stackOutput(
|
|
|
152
156
|
description: options?.description,
|
|
153
157
|
exportName: options?.exportName,
|
|
154
158
|
condition: options?.condition,
|
|
159
|
+
...(options?.name !== undefined ? { name: options.name } : {}),
|
|
155
160
|
};
|
|
156
161
|
|
|
157
162
|
return output;
|
package/src/yaml.test.ts
CHANGED
|
@@ -26,6 +26,12 @@ describe("emitYAML", () => {
|
|
|
26
26
|
expect(emitYAML([undefined, 1], 0)).toBe("\n- null\n- 1");
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
+
test("an empty mapping in a list is an item, not nothing", () => {
|
|
30
|
+
expect(emitYAML([{}], 0)).toBe("\n- {}");
|
|
31
|
+
expect(emitYAML({ egress: [{}] }, 0)).toBe("\negress:\n - {}");
|
|
32
|
+
expect(emitYAML([{ a: undefined }, { b: 1 }], 0)).toBe("\n- {}\n- b: 1");
|
|
33
|
+
});
|
|
34
|
+
|
|
29
35
|
test("booleans", () => {
|
|
30
36
|
expect(emitYAML(true, 0)).toBe("true");
|
|
31
37
|
expect(emitYAML(false, 0)).toBe("false");
|
package/src/yaml.ts
CHANGED
|
@@ -127,6 +127,10 @@ export function emitYAML(value: unknown, indent: number): string {
|
|
|
127
127
|
lines.push(`${prefix} ${key}: ${emitted}`);
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
|
+
} else {
|
|
131
|
+
// An empty mapping is still an item: `egress: [{}]` allows all
|
|
132
|
+
// egress, and dropping it leaves an empty list.
|
|
133
|
+
lines.push(`${prefix}- {}`);
|
|
130
134
|
}
|
|
131
135
|
} else {
|
|
132
136
|
lines.push(`${prefix}- ${emitYAML(item, indent + 1).trimStart()}`);
|