@intentius/tsad-conformance 1.4.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/README.md +59 -0
- package/dist/adapter.d.ts +65 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +2 -0
- package/dist/adapter.js.map +1 -0
- package/dist/bundled.d.ts +5 -0
- package/dist/bundled.d.ts.map +1 -0
- package/dist/bundled.js +28 -0
- package/dist/bundled.js.map +1 -0
- package/dist/fixture.d.ts +49 -0
- package/dist/fixture.d.ts.map +1 -0
- package/dist/fixture.js +95 -0
- package/dist/fixture.js.map +1 -0
- package/dist/host.d.ts +33 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +79 -0
- package/dist/host.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/rules.d.ts +46 -0
- package/dist/rules.d.ts.map +1 -0
- package/dist/rules.js +135 -0
- package/dist/rules.js.map +1 -0
- package/dist/runner.d.ts +26 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +152 -0
- package/dist/runner.js.map +1 -0
- package/fixtures/F-CallLeak/a-call-returns-a-live-object/expect.json +8 -0
- package/fixtures/F-CallLeak/a-call-returns-a-live-object/project/caller.ts +5 -0
- package/fixtures/F-CallLeak/a-call-returns-a-live-object/project/leaky.ts +7 -0
- package/fixtures/F-CallLeak/a-call-returns-a-live-object/project/pure.ts +5 -0
- package/fixtures/F-Cycle/mutual-imports/expect.json +6 -0
- package/fixtures/F-Cycle/mutual-imports/project/a.ts +3 -0
- package/fixtures/F-Cycle/mutual-imports/project/b.ts +3 -0
- package/fixtures/F-Depth/exhaustion-is-a-fallback/expect.json +19 -0
- package/fixtures/F-Depth/exhaustion-is-a-fallback/project/deep.ts +3 -0
- package/fixtures/F-Depth/exhaustion-is-a-fallback/project/rec.ts +3 -0
- package/fixtures/F-Div-Depth/new-inside-function-body/expect.json +21 -0
- package/fixtures/F-Div-Depth/new-inside-function-body/project/app.ts +3 -0
- package/fixtures/F-Div-Depth/new-inside-function-body/project/fn.ts +3 -0
- package/fixtures/F-Div-Eager/referenced-not-called/expect.json +8 -0
- package/fixtures/F-Div-Eager/referenced-not-called/project/app.ts +3 -0
- package/fixtures/F-Div-NsNew/namespace-callee/expect.json +18 -0
- package/fixtures/F-Div-NsNew/namespace-callee/input.ts +3 -0
- package/fixtures/F-Div-Provenance/helper-name-from-project-import/expect.json +20 -0
- package/fixtures/F-Div-Provenance/helper-name-from-project-import/project/app.ts +3 -0
- package/fixtures/F-Div-Provenance/helper-name-from-project-import/project/local.ts +3 -0
- package/fixtures/F-Div-SameFileNew/no-module-graph/expect.json +8 -0
- package/fixtures/F-Div-SameFileNew/no-module-graph/input.ts +5 -0
- package/fixtures/F-Div-Tag/unregistered-tag/expect.json +15 -0
- package/fixtures/F-Div-Tag/unregistered-tag/input.ts +1 -0
- package/fixtures/F-Eval-Array/spread-string-rejected/expect.json +14 -0
- package/fixtures/F-Eval-Array/spread-string-rejected/input.ts +1 -0
- package/fixtures/F-Eval-Binary/division-and-float/expect.json +19 -0
- package/fixtures/F-Eval-Binary/division-and-float/input.ts +1 -0
- package/fixtures/F-Eval-Binary/logical-return-operand/expect.json +20 -0
- package/fixtures/F-Eval-Binary/logical-return-operand/input.ts +1 -0
- package/fixtures/F-Eval-Binary/plus-dispatch/expect.json +19 -0
- package/fixtures/F-Eval-Binary/plus-dispatch/input.ts +1 -0
- package/fixtures/F-Eval-Binary/relational-on-strings/expect.json +18 -0
- package/fixtures/F-Eval-Binary/relational-on-strings/input.ts +1 -0
- package/fixtures/F-Eval-CallEager/evaluated-at-fold-time/expect.json +8 -0
- package/fixtures/F-Eval-CallEager/evaluated-at-fold-time/project/app.ts +3 -0
- package/fixtures/F-Eval-CallEager/not-a-function/expect.json +22 -0
- package/fixtures/F-Eval-CallEager/not-a-function/project/app.ts +3 -0
- package/fixtures/F-Eval-CallEager/not-a-function/project/local.ts +1 -0
- package/fixtures/F-Eval-CallHelper/helper-folds/expect.json +8 -0
- package/fixtures/F-Eval-CallHelper/helper-folds/project/app.ts +3 -0
- package/fixtures/F-Eval-CallHelper/inside-function-body/expect.json +22 -0
- package/fixtures/F-Eval-CallHelper/inside-function-body/project/app.ts +3 -0
- package/fixtures/F-Eval-CallHelper/inside-function-body/project/fn.ts +5 -0
- package/fixtures/F-Eval-CallIntrinsic/call-form-folds/expect.json +8 -0
- package/fixtures/F-Eval-CallIntrinsic/call-form-folds/project/app.ts +3 -0
- package/fixtures/F-Eval-CallIntrinsic/inside-function-body/expect.json +22 -0
- package/fixtures/F-Eval-CallIntrinsic/inside-function-body/project/app.ts +3 -0
- package/fixtures/F-Eval-CallIntrinsic/inside-function-body/project/fn.ts +5 -0
- package/fixtures/F-Eval-CallLocal/local-function-folds/expect.json +7 -0
- package/fixtures/F-Eval-CallLocal/local-function-folds/project/app.ts +3 -0
- package/fixtures/F-Eval-CallLocal/local-function-folds/project/pure.ts +3 -0
- package/fixtures/F-Eval-CallLocal/recursion-folds/expect.json +17 -0
- package/fixtures/F-Eval-CallLocal/recursion-folds/project/rec.ts +3 -0
- package/fixtures/F-Eval-CallLocal/recursion-folds/project/shallow.ts +3 -0
- package/fixtures/F-Eval-CallLocal/spread-argument-rejected/expect.json +20 -0
- package/fixtures/F-Eval-CallLocal/spread-argument-rejected/project/app.ts +5 -0
- package/fixtures/F-Eval-CallLocal/spread-argument-rejected/project/pure.ts +3 -0
- package/fixtures/F-Eval-CallMethod/method-missing/expect.json +17 -0
- package/fixtures/F-Eval-CallMethod/method-missing/input.ts +1 -0
- package/fixtures/F-Eval-CallMethod/null-receiver-dot/expect.json +13 -0
- package/fixtures/F-Eval-CallMethod/null-receiver-dot/input.ts +2 -0
- package/fixtures/F-Eval-CallMethod/null-receiver-optional/expect.json +2 -0
- package/fixtures/F-Eval-CallMethod/null-receiver-optional/input.ts +2 -0
- package/fixtures/F-Eval-CallMethod/real-receiver/expect.json +2 -0
- package/fixtures/F-Eval-CallMethod/real-receiver/input.ts +1 -0
- package/fixtures/F-Eval-Template/number-formatting/expect.json +11 -0
- package/fixtures/F-Eval-Template/number-formatting/input.ts +1 -0
- package/fixtures/F-Eval-Template/tostring-of-non-numbers/expect.json +10 -0
- package/fixtures/F-Eval-Template/tostring-of-non-numbers/input.ts +1 -0
- package/fixtures/F-Eval-Unary/coercion/expect.json +19 -0
- package/fixtures/F-Eval-Unary/coercion/input.ts +1 -0
- package/fixtures/F-Eval-Undefined/bare-undefined/expect.json +2 -0
- package/fixtures/F-Eval-Undefined/bare-undefined/input.ts +1 -0
- package/fixtures/F-Exc-Registry/call-form-without-registry/expect.json +15 -0
- package/fixtures/F-Exc-Registry/call-form-without-registry/input.ts +1 -0
- package/fixtures/F-Host-Closed-vs-Open/package-call-is-closed/expect.json +9 -0
- package/fixtures/F-Host-Closed-vs-Open/package-call-is-closed/project/closed.ts +3 -0
- package/fixtures/F-Host-Closed-vs-Open/package-call-is-closed/project/open.ts +3 -0
- package/fixtures/F-Host-Closed-vs-Open/package-call-is-closed/project/pure.ts +3 -0
- package/fixtures/F-Host-DataExports/plain-data-export/expect.json +8 -0
- package/fixtures/F-Host-DataExports/plain-data-export/project/app.ts +3 -0
- package/fixtures/F-Host-Registry/tag-called-as-function/expect.json +8 -0
- package/fixtures/F-Host-Registry/tag-called-as-function/project/app.ts +3 -0
- package/fixtures/F-Host-Trust/unowned-package/expect.json +6 -0
- package/fixtures/F-Host-Trust/unowned-package/project/app.ts +3 -0
- package/fixtures/F-Namespace/synthetic-namespace-object/expect.json +7 -0
- package/fixtures/F-Namespace/synthetic-namespace-object/project/use.ts +3 -0
- package/fixtures/F-Namespace/synthetic-namespace-object/project/values.ts +2 -0
- package/fixtures/F-NoExports/nothing-to-produce/expect.json +7 -0
- package/fixtures/F-NoExports/nothing-to-produce/project/defaulted.ts +1 -0
- package/fixtures/F-NoExports/nothing-to-produce/project/empty.ts +3 -0
- package/fixtures/F-Prebuild/same-file-construction-shared/expect.json +19 -0
- package/fixtures/F-Prebuild/same-file-construction-shared/project/shared.ts +6 -0
- package/fixtures/F-Profile-DataHost/plain-data-across-files/expect.json +39 -0
- package/fixtures/F-Profile-DataHost/plain-data-across-files/project/defaults.ts +5 -0
- package/fixtures/F-Profile-DataHost/plain-data-across-files/project/service.ts +10 -0
- package/fixtures/F-Seed/seeded-by-its-own-body/expect.json +8 -0
- package/fixtures/F-Seed/seeded-by-its-own-body/project/app.ts +8 -0
- package/fixtures/F-Seed/seeded-by-its-own-body/project/lone.ts +1 -0
- package/fixtures/F-Succ/backward-along-captures/expect.json +26 -0
- package/fixtures/F-Succ/backward-along-captures/project/breaker.ts +10 -0
- package/fixtures/F-Succ/backward-along-captures/project/shared.ts +1 -0
- package/fixtures/F-Succ/backward-along-captures/project/sibling.ts +3 -0
- package/fixtures/F-Succ/forward-into-imports/expect.json +8 -0
- package/fixtures/F-Succ/forward-into-imports/project/app.ts +10 -0
- package/fixtures/F-Succ/forward-into-imports/project/config.ts +1 -0
- package/fixtures/F-Taint/independent-file-still-folds/expect.json +9 -0
- package/fixtures/F-Taint/independent-file-still-folds/project/alone.ts +1 -0
- package/fixtures/F-Taint/independent-file-still-folds/project/app.ts +8 -0
- package/fixtures/F-Total/one-bad-declarator-fails-the-file/expect.json +7 -0
- package/fixtures/F-Total/one-bad-declarator-fails-the-file/project/mixed.ts +3 -0
- package/fixtures/F-Val-Arity/props-attributes-and-spread/expect.json +14 -0
- package/fixtures/F-Val-Arity/props-attributes-and-spread/project/arities.ts +5 -0
- package/fixtures/F-Val-Callable/host-function-as-value/expect.json +16 -0
- package/fixtures/F-Val-Callable/host-function-as-value/project/app.ts +3 -0
- package/fixtures/F-Val-Fate/revive-every-envelope/expect.json +15 -0
- package/fixtures/F-Val-Fate/revive-every-envelope/project/entities.ts +6 -0
- package/fixtures/F-Val-Live/plain-data-is-not-live/expect.json +9 -0
- package/fixtures/F-Val-Live/plain-data-is-not-live/project/breaker.ts +10 -0
- package/fixtures/F-Val-Live/plain-data-is-not-live/project/quiet.ts +3 -0
- package/fixtures/F-Val-Live/plain-data-is-not-live/project/source.ts +5 -0
- package/fixtures/F-Val-Position/attrref-in-host-arguments/expect.json +8 -0
- package/fixtures/F-Val-Position/attrref-in-host-arguments/project/rejected.ts +4 -0
- package/fixtures/F-Val-Undefined/array-element-undefined/expect.json +15 -0
- package/fixtures/F-Val-Undefined/array-element-undefined/input.ts +1 -0
- package/fixtures/F-Val-Undefined/conditional-yields-undefined/expect.json +13 -0
- package/fixtures/F-Val-Undefined/conditional-yields-undefined/input.ts +2 -0
- package/fixtures/F-Val-Undefined/optional-chain-yields-undefined-property/expect.json +13 -0
- package/fixtures/F-Val-Undefined/optional-chain-yields-undefined-property/input.ts +2 -0
- package/fixtures/F-Val-Undefined/property-literal-undefined/expect.json +16 -0
- package/fixtures/F-Val-Undefined/property-literal-undefined/input.ts +1 -0
- package/fixtures/F-Val-Undefined/spread-carries-undefined/expect.json +14 -0
- package/fixtures/F-Val-Undefined/spread-carries-undefined/input.ts +2 -0
- package/fixtures/S-Array/spread/expect.json +1 -0
- package/fixtures/S-Array/spread/input.ts +1 -0
- package/fixtures/S-Binary/arithmetic-and-concat/expect.json +1 -0
- package/fixtures/S-Binary/arithmetic-and-concat/input.ts +1 -0
- package/fixtures/S-Binary/lazy-untaken-unfoldable/expect.json +1 -0
- package/fixtures/S-Binary/lazy-untaken-unfoldable/input.ts +1 -0
- package/fixtures/S-Binary/nullish-coalesce/expect.json +1 -0
- package/fixtures/S-Binary/nullish-coalesce/input.ts +1 -0
- package/fixtures/S-CallLocal/imported-callee-is-shape-valid/expect.json +10 -0
- package/fixtures/S-CallLocal/imported-callee-is-shape-valid/input.ts +3 -0
- package/fixtures/S-Conditional/taken-branch-only/expect.json +1 -0
- package/fixtures/S-Conditional/taken-branch-only/input.ts +1 -0
- package/fixtures/S-ExportDefault/imported-by-sibling/expect.json +30 -0
- package/fixtures/S-ExportDefault/imported-by-sibling/project/app.ts +3 -0
- package/fixtures/S-ExportDefault/imported-by-sibling/project/policy.ts +1 -0
- package/fixtures/S-ExportDefault/plain-object/expect.json +21 -0
- package/fixtures/S-ExportDefault/plain-object/input.ts +1 -0
- package/fixtures/S-Ident/const-chain/expect.json +1 -0
- package/fixtures/S-Ident/const-chain/input.ts +1 -0
- package/fixtures/S-Ident/process/expect.json +1 -0
- package/fixtures/S-Ident/process/input.ts +1 -0
- package/fixtures/S-Ident/unresolved/expect.json +1 -0
- package/fixtures/S-Ident/unresolved/input.ts +1 -0
- package/fixtures/S-Index/dynamic-key/expect.json +1 -0
- package/fixtures/S-Index/dynamic-key/input.ts +1 -0
- package/fixtures/S-Index/literal-key/expect.json +1 -0
- package/fixtures/S-Index/literal-key/input.ts +1 -0
- package/fixtures/S-Literal/null-and-booleans/expect.json +1 -0
- package/fixtures/S-Literal/null-and-booleans/input.ts +1 -0
- package/fixtures/S-Literal/numeric/expect.json +1 -0
- package/fixtures/S-Literal/numeric/input.ts +1 -0
- package/fixtures/S-LocalFunction/arrow-const-call/expect.json +21 -0
- package/fixtures/S-LocalFunction/arrow-const-call/project/label.ts +3 -0
- package/fixtures/S-LocalFunction/function-as-value-still-rejects/expect.json +11 -0
- package/fixtures/S-LocalFunction/function-as-value-still-rejects/input.ts +3 -0
- package/fixtures/S-LocalFunction/same-file-declaration-call/expect.json +19 -0
- package/fixtures/S-LocalFunction/same-file-declaration-call/project/twice.ts +5 -0
- package/fixtures/S-Member/nested/expect.json +1 -0
- package/fixtures/S-Member/nested/input.ts +1 -0
- package/fixtures/S-Member/nullish-plain-refuses/expect.json +1 -0
- package/fixtures/S-Member/nullish-plain-refuses/input.ts +1 -0
- package/fixtures/S-Member/optional-chain/expect.json +1 -0
- package/fixtures/S-Member/optional-chain/input.ts +1 -0
- package/fixtures/S-Object/spread-later-wins/expect.json +1 -0
- package/fixtures/S-Object/spread-later-wins/input.ts +1 -0
- package/fixtures/S-Object/spread-non-object/expect.json +1 -0
- package/fixtures/S-Object/spread-non-object/input.ts +1 -0
- package/fixtures/S-Reject/arrow-as-value/expect.json +1 -0
- package/fixtures/S-Reject/arrow-as-value/input.ts +1 -0
- package/fixtures/S-Reject/call-as-value/expect.json +1 -0
- package/fixtures/S-Reject/call-as-value/input.ts +1 -0
- package/fixtures/S-Template/coercion/expect.json +2 -0
- package/fixtures/S-Template/coercion/input.ts +2 -0
- package/fixtures/S-Template/composite-step-span/expect.json +2 -0
- package/fixtures/S-Template/composite-step-span/input.ts +1 -0
- package/fixtures/S-Template/const-span/expect.json +2 -0
- package/fixtures/S-Template/const-span/input.ts +2 -0
- package/fixtures/S-Template/envelope-span/expect.json +2 -0
- package/fixtures/S-Template/envelope-span/input.ts +2 -0
- package/fixtures/S-Template/nested-construction-span/expect.json +2 -0
- package/fixtures/S-Template/nested-construction-span/input.ts +1 -0
- package/fixtures/S-Template/no-substitution/expect.json +2 -0
- package/fixtures/S-Template/no-substitution/input.ts +1 -0
- package/fixtures/S-Template/unfoldable-span/expect.json +16 -0
- package/fixtures/S-Template/unfoldable-span/input.ts +1 -0
- package/fixtures/S-Unary/not-and-negate/expect.json +1 -0
- package/fixtures/S-Unary/not-and-negate/input.ts +1 -0
- package/fixtures/S-Unclaimed/composite-step/expect.json +3 -0
- package/fixtures/S-Unclaimed/composite-step/input.ts +1 -0
- package/fixtures/S-Unwrap/as-and-parens/expect.json +1 -0
- package/fixtures/S-Unwrap/as-and-parens/input.ts +1 -0
- package/fixtures/UNCOVERED.md +37 -0
- package/package.json +35 -0
- package/spec/VERSION +1 -0
- package/spec/divergence.md +129 -0
- package/spec/grammar.md +277 -0
- package/spec/hosts.md +175 -0
- package/spec/judgments.md +1049 -0
- package/spec/rules.md +102 -0
- package/spec/values.md +247 -0
- package/src/adapter.ts +52 -0
- package/src/adapters/chant.ts +125 -0
- package/src/bundled.ts +27 -0
- package/src/chant-agreement.test.ts +67 -0
- package/src/corpus.test.ts +66 -0
- package/src/corpus.ts +540 -0
- package/src/fixture.ts +117 -0
- package/src/host.ts +105 -0
- package/src/index.ts +6 -0
- package/src/rules.test.ts +50 -0
- package/src/rules.ts +140 -0
- package/src/runner.test.ts +46 -0
- package/src/runner.ts +119 -0
- package/src/version.test.ts +31 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "rules": ["S-SpreadProp", "F-Eval-Object", "F-Div-SpreadType"], "export": "x", "shape": "accept", "fold": "run", "note": "Shape-valid (n is an identifier); the folder rejects once n folds to a number." }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const n = 5; export const x = { ...n };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "rules": ["S-Reject", "F-Eval-Function", "F-Val-Callable"], "export": "x", "shape": "reject", "fold": "run", "note": "A function is never a value." }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const x = () => 1;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "rules": ["S-Reject", "F-Eval-Reject"], "export": "x", "shape": "reject", "fold": "run", "note": "A call has no evaluation case: structurally unrepresentable." }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const x = getId();
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
{ "rules": ["S-Template", "F-Eval-Template", "F-Div-TemplateEnvelope"], "export": "x", "shape": "accept", "fold": "run",
|
|
2
|
+
"note": "The .step idiom in a plain template span. Refused since chant-v0.69.0 (#2397), the fifth and last coercible envelope kind; __symbol cannot reach a plain span." }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const x = `step=${Checkout({}).step}`;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
{ "rules": ["S-Template", "F-Eval-Template", "F-Div-TemplateEnvelope"], "export": "x", "shape": "accept", "fold": "run",
|
|
2
|
+
"note": "A symbolic value (here an attribute reference) inside a plain template span is refused. Shape accepts (bucket.arn is a member access); the folder rejects once the span folds to an envelope. chant-v0.68.0 (#2349) made this a refusal on both paths; before it, both paths produced \"[object Object]\"." }
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
{ "rules": ["S-Template", "F-Eval-Template", "F-Div-TemplateEnvelope"], "export": "x", "shape": "accept", "fold": "run",
|
|
2
|
+
"note": "A nested construction in a plain template span. Refused since chant-v0.69.0 (#2397); before that it coerced to \"[object Object]\" on both paths." }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const x = `img=${new Image({ name: "node:22" })}`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const x = `plain`;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"rules": [
|
|
3
|
+
"S-Template",
|
|
4
|
+
"S-Reject",
|
|
5
|
+
"F-Eval-Reject",
|
|
6
|
+
"F-Reason"
|
|
7
|
+
],
|
|
8
|
+
"export": "x",
|
|
9
|
+
"shape": "reject",
|
|
10
|
+
"fold": "run",
|
|
11
|
+
"rejectAt": {
|
|
12
|
+
"line": 1,
|
|
13
|
+
"column": 24
|
|
14
|
+
},
|
|
15
|
+
"note": "A span outside the subset rejects the template; the rejection points at the span, not the template (F-Reason: a located rejection is a conformance requirement; its wording is not)."
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const x = `id=${getId()}`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "rules": ["S-Unary", "F-Eval-Unary"], "export": "x", "shape": "accept", "fold": "fold", "value": [true, -2] }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const x = [!0, -(2)];
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
{ "rules": ["S-Unclaimed", "S-CompositeStep", "F-Eval-Member"], "export": "x", "shape": "accept", "fold": "fold",
|
|
2
|
+
"value": { "__compositeStep": "Checkout", "args": [{ "v": 4 }] },
|
|
3
|
+
"note": "An unclaimed bare-identifier callee narrowed to .step folds to the composite-step envelope. Claimed callees (a registered helper, an admitted intrinsic) are not unclaimed and take their own S-Call form; the reference ships no host, so nothing claims Checkout here." }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const x = Checkout({ v: 4 }).step;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "rules": ["S-Unwrap", "F-Eval-Unwrap"], "export": "x", "shape": "accept", "fold": "fold", "value": "a" }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const x = (("a" as string) satisfies string)!;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Rules with no conformance fixture yet
|
|
2
|
+
|
|
3
|
+
Deliberate, and this list may only shrink (#8). Each entry names the rule and why it is still uncovered. Remove an entry when its fixture lands; the gate fails if an entry is stale.
|
|
4
|
+
|
|
5
|
+
107 of 138 rules have fixtures. Most of the rules below are uncovered because the corpus is still growing (#24); where a rule needs something the reference implementation does not have, the entry says so.
|
|
6
|
+
|
|
7
|
+
- `F-Rule-Input` — the harness has no rule hook and no findings-as-data fixture kind yet (#101)
|
|
8
|
+
- `F-Rule-Phase` — the harness has no rule hook and no findings-as-data fixture kind yet (#101)
|
|
9
|
+
- `F-Rule-Pure` — the harness has no rule hook and no findings-as-data fixture kind yet (#101)
|
|
10
|
+
- `F-Rule-Finding` — the harness has no rule hook and no findings-as-data fixture kind yet (#101)
|
|
11
|
+
- `F-Rule-Equivalence` — the harness has no rule hook and no findings-as-data fixture kind yet (#101)
|
|
12
|
+
- `F-Rule-Supply` — the harness has no rule hook and no findings-as-data fixture kind yet (#101)
|
|
13
|
+
- `F-Div-Step` — needs `{__compositeStep}`, which has no fate in the reference implementation (no composite factory form)
|
|
14
|
+
- `F-Eval-Interior` — an unresolved chain inside an intrinsic call folds to a symbol only with a registry in scope, and an expression fixture names no host
|
|
15
|
+
- `F-Host-Composite` — needs the composite registration form `Composite(fn, "N")`, which the reference implementation does not have
|
|
16
|
+
- `F-Host-Generality` — says what a host may vary and what it may not; no verdict exercises it
|
|
17
|
+
- `F-IsolatedRefusal` — needs isolation mode, which the reference implementation does not have
|
|
18
|
+
- `F-NoOwnExecution` — measured by chant's `test/leftness` profile; an adapter reports verdicts and cannot observe execution
|
|
19
|
+
- `F-NotProject` — a file inside the host's own module tree; the reference's project is a map with no outside
|
|
20
|
+
- `F-Obs-Counters` — the conformance adapter exposes no counters
|
|
21
|
+
- `F-Obs-Provenance` — an optional capability, reported rather than asserted
|
|
22
|
+
- `F-Val-Domain` — no fixture yet; corpus is #24's
|
|
23
|
+
- `F-Val-Envelope` — no fixture yet; corpus is #24's
|
|
24
|
+
- `F-Val-Symbol-Scope` — no fixture yet; corpus is #24's
|
|
25
|
+
- `S-Disqualify` — no fixture yet; corpus is #24's
|
|
26
|
+
- `S-ExportDestructure` — no fixture yet; corpus is #24's
|
|
27
|
+
- `S-ExportNamed` — no fixture yet; corpus is #24's
|
|
28
|
+
- `S-ExportResource` — no fixture yet; corpus is #24's
|
|
29
|
+
- `S-ExportSingle` — no fixture yet; corpus is #24's
|
|
30
|
+
- `S-ExportTypeOnly` — no fixture yet; corpus is #24's
|
|
31
|
+
- `S-FactoryBody` — needs the composite factory form, which the reference implementation does not have
|
|
32
|
+
- `S-FactoryParams` — needs the composite factory form, which the reference implementation does not have
|
|
33
|
+
- `S-Module` — no fixture yet; corpus is #24's
|
|
34
|
+
- `S-Prop` — no fixture yet; corpus is #24's
|
|
35
|
+
- `S-ReExport` — no fixture yet; corpus is #24's
|
|
36
|
+
- `S-Shorthand` — no fixture yet; corpus is #24's
|
|
37
|
+
- `S-TopConst` — no fixture yet; corpus is #24's
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@intentius/tsad-conformance",
|
|
3
|
+
"version": "1.4.0",
|
|
4
|
+
"description": "The conformance suite of the typescript-as-data specification: fixture loader, runner, and the named hosts. An implementation supplies an adapter and gets a report.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/INTENTIUS/typescript-as-data.git",
|
|
9
|
+
"directory": "packages/conformance"
|
|
10
|
+
},
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"access": "public"
|
|
13
|
+
},
|
|
14
|
+
"type": "module",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"development": "./src/index.ts",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"default": "./dist/index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"main": "./dist/index.js",
|
|
24
|
+
"files": [
|
|
25
|
+
"src/",
|
|
26
|
+
"dist/",
|
|
27
|
+
"fixtures/",
|
|
28
|
+
"spec/"
|
|
29
|
+
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "rm -rf dist fixtures spec && tsc -p tsconfig.build.json && cp -R ../../spec/fixtures fixtures && mkdir spec && cp ../../spec/VERSION ../../spec/grammar.md ../../spec/judgments.md ../../spec/values.md ../../spec/divergence.md ../../spec/hosts.md ../../spec/rules.md spec/",
|
|
32
|
+
"prepack": "npm run build"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {}
|
|
35
|
+
}
|
package/spec/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.4
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Divergence between the shape classifier and the folder
|
|
2
|
+
|
|
3
|
+
Normative draft (#17). One subset, two consumers with unequal information
|
|
4
|
+
(R3). This file states the direction in which they may disagree as a claim
|
|
5
|
+
with a proof obligation, enumerates every known divergence, and states the
|
|
6
|
+
two exceptions with the reason each is tolerated. Derived from
|
|
7
|
+
`subset.ts`'s module doc and `findSubsetViolation`, and `fold()`, at
|
|
8
|
+
`e4074c17` with the chant-v0.63.0 addition.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## F-Direction (the claim)
|
|
13
|
+
|
|
14
|
+
Let `shape(e, ρ)` be the classifier's verdict on expression `e` given an
|
|
15
|
+
optional registry `ρ`, and `fold(e, Γ, ρ)` the folder's, given also an
|
|
16
|
+
environment `Γ`.
|
|
17
|
+
|
|
18
|
+
> **Proposition.** For every `e`, `Γ`, `ρ`: if `fold(e, Γ, ρ)` succeeds, then
|
|
19
|
+
> `shape(e, ρ)` accepts, *except* in the two cases F-Exc-Lazy and
|
|
20
|
+
> F-Exc-Registry below.
|
|
21
|
+
|
|
22
|
+
Equivalently: the classifier may accept what the folder rejects (a *false
|
|
23
|
+
negative* relative to fold, visible only as a later fallback), and must never
|
|
24
|
+
reject what the folder accepts (a *false positive*, visible as a lint error on
|
|
25
|
+
folding code), outside the two named exceptions.
|
|
26
|
+
|
|
27
|
+
**Why this direction.** A false negative costs a fallback the author learns
|
|
28
|
+
about from `[fold:run]`. A false positive costs a lint error on correct
|
|
29
|
+
source, and a lint that cries wolf gets disabled. The classifier is also the
|
|
30
|
+
predicate a downstream tool asks "will this fold?", a tool with no registry
|
|
31
|
+
must get an answer that is safe to act on, which means erring toward "it may
|
|
32
|
+
run" (`subset.ts` module doc, point 2c).
|
|
33
|
+
|
|
34
|
+
**Discharge.** By construction: both consumers import one classifier
|
|
35
|
+
(`subset.ts`), so they cannot disagree on node kinds, operators or key shapes;
|
|
36
|
+
every remaining disagreement is a *resolution* the classifier does not
|
|
37
|
+
perform, enumerated below. And by fixture: one accepting and one rejecting
|
|
38
|
+
fixture per row of F-Div, asserting the classifier's and the folder's verdicts
|
|
39
|
+
side by side (#8, #24). chant's `subset-doc-parity.test.ts` is the precedent.
|
|
40
|
+
|
|
41
|
+
## F-Div (the divergences in the permitted direction)
|
|
42
|
+
|
|
43
|
+
Shape accepts; the folder may reject, because it resolves.
|
|
44
|
+
|
|
45
|
+
| Rule | Shape sees | Folder additionally requires | Row |
|
|
46
|
+
|---|---|---|---|
|
|
47
|
+
| F-Div-Ident | any bare identifier is valid | resolves in `consts` then `externals`; `process` is a pointed rejection | L2.3, L3.6, L3.7 |
|
|
48
|
+
| F-Div-Tag | any tagged-template tag; interior opaque | tag is a registered, tag-foldable intrinsic; interior folds | L2.4 |
|
|
49
|
+
| F-Div-Provenance | a registered helper *name* | the name is bound by an import from chant, not shadowed | L2.11 |
|
|
50
|
+
| F-Div-SpreadType | a spread operand of valid shape | operand folds to an object (object spread) or array (array spread) | L3.4, L3.5 |
|
|
51
|
+
| F-Div-SameFileNew | a bare identifier | if bound to a same-file `new`, only `externals` may answer, and F-Prebuild is what puts the instance there; a folder that cannot construct rejects rather than build a duplicate | L3.8 |
|
|
52
|
+
| F-Div-Nullish | `a.b`, `a[k]` | the object does not fold to `null`/`undefined`; `?.` short-circuits instead (chant-v0.63.0) | L3.10, L3.21 |
|
|
53
|
+
| F-Div-NsNew | `new ⟨Expr⟩(…)` with any callee | the callee is a plain identifier | L3.15 |
|
|
54
|
+
| F-Div-Method | `x.m(…)` | the receiver folds to a real value that is not an envelope and whose `m` is a function | L3.18, L3.19 |
|
|
55
|
+
| F-Div-Step | `⟨call⟩.step` | the callee is an *unclaimed* bare identifier | L3.20 |
|
|
56
|
+
| F-Div-Depth | a `new`, tagged template, helper call, intrinsic call, or `.step` | is not inside a folded function body | L3.16 |
|
|
57
|
+
| F-Div-Eager | a registered eager intrinsic name | resolves to a function; is called, not referenced | L3.17 |
|
|
58
|
+
| F-Div-TemplateEnvelope | a member access or call inside a template span | the span does not fold to an envelope; chant refuses all five reachable kinds since v0.69.0 | L3.23 |
|
|
59
|
+
|
|
60
|
+
Every row is a fallback, never wrong output. That property, a divergence in
|
|
61
|
+
this direction can only lose coverage, is what makes the direction the safe
|
|
62
|
+
one.
|
|
63
|
+
|
|
64
|
+
## F-Exc (the two exceptions)
|
|
65
|
+
|
|
66
|
+
Shape rejects; the folder accepts. Each is stated with why it is tolerated
|
|
67
|
+
rather than fixed.
|
|
68
|
+
|
|
69
|
+
**F-Exc-Lazy.** Short-circuit laziness. The folder evaluates `&&`, `||`,
|
|
70
|
+
`??` and `?:` lazily and never folds the untaken operand; the classifier is
|
|
71
|
+
flow-insensitive and requires every operand to be shape-valid (L2.9, L3.13).
|
|
72
|
+
`false && sideEffect()` folds to `false` and is a lint error. *Tolerated
|
|
73
|
+
because:* a flow-sensitive classifier is an evaluator, and the cost of the
|
|
74
|
+
false positive is a visible lint error on code whose untaken branch is
|
|
75
|
+
suspect anyway. The implementation's own module doc calls it a wart, and a
|
|
76
|
+
specification should not launder the word.
|
|
77
|
+
|
|
78
|
+
**F-Exc-Registry.** Call-form registration without a registry. The
|
|
79
|
+
classifier takes `ρ` as an optional parameter. Given one, its answer for a
|
|
80
|
+
plain call is the folder's own; without one, every plain call is a violation,
|
|
81
|
+
including `Ref(bucket)` that the folder accepts (L2.12, L2.13). *Tolerated
|
|
82
|
+
because:* the registry-less answer is the conservative one, it is a
|
|
83
|
+
parameter rather than a guess, and the lint engine now threads the active
|
|
84
|
+
lexicons' registry through (chant#1106) so the exception is closed in
|
|
85
|
+
practice for `chant lint` while remaining true of the classifier in
|
|
86
|
+
isolation.
|
|
87
|
+
|
|
88
|
+
There is no third exception. An implementation that discovers one has found
|
|
89
|
+
either a bug or a new rule, and must add it here before shipping it.
|
|
90
|
+
|
|
91
|
+
## What this file does not claim
|
|
92
|
+
|
|
93
|
+
That the classifier and the folder agree. They do not, and the enumeration
|
|
94
|
+
above is the point. The claim is narrower and more useful: **every
|
|
95
|
+
disagreement outside F-Exc costs coverage, never correctness**, and the two
|
|
96
|
+
that go the other way are named, bounded, and justified.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Rationale
|
|
101
|
+
|
|
102
|
+
Non-normative. The reasoning that motivated each rule, carried over from the retired `requirements.md` (#46). Keyed by the rule(s) each note supports.
|
|
103
|
+
|
|
104
|
+
**F-Direction** *(was R3. Membership is decided once, by a classifier permitted to err in one direction only)*
|
|
105
|
+
|
|
106
|
+
The subset has exactly one definition: `findSubsetViolation` (`subset.ts:289`),
|
|
107
|
+
shared by the folder and by the lint rules EVL001/EVL003 so the linted subset
|
|
108
|
+
and the folded subset cannot drift (L2.*).
|
|
109
|
+
|
|
110
|
+
**F-Div-*** *(was R3.1. The direction is the requirement, not the agreement)*
|
|
111
|
+
|
|
112
|
+
The two consumers have different information. A lint pass has no binding
|
|
113
|
+
resolver and no lexicon registry; the folder has both. The shape-only
|
|
114
|
+
classifier may accept what the resolving evaluator rejects, and must never
|
|
115
|
+
reject what it accepts. Enumerated divergences in that direction: identifier
|
|
116
|
+
resolution (L2.3), tag registration (L2.4), helper provenance (L2.11),
|
|
117
|
+
spread-source runtime type (L3.4, L3.5), a bare identifier bound to a
|
|
118
|
+
same-file construction (L3.8), and, since chant-v0.63.0, a member read whose
|
|
119
|
+
object resolves to `null`/`undefined` (L3.10; shape-valid, folder refuses).
|
|
120
|
+
|
|
121
|
+
**F-Exc-Lazy, F-Exc-Registry** *(was R3.2. The two exceptions must be stated, not tidied away)*
|
|
122
|
+
|
|
123
|
+
1. **Short-circuit laziness** (L2.9, L3.13). The folder evaluates `&&`, `||`,
|
|
124
|
+
`??` and the conditional lazily; the classifier requires every branch to be
|
|
125
|
+
valid. The implementation's own module doc calls this a wart.
|
|
126
|
+
2. **Intrinsic call-form registration** (L2.12). The classifier takes the
|
|
127
|
+
registry as an optional parameter, exact with one, conservatively rejecting
|
|
128
|
+
without. The parameter exists so a downstream tool can ask "will this fold?"
|
|
129
|
+
without running a fold.
|
package/spec/grammar.md
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# Grammar of the fold subset
|
|
2
|
+
|
|
3
|
+
Normative draft (#12). Identifiers are `S-*` per #6: every production here is
|
|
4
|
+
decidable from syntax alone. Where the folder is stricter than the shape rule
|
|
5
|
+
- because it also resolves names or consults a registry, the production says
|
|
6
|
+
so and names the `F-*` rule (judgments.md) that adds the condition. That is
|
|
7
|
+
the one direction R3.1 permits; a production must never be stricter than the
|
|
8
|
+
folder.
|
|
9
|
+
|
|
10
|
+
Derived from `findSubsetViolation` (`subset.ts:289`), `fold()`
|
|
11
|
+
(`fold.ts:896`), `scanExports` (`fold-import.ts:591`),
|
|
12
|
+
`findFunctionSubsetViolation` and `findFactorySubsetViolation`, at
|
|
13
|
+
`e4074c17`, with the `?.` forms from chant-v0.63.0 (`11572c7a`, #2328). Node kinds are TypeScript's.
|
|
14
|
+
|
|
15
|
+
Notation: `⟨X⟩` is a nonterminal; `|` alternation; `*` zero or more; `+` one
|
|
16
|
+
or more. Terminals are TypeScript tokens or node kinds. Each production cites
|
|
17
|
+
its inventory row.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. Module and statements, the gate
|
|
22
|
+
|
|
23
|
+
**S-Module.** A module is a sequence of top-level statements. The gate
|
|
24
|
+
examines **only statements carrying `export`**. Every other statement, a
|
|
25
|
+
non-exported `let`, a bare call, an `if`, a non-exported class, is neither
|
|
26
|
+
admitted nor a disqualifier: it is invisible to the gate, and its effects are
|
|
27
|
+
never performed (R2). (`fold-import.ts` `scanExports`, the `continue` for
|
|
28
|
+
non-exported statements; L1.1.)
|
|
29
|
+
|
|
30
|
+
**S-TopConst.** `const ⟨Identifier⟩ = ⟨Expr⟩`, exported or not, is a binding
|
|
31
|
+
(R6.6, L5.1). A destructured or uninitialized top-level `const` is not a
|
|
32
|
+
binding: the name is invisible.
|
|
33
|
+
|
|
34
|
+
**S-LocalFunction.** A top-level `function ⟨Identifier⟩ ( ⟨Params⟩ ) ⟨Block⟩`,
|
|
35
|
+
exported or not, and a top-level `const ⟨Identifier⟩ = ⟨Arrow⟩` or
|
|
36
|
+
`= function …`, bind the name to a project-local function (F-Bind). The body
|
|
37
|
+
is judged by S-FnBody at the call, never here; the name used as a value is
|
|
38
|
+
F-Eval-Ident's rejection. Added in `1.2` (#95), after chant was found to
|
|
39
|
+
fold both forms while the text said so for neither.
|
|
40
|
+
|
|
41
|
+
A module is **admitted** when every exported statement matches one of
|
|
42
|
+
S-ExportResource … S-ExportTypeOnly. One S-Disqualify match rejects the whole
|
|
43
|
+
module (R4.1, L1.2–L1.5).
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
S-ExportResource ::= export const ⟨Identifier⟩ = new ⟨Expr⟩ ( ⟨Args⟩ )
|
|
47
|
+
S-ExportSingle ::= export const ⟨Identifier⟩ = ⟨Expr⟩
|
|
48
|
+
S-ExportDestructure ::= export const { ⟨PlainElement⟩+ } = ⟨Expr⟩
|
|
49
|
+
S-ExportNamed ::= export { ( ⟨Identifier⟩ ( as ⟨Identifier⟩ )? )+ }
|
|
50
|
+
S-ReExport ::= export { ( ⟨Identifier⟩ ( as ⟨Identifier⟩ )? )+ } from ⟨StringLiteral⟩
|
|
51
|
+
S-ExportFunction ::= export function ⟨Identifier⟩ ( ⟨Params⟩ ) ⟨Block⟩
|
|
52
|
+
S-ExportDefault ::= export default ⟨Expr⟩ -- data-host; see below
|
|
53
|
+
S-ExportTypeOnly ::= export type { … } | a type-only element of S-ExportNamed / S-ReExport
|
|
54
|
+
|
|
55
|
+
⟨PlainElement⟩ ::= ⟨Identifier⟩ | ⟨PropertyName⟩ : ⟨Identifier⟩ -- no rest, no default, no nesting
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Notes. S-ExportFunction: an overload signature (no body) is skipped, not a
|
|
59
|
+
disqualifier; the bodied declaration that follows is the export. S-ReExport:
|
|
60
|
+
named elements only. S-ExportNamed: a local name must be an identifier, the
|
|
61
|
+
TS 4.5 string module-export-name form disqualifies.
|
|
62
|
+
|
|
63
|
+
S-ExportDefault is the declarator named `default`, admitted in the
|
|
64
|
+
`data-host` profile since `1.2` (#94); in `full` it stays a disqualifier
|
|
65
|
+
until chant admits it, which the profile table records as permitted and not
|
|
66
|
+
required. `export default function` and `export =` disqualify in both.
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
S-Disqualify ::= export default … -- full only; data-host admits S-ExportDefault
|
|
70
|
+
| export default function …
|
|
71
|
+
| export * from …
|
|
72
|
+
| export class …
|
|
73
|
+
| export let … | export var …
|
|
74
|
+
| export const ⟨Identifier⟩ -- no initializer
|
|
75
|
+
| export const [ … ] = … -- array pattern
|
|
76
|
+
| export const { … ⟨rest | default | nested⟩ … } = …
|
|
77
|
+
| export { "…" as ⟨Identifier⟩ }
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 2. Expressions, the classifier
|
|
83
|
+
|
|
84
|
+
`⟨Expr⟩` is any production below. The shape rule is what `findSubsetViolation`
|
|
85
|
+
decides; an **F** note is a condition only the folder can check (R3.1).
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
S-Unwrap ::= ( ⟨Expr⟩ ) | ⟨Expr⟩ as ⟨Type⟩ | ⟨Expr⟩ satisfies ⟨Type⟩ | ⟨Expr⟩ !
|
|
89
|
+
S-Literal ::= ⟨StringLiteral⟩ | ⟨NoSubstitutionTemplateLiteral⟩ | ⟨NumericLiteral⟩ | true | false | null
|
|
90
|
+
S-Undefined ::= undefined
|
|
91
|
+
S-Ident ::= ⟨Identifier⟩
|
|
92
|
+
S-Template ::= ` ⟨text⟩ ( ${ ⟨Expr⟩ } ⟨text⟩ )+ `
|
|
93
|
+
S-Tagged ::= ⟨Identifier⟩ ` … `
|
|
94
|
+
S-Object ::= { ⟨Member⟩* }
|
|
95
|
+
⟨Member⟩ ::= S-Prop | S-Shorthand | S-SpreadProp
|
|
96
|
+
S-Prop ::= ⟨LiteralKey⟩ : ⟨Expr⟩
|
|
97
|
+
S-Shorthand ::= ⟨Identifier⟩
|
|
98
|
+
S-SpreadProp::= ... ⟨Expr⟩
|
|
99
|
+
⟨LiteralKey⟩::= ⟨Identifier⟩ | ⟨StringLiteral⟩ | ⟨NumericLiteral⟩
|
|
100
|
+
S-Array ::= [ ( ⟨Expr⟩ | ... ⟨Expr⟩ )* ]
|
|
101
|
+
S-Member ::= ⟨Expr⟩ ( . | ?. ) ⟨Identifier⟩
|
|
102
|
+
S-Index ::= ⟨Expr⟩ ( [ | ?.[ ) ⟨StringLiteral⟩ | ⟨NumericLiteral⟩ ]
|
|
103
|
+
S-Unary ::= ! ⟨Expr⟩ | - ⟨Expr⟩
|
|
104
|
+
S-Binary ::= ⟨Expr⟩ ⟨BinOp⟩ ⟨Expr⟩
|
|
105
|
+
⟨BinOp⟩ ::= && | || | ?? | + | - | * | / | === | !== | > | < | >= | <=
|
|
106
|
+
S-Conditional ::= ⟨Expr⟩ ? ⟨Expr⟩ : ⟨Expr⟩
|
|
107
|
+
S-New ::= new ⟨Expr⟩ ( ⟨Expr⟩* )
|
|
108
|
+
S-Call ::= S-CallHelper | S-CallIntrinsic | S-CallEager | S-CallMethod | S-CompositeStep
|
|
109
|
+
S-CallHelper ::= ⟨HelperName⟩ ( ⟨Expr⟩* )
|
|
110
|
+
S-CallIntrinsic ::= ⟨Identifier⟩ ( ⟨Expr⟩* ) -- registry-gated
|
|
111
|
+
S-CallEager ::= ⟨Identifier⟩ ( ⟨Expr⟩* ) -- registry-gated
|
|
112
|
+
S-CallMethod ::= ⟨Expr⟩ ( . | ?. ) ⟨Identifier⟩ ( ⟨Expr⟩* )
|
|
113
|
+
S-CompositeStep ::= ⟨UnclaimedCall⟩ . step
|
|
114
|
+
⟨UnclaimedCall⟩ ::= ⟨Identifier⟩ ( ⟨Expr⟩* ) -- see S-Unclaimed
|
|
115
|
+
S-Reject ::= anything else
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Per-production conditions and divergences:
|
|
119
|
+
|
|
120
|
+
| Production | Row | Shape rule | F: what the folder adds |
|
|
121
|
+
|---|---|---|---|
|
|
122
|
+
| S-Unwrap | L2.1 | recurse into the operand |; |
|
|
123
|
+
| S-Literal | L2.2 | admitted | numeric → `Number(text)` |
|
|
124
|
+
| S-Undefined |; | an identifier, shape-valid as S-Ident | folds to `undefined` |
|
|
125
|
+
| S-Ident | L2.3 | always shape-valid | must resolve in `consts` then `externals` (R6.6); a bare `process` is a pointed rejection (R8); a name bound to a same-file `new` resolves only via `externals`, where F-Prebuild placed the single instance (R4.6) |
|
|
126
|
+
| S-Template | L2.5 | every span ∈ ⟨Expr⟩ | spans coerce by `ToString` (R10.4) |
|
|
127
|
+
| S-Tagged | L2.4 | interior **opaque**; not recursed | tag must be a registered, tag-foldable intrinsic; interior folds with unresolved dotted chains kept symbolic |
|
|
128
|
+
| S-Prop | L2.6 | key must be ⟨LiteralKey⟩ (EVL001); value ∈ ⟨Expr⟩ |; |
|
|
129
|
+
| S-Shorthand | L2.6 | always shape-valid | the name resolves as S-Ident |
|
|
130
|
+
| S-SpreadProp | L2.6 | operand ∈ ⟨Expr⟩ | operand must fold to a non-null object (R10.6) |
|
|
131
|
+
| S-Array |; | each element or spread operand ∈ ⟨Expr⟩ | spread operand must be an array (R10.6) |
|
|
132
|
+
| S-Member | L2.15 | object ∈ ⟨Expr⟩, `.` or `?.`; **S-CompositeStep takes precedence** when the member is `step` and the object is a call | on a resource-bound identifier → `{__attrRef}` (R10.3); `.` on `null`/`undefined` → **refused** (R10.2, L3.10); `?.` on `null`/`undefined` → short-circuits the rest of the chain to `undefined` (L3.21) |
|
|
133
|
+
| S-Index | L2.7 | key must be a string or numeric **literal** (EVL003); object ∈ ⟨Expr⟩, `[` or `?.[` | same as S-Member, including the `.`/`?.` distinction |
|
|
134
|
+
| S-Unary | L2.8 | operator ∈ {`!`, `-`} | ECMAScript coercion (R10.1) |
|
|
135
|
+
| S-Binary | L2.8, L2.9 | operator ∈ ⟨BinOp⟩; **both** sides ∈ ⟨Expr⟩ (flow-insensitive) | `&&`/`\|\|`/`??` evaluate lazily; the untaken side is never folded (R3.2) |
|
|
136
|
+
| S-Conditional | L2.9 | all three ∈ ⟨Expr⟩ | only the taken branch is folded (R3.2) |
|
|
137
|
+
| S-New | L2.10 | every argument ∈ ⟨Expr⟩, positionally; **callee shape unconstrained** | callee must be a plain identifier (L3.15, R6.3); refused inside a folded function body (R6.3) |
|
|
138
|
+
| S-CallHelper | L2.11 | name ∈ `FOLDABLE_AUTHORING_HELPERS`; args ∈ ⟨Expr⟩ | name must be bound by an import from chant (R3.3); not shadowed by a local `const`; refused inside a folded function body |
|
|
139
|
+
| S-CallIntrinsic | L2.12 | with a registry: name registered with `foldsAsCall`; **without a registry: S-Reject** | name must resolve through the file's imports; refused inside a folded function body |
|
|
140
|
+
| S-CallEager | L2.13 | with a registry: name registered with `foldsEagerly`; without: S-Reject | callee must resolve to a function; evaluated at fold time (R7.3) |
|
|
141
|
+
| S-CallLocal | L2.17, L5.4 | callee is an identifier this file binds by S-LocalFunction or by an import from a project specifier (`./`, `../`); args ∈ ⟨Expr⟩ | the body must satisfy S-FnBody at the call (F-Eval-CallLocal); a cross-file callee needs the module graph, so an expression-level folder refuses it |
|
|
142
|
+
| S-CallMethod | L2.14 | receiver ∈ ⟨Expr⟩, `.` or `?.`; args ∈ ⟨Expr⟩; method name unconstrained | receiver must fold to a real value, not a symbolic envelope; the named property must be a function (R3.3). Receiver `null`/`undefined`: `.` refuses, `?.` short-circuits (L3.22) |
|
|
143
|
+
| S-CompositeStep | L2.15 | any call, any arguments, member exactly `step` | callee must be an *unclaimed* bare identifier (L3.20); refused inside a folded function body |
|
|
144
|
+
| S-Reject | L2.16 | EVL001 |; |
|
|
145
|
+
|
|
146
|
+
**S-Unclaimed.** A call is *unclaimed* when its callee is a bare identifier
|
|
147
|
+
that no other S-Call form claims. The callee must not be:
|
|
148
|
+
|
|
149
|
+
- a registered authoring helper
|
|
150
|
+
- an intrinsic the registry admits in call or eager form
|
|
151
|
+
- a project-local function the scope binds
|
|
152
|
+
- shadowed by a local `const`
|
|
153
|
+
|
|
154
|
+
Only the bare-identifier part is decidable from syntax. The four conditions
|
|
155
|
+
are resolution, so S-CompositeStep admits any call at shape level and
|
|
156
|
+
F-Eval-Member step 2 applies the full test. S-CompositeStep, F-Div-Step and
|
|
157
|
+
F-Eval-Member all used this term without a definition until #51.
|
|
158
|
+
|
|
159
|
+
**Explicitly outside the subset** (S-Reject at shape level, and rejected by
|
|
160
|
+
the folder): an arrow or function expression as a value (L3.1); class
|
|
161
|
+
expressions; `await`, `yield`; assignment and compound assignment; the comma
|
|
162
|
+
operator; `typeof`, `void`, `delete`, `++`, `--`; `==`, `!=`, `%`, `**`, the
|
|
163
|
+
bitwise operators, `in`, `instanceof`; a computed property name; a
|
|
164
|
+
non-literal element-access key; a call not matching any S-Call form. Optional chaining is
|
|
165
|
+
specified, not merely admitted: since chant-v0.63.0 a `?.` on a nullish object
|
|
166
|
+
produces a chain-short-circuit value that propagates through the remaining
|
|
167
|
+
`.`/`[]`/`!`/`?.()` of the same chain and becomes `undefined` at its end -
|
|
168
|
+
ECMAScript's semantics, implemented rather than coincidental.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## 3. Body sub-grammars
|
|
173
|
+
|
|
174
|
+
Two further statement-level grammars govern what may appear *inside* a
|
|
175
|
+
function the folder evaluates. Both are stricter than S-Module.
|
|
176
|
+
|
|
177
|
+
**S-FnBody**, a project-local function (R6.5, L5.4):
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
S-FnParams ::= ( ⟨Identifier⟩ ( = ⟨Expr⟩ )? | { ⟨PlainElement⟩+ } )* -- no rest, no array pattern
|
|
181
|
+
S-FnBody ::= ⟨Expr⟩
|
|
182
|
+
| { ( const ⟨Identifier⟩ = ⟨Expr⟩ | const { ⟨PlainElement⟩+ } = ⟨Expr⟩ )* ( return ⟨Expr⟩? )? }
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
No generator, no `async`, no early `return`, no `let`/`var`, no uninitialized
|
|
186
|
+
`const`, no other statement kind. A block with no `return` evaluates to
|
|
187
|
+
`undefined`. Inside S-FnBody the expression grammar **loses** S-New, S-Tagged,
|
|
188
|
+
S-CallHelper, S-CallIntrinsic and S-CompositeStep (R6.3, L3.16).
|
|
189
|
+
|
|
190
|
+
**S-FactoryBody**, an interpretable composite factory (R7.2 rules 3–5, L7.3–L7.5):
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
S-FactoryParams ::= ( ⟨Identifier⟩ | { ⟨PlainElement⟩+ } )? -- at most one; no default, no rest
|
|
194
|
+
S-FactoryBody ::= ⟨Expr⟩
|
|
195
|
+
| { ( const … = ⟨Expr⟩ )* return ⟨Expr⟩ } -- must end in return; empty body rejected
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Inside S-FactoryBody the expression grammar **gains** `new` in any value
|
|
199
|
+
position and a call through a bare identifier (a nested composite, a
|
|
200
|
+
registered helper, an opted-in intrinsic), and a method call stays out (per
|
|
201
|
+
the contract above `resolveInterpretableFactory`; `checkFactoryExpression`'s
|
|
202
|
+
exact set is not transcribed here, #44 precondition).
|
|
203
|
+
|
|
204
|
+
The asymmetry between the two. S-FnBody tolerates a missing `return`,
|
|
205
|
+
S-FactoryBody requires one, is R6.5's and is a decision the spec should make
|
|
206
|
+
rather than inherit.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## What this grammar does not decide
|
|
211
|
+
|
|
212
|
+
Resolution (R6.6), registration (R3.2), trust (R2.1), the fold/run verdict and
|
|
213
|
+
its taint (R4, judgments.md), and every semantic rule in R10. A string that
|
|
214
|
+
parses under this grammar is *shape-admissible*; whether it folds is the
|
|
215
|
+
judgments' question.
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Rationale
|
|
220
|
+
|
|
221
|
+
Non-normative. The reasoning that motivated each rule, carried over from the retired `requirements.md` (#46). Keyed by the rule(s) each note supports.
|
|
222
|
+
|
|
223
|
+
**S-Call** *(was R3.3. A call is structurally unrepresentable, with an enumerated set of exceptions)*
|
|
224
|
+
|
|
225
|
+
A function call as a value has no evaluation case, it is absent from the
|
|
226
|
+
mechanism, not forbidden by a rule (L2.16). The spec must enumerate the
|
|
227
|
+
exceptions exhaustively, and say which *kind* each is:
|
|
228
|
+
|
|
229
|
+
| Exception | Kind | Rows |
|
|
230
|
+
|---|---|---|
|
|
231
|
+
| registered authoring helper | closed allowlist, name **and** import provenance | L2.11 |
|
|
232
|
+
| lexicon intrinsic, call form opted in | closed allowlist, per intrinsic | L2.12 |
|
|
233
|
+
| project-local function with a foldable body | open, local; the callee's binding is visible in the file, which is S-CallLocal since `1.2` | L2.17, L5.4 |
|
|
234
|
+
| eagerly-evaluated lexicon function | closed allowlist, evaluates at fold time | L2.13, R7.3 |
|
|
235
|
+
| method call on a real receiver | receiver-type condition, method never checked by name | L2.14, L3.18, L3.19 |
|
|
236
|
+
| `<Identifier>(...).step` | one idiom, member fixed, callee must be unclaimed | L2.15, L3.20 |
|
|
237
|
+
|
|
238
|
+
"The callee is admitted" and "the receiver is admitted" are different
|
|
239
|
+
admissibility rules and an implementer will conflate them.
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
**S-Module** *(was R6. Admissibility is decided at two layers, and is scope-dependent)*
|
|
244
|
+
|
|
245
|
+
The first revision specified only the expression layer.
|
|
246
|
+
|
|
247
|
+
**S-Module, S-Disqualify** *(was R6.1. The statement gate runs first and disqualifies whole files)*
|
|
248
|
+
|
|
249
|
+
`scanExports` (L1.1–L1.6) recognizes exactly: `export const X = new Type(...)`,
|
|
250
|
+
`export const X = <expr>`, `export const {a, b} = <expr>`, `export {a, b}`,
|
|
251
|
+
`export {a, b} from "./m"`, and `export function f() {}`. Anything else
|
|
252
|
+
disqualifies the file: `export default`, `export * from`, an exported class,
|
|
253
|
+
`let`/`var`, a destructured export with a rest, nested or defaulted element.
|
|
254
|
+
`export type {...}` and type-only re-export elements are erased, not
|
|
255
|
+
disqualifiers (L1.6).
|
|
256
|
+
|
|
257
|
+
**§2** *(was R6.2. The expression layer is R3's subject and #12's grammar)*
|
|
258
|
+
|
|
259
|
+
Every expression reachable from an admitted statement is classified by R3's
|
|
260
|
+
single definition. The admissible forms, literals, templates with spans,
|
|
261
|
+
object members with literal keys, element access with literal keys, the
|
|
262
|
+
operator sets, positional `new` arguments, are enumerated by the grammar
|
|
263
|
+
(#12), not here. Inventory rows L2.1, L2.2, L2.5–L2.8, L2.10 remain GAP until
|
|
264
|
+
#12 lands.
|
|
265
|
+
|
|
266
|
+
**S-FnBody, S-FactoryBody** *(was R6.5. Two further statement-level subsets, and an asymmetry between them)*
|
|
267
|
+
|
|
268
|
+
A **project-local function** is admissible (L5.4) when its parameters bind
|
|
269
|
+
plainly, its body is a single expression or `const` declarations followed by
|
|
270
|
+
one `return`, and it is not a generator, async, rest-parameter, early-return,
|
|
271
|
+
or `let`/`var` function. Parameter defaults fold in the callee's scope (L5.6).
|
|
272
|
+
A block body with no `return` evaluates to `undefined` (L5.7).
|
|
273
|
+
|
|
274
|
+
A **composite factory** is admissible (R7.2) under rules 3–5 of the same
|
|
275
|
+
shape, except that its body **must** end in `return` and an empty body is
|
|
276
|
+
rejected (L7.4). The two subsets differ on exactly this point and the spec
|
|
277
|
+
should say why, or fix one.
|