@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.
Files changed (257) hide show
  1. package/README.md +59 -0
  2. package/dist/adapter.d.ts +65 -0
  3. package/dist/adapter.d.ts.map +1 -0
  4. package/dist/adapter.js +2 -0
  5. package/dist/adapter.js.map +1 -0
  6. package/dist/bundled.d.ts +5 -0
  7. package/dist/bundled.d.ts.map +1 -0
  8. package/dist/bundled.js +28 -0
  9. package/dist/bundled.js.map +1 -0
  10. package/dist/fixture.d.ts +49 -0
  11. package/dist/fixture.d.ts.map +1 -0
  12. package/dist/fixture.js +95 -0
  13. package/dist/fixture.js.map +1 -0
  14. package/dist/host.d.ts +33 -0
  15. package/dist/host.d.ts.map +1 -0
  16. package/dist/host.js +79 -0
  17. package/dist/host.js.map +1 -0
  18. package/dist/index.d.ts +7 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +7 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/rules.d.ts +46 -0
  23. package/dist/rules.d.ts.map +1 -0
  24. package/dist/rules.js +135 -0
  25. package/dist/rules.js.map +1 -0
  26. package/dist/runner.d.ts +26 -0
  27. package/dist/runner.d.ts.map +1 -0
  28. package/dist/runner.js +152 -0
  29. package/dist/runner.js.map +1 -0
  30. package/fixtures/F-CallLeak/a-call-returns-a-live-object/expect.json +8 -0
  31. package/fixtures/F-CallLeak/a-call-returns-a-live-object/project/caller.ts +5 -0
  32. package/fixtures/F-CallLeak/a-call-returns-a-live-object/project/leaky.ts +7 -0
  33. package/fixtures/F-CallLeak/a-call-returns-a-live-object/project/pure.ts +5 -0
  34. package/fixtures/F-Cycle/mutual-imports/expect.json +6 -0
  35. package/fixtures/F-Cycle/mutual-imports/project/a.ts +3 -0
  36. package/fixtures/F-Cycle/mutual-imports/project/b.ts +3 -0
  37. package/fixtures/F-Depth/exhaustion-is-a-fallback/expect.json +19 -0
  38. package/fixtures/F-Depth/exhaustion-is-a-fallback/project/deep.ts +3 -0
  39. package/fixtures/F-Depth/exhaustion-is-a-fallback/project/rec.ts +3 -0
  40. package/fixtures/F-Div-Depth/new-inside-function-body/expect.json +21 -0
  41. package/fixtures/F-Div-Depth/new-inside-function-body/project/app.ts +3 -0
  42. package/fixtures/F-Div-Depth/new-inside-function-body/project/fn.ts +3 -0
  43. package/fixtures/F-Div-Eager/referenced-not-called/expect.json +8 -0
  44. package/fixtures/F-Div-Eager/referenced-not-called/project/app.ts +3 -0
  45. package/fixtures/F-Div-NsNew/namespace-callee/expect.json +18 -0
  46. package/fixtures/F-Div-NsNew/namespace-callee/input.ts +3 -0
  47. package/fixtures/F-Div-Provenance/helper-name-from-project-import/expect.json +20 -0
  48. package/fixtures/F-Div-Provenance/helper-name-from-project-import/project/app.ts +3 -0
  49. package/fixtures/F-Div-Provenance/helper-name-from-project-import/project/local.ts +3 -0
  50. package/fixtures/F-Div-SameFileNew/no-module-graph/expect.json +8 -0
  51. package/fixtures/F-Div-SameFileNew/no-module-graph/input.ts +5 -0
  52. package/fixtures/F-Div-Tag/unregistered-tag/expect.json +15 -0
  53. package/fixtures/F-Div-Tag/unregistered-tag/input.ts +1 -0
  54. package/fixtures/F-Eval-Array/spread-string-rejected/expect.json +14 -0
  55. package/fixtures/F-Eval-Array/spread-string-rejected/input.ts +1 -0
  56. package/fixtures/F-Eval-Binary/division-and-float/expect.json +19 -0
  57. package/fixtures/F-Eval-Binary/division-and-float/input.ts +1 -0
  58. package/fixtures/F-Eval-Binary/logical-return-operand/expect.json +20 -0
  59. package/fixtures/F-Eval-Binary/logical-return-operand/input.ts +1 -0
  60. package/fixtures/F-Eval-Binary/plus-dispatch/expect.json +19 -0
  61. package/fixtures/F-Eval-Binary/plus-dispatch/input.ts +1 -0
  62. package/fixtures/F-Eval-Binary/relational-on-strings/expect.json +18 -0
  63. package/fixtures/F-Eval-Binary/relational-on-strings/input.ts +1 -0
  64. package/fixtures/F-Eval-CallEager/evaluated-at-fold-time/expect.json +8 -0
  65. package/fixtures/F-Eval-CallEager/evaluated-at-fold-time/project/app.ts +3 -0
  66. package/fixtures/F-Eval-CallEager/not-a-function/expect.json +22 -0
  67. package/fixtures/F-Eval-CallEager/not-a-function/project/app.ts +3 -0
  68. package/fixtures/F-Eval-CallEager/not-a-function/project/local.ts +1 -0
  69. package/fixtures/F-Eval-CallHelper/helper-folds/expect.json +8 -0
  70. package/fixtures/F-Eval-CallHelper/helper-folds/project/app.ts +3 -0
  71. package/fixtures/F-Eval-CallHelper/inside-function-body/expect.json +22 -0
  72. package/fixtures/F-Eval-CallHelper/inside-function-body/project/app.ts +3 -0
  73. package/fixtures/F-Eval-CallHelper/inside-function-body/project/fn.ts +5 -0
  74. package/fixtures/F-Eval-CallIntrinsic/call-form-folds/expect.json +8 -0
  75. package/fixtures/F-Eval-CallIntrinsic/call-form-folds/project/app.ts +3 -0
  76. package/fixtures/F-Eval-CallIntrinsic/inside-function-body/expect.json +22 -0
  77. package/fixtures/F-Eval-CallIntrinsic/inside-function-body/project/app.ts +3 -0
  78. package/fixtures/F-Eval-CallIntrinsic/inside-function-body/project/fn.ts +5 -0
  79. package/fixtures/F-Eval-CallLocal/local-function-folds/expect.json +7 -0
  80. package/fixtures/F-Eval-CallLocal/local-function-folds/project/app.ts +3 -0
  81. package/fixtures/F-Eval-CallLocal/local-function-folds/project/pure.ts +3 -0
  82. package/fixtures/F-Eval-CallLocal/recursion-folds/expect.json +17 -0
  83. package/fixtures/F-Eval-CallLocal/recursion-folds/project/rec.ts +3 -0
  84. package/fixtures/F-Eval-CallLocal/recursion-folds/project/shallow.ts +3 -0
  85. package/fixtures/F-Eval-CallLocal/spread-argument-rejected/expect.json +20 -0
  86. package/fixtures/F-Eval-CallLocal/spread-argument-rejected/project/app.ts +5 -0
  87. package/fixtures/F-Eval-CallLocal/spread-argument-rejected/project/pure.ts +3 -0
  88. package/fixtures/F-Eval-CallMethod/method-missing/expect.json +17 -0
  89. package/fixtures/F-Eval-CallMethod/method-missing/input.ts +1 -0
  90. package/fixtures/F-Eval-CallMethod/null-receiver-dot/expect.json +13 -0
  91. package/fixtures/F-Eval-CallMethod/null-receiver-dot/input.ts +2 -0
  92. package/fixtures/F-Eval-CallMethod/null-receiver-optional/expect.json +2 -0
  93. package/fixtures/F-Eval-CallMethod/null-receiver-optional/input.ts +2 -0
  94. package/fixtures/F-Eval-CallMethod/real-receiver/expect.json +2 -0
  95. package/fixtures/F-Eval-CallMethod/real-receiver/input.ts +1 -0
  96. package/fixtures/F-Eval-Template/number-formatting/expect.json +11 -0
  97. package/fixtures/F-Eval-Template/number-formatting/input.ts +1 -0
  98. package/fixtures/F-Eval-Template/tostring-of-non-numbers/expect.json +10 -0
  99. package/fixtures/F-Eval-Template/tostring-of-non-numbers/input.ts +1 -0
  100. package/fixtures/F-Eval-Unary/coercion/expect.json +19 -0
  101. package/fixtures/F-Eval-Unary/coercion/input.ts +1 -0
  102. package/fixtures/F-Eval-Undefined/bare-undefined/expect.json +2 -0
  103. package/fixtures/F-Eval-Undefined/bare-undefined/input.ts +1 -0
  104. package/fixtures/F-Exc-Registry/call-form-without-registry/expect.json +15 -0
  105. package/fixtures/F-Exc-Registry/call-form-without-registry/input.ts +1 -0
  106. package/fixtures/F-Host-Closed-vs-Open/package-call-is-closed/expect.json +9 -0
  107. package/fixtures/F-Host-Closed-vs-Open/package-call-is-closed/project/closed.ts +3 -0
  108. package/fixtures/F-Host-Closed-vs-Open/package-call-is-closed/project/open.ts +3 -0
  109. package/fixtures/F-Host-Closed-vs-Open/package-call-is-closed/project/pure.ts +3 -0
  110. package/fixtures/F-Host-DataExports/plain-data-export/expect.json +8 -0
  111. package/fixtures/F-Host-DataExports/plain-data-export/project/app.ts +3 -0
  112. package/fixtures/F-Host-Registry/tag-called-as-function/expect.json +8 -0
  113. package/fixtures/F-Host-Registry/tag-called-as-function/project/app.ts +3 -0
  114. package/fixtures/F-Host-Trust/unowned-package/expect.json +6 -0
  115. package/fixtures/F-Host-Trust/unowned-package/project/app.ts +3 -0
  116. package/fixtures/F-Namespace/synthetic-namespace-object/expect.json +7 -0
  117. package/fixtures/F-Namespace/synthetic-namespace-object/project/use.ts +3 -0
  118. package/fixtures/F-Namespace/synthetic-namespace-object/project/values.ts +2 -0
  119. package/fixtures/F-NoExports/nothing-to-produce/expect.json +7 -0
  120. package/fixtures/F-NoExports/nothing-to-produce/project/defaulted.ts +1 -0
  121. package/fixtures/F-NoExports/nothing-to-produce/project/empty.ts +3 -0
  122. package/fixtures/F-Prebuild/same-file-construction-shared/expect.json +19 -0
  123. package/fixtures/F-Prebuild/same-file-construction-shared/project/shared.ts +6 -0
  124. package/fixtures/F-Profile-DataHost/plain-data-across-files/expect.json +39 -0
  125. package/fixtures/F-Profile-DataHost/plain-data-across-files/project/defaults.ts +5 -0
  126. package/fixtures/F-Profile-DataHost/plain-data-across-files/project/service.ts +10 -0
  127. package/fixtures/F-Seed/seeded-by-its-own-body/expect.json +8 -0
  128. package/fixtures/F-Seed/seeded-by-its-own-body/project/app.ts +8 -0
  129. package/fixtures/F-Seed/seeded-by-its-own-body/project/lone.ts +1 -0
  130. package/fixtures/F-Succ/backward-along-captures/expect.json +26 -0
  131. package/fixtures/F-Succ/backward-along-captures/project/breaker.ts +10 -0
  132. package/fixtures/F-Succ/backward-along-captures/project/shared.ts +1 -0
  133. package/fixtures/F-Succ/backward-along-captures/project/sibling.ts +3 -0
  134. package/fixtures/F-Succ/forward-into-imports/expect.json +8 -0
  135. package/fixtures/F-Succ/forward-into-imports/project/app.ts +10 -0
  136. package/fixtures/F-Succ/forward-into-imports/project/config.ts +1 -0
  137. package/fixtures/F-Taint/independent-file-still-folds/expect.json +9 -0
  138. package/fixtures/F-Taint/independent-file-still-folds/project/alone.ts +1 -0
  139. package/fixtures/F-Taint/independent-file-still-folds/project/app.ts +8 -0
  140. package/fixtures/F-Total/one-bad-declarator-fails-the-file/expect.json +7 -0
  141. package/fixtures/F-Total/one-bad-declarator-fails-the-file/project/mixed.ts +3 -0
  142. package/fixtures/F-Val-Arity/props-attributes-and-spread/expect.json +14 -0
  143. package/fixtures/F-Val-Arity/props-attributes-and-spread/project/arities.ts +5 -0
  144. package/fixtures/F-Val-Callable/host-function-as-value/expect.json +16 -0
  145. package/fixtures/F-Val-Callable/host-function-as-value/project/app.ts +3 -0
  146. package/fixtures/F-Val-Fate/revive-every-envelope/expect.json +15 -0
  147. package/fixtures/F-Val-Fate/revive-every-envelope/project/entities.ts +6 -0
  148. package/fixtures/F-Val-Live/plain-data-is-not-live/expect.json +9 -0
  149. package/fixtures/F-Val-Live/plain-data-is-not-live/project/breaker.ts +10 -0
  150. package/fixtures/F-Val-Live/plain-data-is-not-live/project/quiet.ts +3 -0
  151. package/fixtures/F-Val-Live/plain-data-is-not-live/project/source.ts +5 -0
  152. package/fixtures/F-Val-Position/attrref-in-host-arguments/expect.json +8 -0
  153. package/fixtures/F-Val-Position/attrref-in-host-arguments/project/rejected.ts +4 -0
  154. package/fixtures/F-Val-Undefined/array-element-undefined/expect.json +15 -0
  155. package/fixtures/F-Val-Undefined/array-element-undefined/input.ts +1 -0
  156. package/fixtures/F-Val-Undefined/conditional-yields-undefined/expect.json +13 -0
  157. package/fixtures/F-Val-Undefined/conditional-yields-undefined/input.ts +2 -0
  158. package/fixtures/F-Val-Undefined/optional-chain-yields-undefined-property/expect.json +13 -0
  159. package/fixtures/F-Val-Undefined/optional-chain-yields-undefined-property/input.ts +2 -0
  160. package/fixtures/F-Val-Undefined/property-literal-undefined/expect.json +16 -0
  161. package/fixtures/F-Val-Undefined/property-literal-undefined/input.ts +1 -0
  162. package/fixtures/F-Val-Undefined/spread-carries-undefined/expect.json +14 -0
  163. package/fixtures/F-Val-Undefined/spread-carries-undefined/input.ts +2 -0
  164. package/fixtures/S-Array/spread/expect.json +1 -0
  165. package/fixtures/S-Array/spread/input.ts +1 -0
  166. package/fixtures/S-Binary/arithmetic-and-concat/expect.json +1 -0
  167. package/fixtures/S-Binary/arithmetic-and-concat/input.ts +1 -0
  168. package/fixtures/S-Binary/lazy-untaken-unfoldable/expect.json +1 -0
  169. package/fixtures/S-Binary/lazy-untaken-unfoldable/input.ts +1 -0
  170. package/fixtures/S-Binary/nullish-coalesce/expect.json +1 -0
  171. package/fixtures/S-Binary/nullish-coalesce/input.ts +1 -0
  172. package/fixtures/S-CallLocal/imported-callee-is-shape-valid/expect.json +10 -0
  173. package/fixtures/S-CallLocal/imported-callee-is-shape-valid/input.ts +3 -0
  174. package/fixtures/S-Conditional/taken-branch-only/expect.json +1 -0
  175. package/fixtures/S-Conditional/taken-branch-only/input.ts +1 -0
  176. package/fixtures/S-ExportDefault/imported-by-sibling/expect.json +30 -0
  177. package/fixtures/S-ExportDefault/imported-by-sibling/project/app.ts +3 -0
  178. package/fixtures/S-ExportDefault/imported-by-sibling/project/policy.ts +1 -0
  179. package/fixtures/S-ExportDefault/plain-object/expect.json +21 -0
  180. package/fixtures/S-ExportDefault/plain-object/input.ts +1 -0
  181. package/fixtures/S-Ident/const-chain/expect.json +1 -0
  182. package/fixtures/S-Ident/const-chain/input.ts +1 -0
  183. package/fixtures/S-Ident/process/expect.json +1 -0
  184. package/fixtures/S-Ident/process/input.ts +1 -0
  185. package/fixtures/S-Ident/unresolved/expect.json +1 -0
  186. package/fixtures/S-Ident/unresolved/input.ts +1 -0
  187. package/fixtures/S-Index/dynamic-key/expect.json +1 -0
  188. package/fixtures/S-Index/dynamic-key/input.ts +1 -0
  189. package/fixtures/S-Index/literal-key/expect.json +1 -0
  190. package/fixtures/S-Index/literal-key/input.ts +1 -0
  191. package/fixtures/S-Literal/null-and-booleans/expect.json +1 -0
  192. package/fixtures/S-Literal/null-and-booleans/input.ts +1 -0
  193. package/fixtures/S-Literal/numeric/expect.json +1 -0
  194. package/fixtures/S-Literal/numeric/input.ts +1 -0
  195. package/fixtures/S-LocalFunction/arrow-const-call/expect.json +21 -0
  196. package/fixtures/S-LocalFunction/arrow-const-call/project/label.ts +3 -0
  197. package/fixtures/S-LocalFunction/function-as-value-still-rejects/expect.json +11 -0
  198. package/fixtures/S-LocalFunction/function-as-value-still-rejects/input.ts +3 -0
  199. package/fixtures/S-LocalFunction/same-file-declaration-call/expect.json +19 -0
  200. package/fixtures/S-LocalFunction/same-file-declaration-call/project/twice.ts +5 -0
  201. package/fixtures/S-Member/nested/expect.json +1 -0
  202. package/fixtures/S-Member/nested/input.ts +1 -0
  203. package/fixtures/S-Member/nullish-plain-refuses/expect.json +1 -0
  204. package/fixtures/S-Member/nullish-plain-refuses/input.ts +1 -0
  205. package/fixtures/S-Member/optional-chain/expect.json +1 -0
  206. package/fixtures/S-Member/optional-chain/input.ts +1 -0
  207. package/fixtures/S-Object/spread-later-wins/expect.json +1 -0
  208. package/fixtures/S-Object/spread-later-wins/input.ts +1 -0
  209. package/fixtures/S-Object/spread-non-object/expect.json +1 -0
  210. package/fixtures/S-Object/spread-non-object/input.ts +1 -0
  211. package/fixtures/S-Reject/arrow-as-value/expect.json +1 -0
  212. package/fixtures/S-Reject/arrow-as-value/input.ts +1 -0
  213. package/fixtures/S-Reject/call-as-value/expect.json +1 -0
  214. package/fixtures/S-Reject/call-as-value/input.ts +1 -0
  215. package/fixtures/S-Template/coercion/expect.json +2 -0
  216. package/fixtures/S-Template/coercion/input.ts +2 -0
  217. package/fixtures/S-Template/composite-step-span/expect.json +2 -0
  218. package/fixtures/S-Template/composite-step-span/input.ts +1 -0
  219. package/fixtures/S-Template/const-span/expect.json +2 -0
  220. package/fixtures/S-Template/const-span/input.ts +2 -0
  221. package/fixtures/S-Template/envelope-span/expect.json +2 -0
  222. package/fixtures/S-Template/envelope-span/input.ts +2 -0
  223. package/fixtures/S-Template/nested-construction-span/expect.json +2 -0
  224. package/fixtures/S-Template/nested-construction-span/input.ts +1 -0
  225. package/fixtures/S-Template/no-substitution/expect.json +2 -0
  226. package/fixtures/S-Template/no-substitution/input.ts +1 -0
  227. package/fixtures/S-Template/unfoldable-span/expect.json +16 -0
  228. package/fixtures/S-Template/unfoldable-span/input.ts +1 -0
  229. package/fixtures/S-Unary/not-and-negate/expect.json +1 -0
  230. package/fixtures/S-Unary/not-and-negate/input.ts +1 -0
  231. package/fixtures/S-Unclaimed/composite-step/expect.json +3 -0
  232. package/fixtures/S-Unclaimed/composite-step/input.ts +1 -0
  233. package/fixtures/S-Unwrap/as-and-parens/expect.json +1 -0
  234. package/fixtures/S-Unwrap/as-and-parens/input.ts +1 -0
  235. package/fixtures/UNCOVERED.md +37 -0
  236. package/package.json +35 -0
  237. package/spec/VERSION +1 -0
  238. package/spec/divergence.md +129 -0
  239. package/spec/grammar.md +277 -0
  240. package/spec/hosts.md +175 -0
  241. package/spec/judgments.md +1049 -0
  242. package/spec/rules.md +102 -0
  243. package/spec/values.md +247 -0
  244. package/src/adapter.ts +52 -0
  245. package/src/adapters/chant.ts +125 -0
  246. package/src/bundled.ts +27 -0
  247. package/src/chant-agreement.test.ts +67 -0
  248. package/src/corpus.test.ts +66 -0
  249. package/src/corpus.ts +540 -0
  250. package/src/fixture.ts +117 -0
  251. package/src/host.ts +105 -0
  252. package/src/index.ts +6 -0
  253. package/src/rules.test.ts +50 -0
  254. package/src/rules.ts +140 -0
  255. package/src/runner.test.ts +46 -0
  256. package/src/runner.ts +119 -0
  257. package/src/version.test.ts +31 -0
package/dist/rules.js ADDED
@@ -0,0 +1,135 @@
1
+ /**
2
+ * #34 — the rule index, and the check a downstream document runs against it.
3
+ *
4
+ * chant's documentation describes the mechanism this specification owns. A
5
+ * subset change that lands here can leave that prose describing the old
6
+ * subset, and chant#2306 was three such claims, one in a shape chant's own
7
+ * parity gate could not see because it only looked at fenced blocks under
8
+ * headings. This gate looks at rule identifiers instead: every `S-*` or
9
+ * `F-*` a document cites must exist at the specification version the
10
+ * document's implementation declares, and where the document quotes a rule,
11
+ * the quote must be the rule's own text.
12
+ *
13
+ * Two things a document can do, and what each is held to:
14
+ *
15
+ * - Mention an identifier in prose, `F-Depth`. It must be defined. Nothing
16
+ * about the surrounding claim is checked; the identifier is a link, and a
17
+ * link to nothing is the failure.
18
+ * - Quote a rule, as a blockquote directly under a marker line. The marker
19
+ * is a comment on a line of its own whose content is `rule: F-Depth`, in
20
+ * MDX's comment form or HTML's, and the blockquote follows it:
21
+ *
22
+ * > The rule's text, or its opening, verbatim.
23
+ *
24
+ * The quoted text must occur verbatim in the rule's normative text. A
25
+ * paraphrase is a claim the gate cannot check, so it is not accepted where a
26
+ * quote was promised.
27
+ */
28
+ import { readFileSync } from "node:fs";
29
+ import { join } from "node:path";
30
+ /** The five files that define rules, in reading order. The same list `spec/fixtures.test.ts` gates on. */
31
+ export const RULE_FILES = ["grammar.md", "judgments.md", "values.md", "divergence.md", "hosts.md", "rules.md"];
32
+ const DEFINITION = [
33
+ /^#{1,6}\s+([SF]-[A-Za-z0-9-]+)\b/,
34
+ /^\*\*([SF]-[A-Za-z0-9-]+)[.\s(]/,
35
+ /^\|\s*([SF]-[A-Za-z0-9-]+)\s*\|/,
36
+ /^\s*([SF]-[A-Za-z0-9-]+)\s*::=/,
37
+ ];
38
+ const collapse = (s) => s.replace(/\s+/g, " ").trim();
39
+ /** Every rule the specification defines, with its text. `specDir` holds the rule files and `VERSION`. */
40
+ export function loadRules(specDir) {
41
+ const version = readFileSync(join(specDir, "VERSION"), "utf8").trim();
42
+ const rules = new Map();
43
+ for (const file of RULE_FILES) {
44
+ const lines = readFileSync(join(specDir, file), "utf8").split("\n");
45
+ let current;
46
+ const flush = () => {
47
+ if (!current)
48
+ return;
49
+ const text = collapse(current.body.join("\n"));
50
+ // A rule may be defined in more than one place (a table row and a
51
+ // rationale paragraph). The first definition wins; later ones append.
52
+ const prior = rules.get(current.id);
53
+ rules.set(current.id, { id: current.id, file, text: prior ? `${prior.text} ${text}` : text });
54
+ current = undefined;
55
+ };
56
+ for (const line of lines) {
57
+ const id = DEFINITION.map((re) => re.exec(line)?.[1]).find(Boolean);
58
+ if (id) {
59
+ flush();
60
+ current = { id, body: [line] };
61
+ continue;
62
+ }
63
+ if (/^#{1,6}\s/.test(line) || /^---\s*$/.test(line)) {
64
+ flush();
65
+ continue;
66
+ }
67
+ current?.body.push(line);
68
+ }
69
+ flush();
70
+ }
71
+ return { version, rules };
72
+ }
73
+ const IDENTIFIER = /\b([SF]-[A-Z][A-Za-z0-9]*(?:-[A-Za-z0-9]+)*)\b/g;
74
+ const MARKER = /^\s*(?:\{\/\*|<!--)\s*rule:\s*([SF]-[A-Za-z0-9-]+)\s*(?:\*\/\}|-->)\s*$/;
75
+ /**
76
+ * Check one document's citations against the rule index.
77
+ *
78
+ * @param declared the specification version the document's implementation
79
+ * declares, compared against the index's; `undefined` skips the comparison
80
+ * and is reported as nothing, since an undeclared version is #18's concern
81
+ * and not this gate's.
82
+ */
83
+ export function checkCitations(document, index, declared) {
84
+ const findings = [];
85
+ // Same major, minor not ahead of the index: the policy says an addition
86
+ // leaves an older minor's rules unchanged, so a document written against
87
+ // 1.0 is held to 1.1's index. A different major, or a declaration ahead of
88
+ // the index, is a mismatch.
89
+ if (declared !== undefined) {
90
+ const [dm, dn] = declared.split(".").map(Number);
91
+ const [im, in_] = index.version.split(".").map(Number);
92
+ if (!(dm === im && dn <= in_))
93
+ findings.push({ kind: "version-mismatch", declared, spec: index.version });
94
+ }
95
+ const lines = document.split("\n");
96
+ for (let i = 0; i < lines.length; i++) {
97
+ const line = lines[i];
98
+ const marker = MARKER.exec(line);
99
+ if (marker) {
100
+ const id = marker[1];
101
+ const rule = index.rules.get(id);
102
+ if (!rule) {
103
+ findings.push({ kind: "unknown-identifier", id, line: i + 1 });
104
+ continue;
105
+ }
106
+ const quoted = [];
107
+ let j = i + 1;
108
+ while (j < lines.length && /^\s*>/.test(lines[j]))
109
+ quoted.push(lines[j].replace(/^\s*>\s?/, "")), j++;
110
+ if (quoted.length === 0) {
111
+ findings.push({ kind: "marker-without-quote", id, line: i + 1 });
112
+ continue;
113
+ }
114
+ const quote = collapse(quoted.join(" "));
115
+ if (!rule.text.includes(quote))
116
+ findings.push({ kind: "quote-not-in-rule", id, line: i + 1, quote });
117
+ continue;
118
+ }
119
+ for (const m of line.matchAll(IDENTIFIER)) {
120
+ if (!index.rules.has(m[1]))
121
+ findings.push({ kind: "unknown-identifier", id: m[1], line: i + 1 });
122
+ }
123
+ }
124
+ return findings;
125
+ }
126
+ /** One line per finding, for a test's failure message. */
127
+ export function describeFinding(f) {
128
+ switch (f.kind) {
129
+ case "unknown-identifier": return `line ${f.line}: ${f.id} is not a rule of this specification`;
130
+ case "quote-not-in-rule": return `line ${f.line}: the quote under ${f.id} is not the rule's text: "${f.quote}"`;
131
+ case "marker-without-quote": return `line ${f.line}: rule marker ${f.id} is not followed by a blockquote`;
132
+ case "version-mismatch": return `the document's implementation declares spec ${f.declared}, the rules are at ${f.spec}`;
133
+ }
134
+ }
135
+ //# sourceMappingURL=rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.js","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { ConformanceAdapter } from "./adapter.js";
2
+ import type { ExpressionFixture, Fixture, ProjectFixture } from "./fixture.js";
3
+ export interface FixtureReport {
4
+ fixture: string;
5
+ adapter: string;
6
+ pass: boolean;
7
+ skipped?: string;
8
+ failures: string[];
9
+ }
10
+ /**
11
+ * The comparison form of a folded value. `JSON.stringify` drops an
12
+ * `undefined`-valued key and turns an `undefined` element into `null`, which
13
+ * is exactly the distinction F-Val-Undefined draws (#82): a fixture that wants
14
+ * to see it writes the sentinel `"$undefined"` where the fold must yield
15
+ * `undefined`, and this encoding maps the fold's `undefined` to the same
16
+ * sentinel before the two are compared. Non-finite numbers, which JSON cannot
17
+ * write either, encode as ToString would print them.
18
+ */
19
+ export declare function encodeValue(v: unknown): string;
20
+ export declare function runFixture(adapter: ConformanceAdapter, f: ExpressionFixture): FixtureReport;
21
+ export declare function runFixtures(adapter: ConformanceAdapter, fixtures: Fixture[]): Promise<FixtureReport[]>;
22
+ /** #24 — a whole-build fixture. J3's edges are invisible in any single file, so this is the only shape that can test them. */
23
+ export declare function runProjectFixture(adapter: ConformanceAdapter, f: ProjectFixture): Promise<FixtureReport>;
24
+ /** #11 — two implementations must agree on every fixture, independently of what the fixture expects. */
25
+ export declare function compareAdapters(a: ConformanceAdapter, b: ConformanceAdapter, fixtures: Fixture[]): Promise<string[]>;
26
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAI/E,MAAM,WAAW,aAAa;IAAG,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE;AAExH;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAS9C;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,kBAAkB,EAAE,CAAC,EAAE,iBAAiB,GAAG,aAAa,CAe3F;AACD,wBAAsB,WAAW,CAAC,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAK5G;AAED,8HAA8H;AAC9H,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,EAAE,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAmC9G;AAED,wGAAwG;AACxG,wBAAsB,eAAe,CAAC,CAAC,EAAE,kBAAkB,EAAE,CAAC,EAAE,kBAAkB,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA6B1H"}
package/dist/runner.js ADDED
@@ -0,0 +1,152 @@
1
+ import { expressionFixtures, projectFixtures } from "./fixture.js";
2
+ import { requireHost } from "./host.js";
3
+ /**
4
+ * The comparison form of a folded value. `JSON.stringify` drops an
5
+ * `undefined`-valued key and turns an `undefined` element into `null`, which
6
+ * is exactly the distinction F-Val-Undefined draws (#82): a fixture that wants
7
+ * to see it writes the sentinel `"$undefined"` where the fold must yield
8
+ * `undefined`, and this encoding maps the fold's `undefined` to the same
9
+ * sentinel before the two are compared. Non-finite numbers, which JSON cannot
10
+ * write either, encode as ToString would print them.
11
+ */
12
+ export function encodeValue(v) {
13
+ const walk = (x) => {
14
+ if (x === undefined)
15
+ return "$undefined";
16
+ if (typeof x === "number" && !Number.isFinite(x))
17
+ return String(x);
18
+ if (x === null || typeof x !== "object")
19
+ return x;
20
+ if (Array.isArray(x))
21
+ return x.map(walk);
22
+ return Object.fromEntries(Object.entries(x).map(([k, e]) => [k, walk(e)]));
23
+ };
24
+ return JSON.stringify(walk(v));
25
+ }
26
+ export function runFixture(adapter, f) {
27
+ const failures = [];
28
+ let skipped;
29
+ const s = adapter.shape(f.input, f.exportName);
30
+ if (s === "unavailable")
31
+ skipped = "shape classifier unavailable";
32
+ else if (s.accepted !== (f.shape === "accept"))
33
+ failures.push(`shape: expected ${f.shape}, got ${s.accepted ? "accept" : `reject (${s.message})`}`);
34
+ const r = adapter.foldExport(f.input, f.exportName);
35
+ if (f.fold === "fold") {
36
+ if (!r.ok)
37
+ failures.push(`fold: expected fold, got run (${r.message})`);
38
+ else if (encodeValue(r.value) !== encodeValue(f.value))
39
+ failures.push(`fold: value ${encodeValue(r.value)} ≠ expected ${encodeValue(f.value)}`);
40
+ }
41
+ else {
42
+ if (r.ok)
43
+ failures.push(`fold: expected run, got fold with ${JSON.stringify(r.value)}`);
44
+ else if (f.rejectAt && (r.line !== f.rejectAt.line || r.column !== f.rejectAt.column))
45
+ failures.push(`fold: rejection at ${r.line}:${r.column}, expected ${f.rejectAt.line}:${f.rejectAt.column}`);
46
+ }
47
+ return { fixture: f.id, adapter: adapter.name, pass: failures.length === 0, skipped, failures };
48
+ }
49
+ export async function runFixtures(adapter, fixtures) {
50
+ return [
51
+ ...expressionFixtures(fixtures).map((f) => runFixture(adapter, f)),
52
+ ...(await Promise.all(projectFixtures(fixtures).map((f) => runProjectFixture(adapter, f)))),
53
+ ];
54
+ }
55
+ /** #24 — a whole-build fixture. J3's edges are invisible in any single file, so this is the only shape that can test them. */
56
+ export async function runProjectFixture(adapter, f) {
57
+ const base = { fixture: f.id, adapter: adapter.name };
58
+ if (!adapter.foldProject)
59
+ return { ...base, pass: true, skipped: "no project entry", failures: [] };
60
+ const r = await adapter.foldProject(f.files, f.host ? requireHost(f.host) : undefined);
61
+ if (r === "unavailable")
62
+ return { ...base, pass: true, skipped: "project entry unavailable", failures: [] };
63
+ const failures = [];
64
+ for (const [path, want] of Object.entries(f.verdicts)) {
65
+ const got = r.verdicts[path];
66
+ if (!got) {
67
+ failures.push(`${path}: no verdict reported`);
68
+ continue;
69
+ }
70
+ if (got.kind !== want)
71
+ failures.push(`${path}: expected ${want}, got ${got.kind}${got.kind === "run" ? ` (${got.reason})` : ""}`);
72
+ }
73
+ for (const path of Object.keys(r.verdicts))
74
+ if (!(path in f.verdicts))
75
+ failures.push(`${path}: verdict reported but not expected`);
76
+ for (const [path, want] of Object.entries(f.tentative ?? {})) {
77
+ if (!r.tentative) {
78
+ failures.push(`${path}: fixture expects a tentative verdict, adapter reports none`);
79
+ continue;
80
+ }
81
+ if (r.tentative[path] !== want)
82
+ failures.push(`${path}: tentative expected ${want}, got ${r.tentative[path] ?? "none"}`);
83
+ }
84
+ for (const [path, want] of Object.entries(f.taintedBy ?? {})) {
85
+ if (!r.taintedBy) {
86
+ failures.push(`${path}: fixture expects a taint source, adapter reports none`);
87
+ continue;
88
+ }
89
+ if (r.taintedBy[path] !== want)
90
+ failures.push(`${path}: tainted by ${r.taintedBy[path] ?? "nothing"}, expected ${want}`);
91
+ }
92
+ for (const [path, want] of Object.entries(f.rejectRule ?? {})) {
93
+ const got = r.verdicts[path];
94
+ if (got?.kind !== "run") {
95
+ failures.push(`${path}: expected a ${want} rejection, but the file folded`);
96
+ continue;
97
+ }
98
+ if (got.rule !== undefined && got.rule !== want)
99
+ failures.push(`${path}: rejected under ${got.rule}, expected ${want} (${got.reason})`);
100
+ }
101
+ for (const [path, want] of Object.entries(f.exports ?? {})) {
102
+ const got = r.verdicts[path];
103
+ if (got?.kind !== "fold") {
104
+ failures.push(`${path}: expected exports, but the file did not fold`);
105
+ continue;
106
+ }
107
+ for (const [name, value] of Object.entries(want)) {
108
+ if (encodeValue(got.exports[name]) !== encodeValue(value)) {
109
+ failures.push(`${path}: export ${name} = ${encodeValue(got.exports[name])} ≠ expected ${encodeValue(value)}`);
110
+ }
111
+ }
112
+ }
113
+ return { ...base, pass: failures.length === 0, failures };
114
+ }
115
+ /** #11 — two implementations must agree on every fixture, independently of what the fixture expects. */
116
+ export async function compareAdapters(a, b, fixtures) {
117
+ const dis = [];
118
+ for (const f of projectFixtures(fixtures)) {
119
+ if (!a.foldProject || !b.foldProject)
120
+ continue;
121
+ const host = f.host ? requireHost(f.host) : undefined;
122
+ const [ra, rb] = await Promise.all([a.foldProject(f.files, host), b.foldProject(f.files, host)]);
123
+ if (ra === "unavailable" || rb === "unavailable")
124
+ continue;
125
+ for (const path of new Set([...Object.keys(ra.verdicts), ...Object.keys(rb.verdicts)])) {
126
+ const va = ra.verdicts[path]?.kind ?? "absent", vb = rb.verdicts[path]?.kind ?? "absent";
127
+ if (va !== vb)
128
+ dis.push(`${f.id} ${path}: ${a.name} ${va}, ${b.name} ${vb}`);
129
+ // The verdict alone cannot tell a seed from a taint casualty, and both of
130
+ // those are "run". Where both implementations report the tentative
131
+ // verdict and the edge, compare them: that is where J3 actually lives.
132
+ if (ra.tentative && rb.tentative && ra.tentative[path] !== rb.tentative[path]) {
133
+ dis.push(`${f.id} ${path}: tentative — ${a.name} ${ra.tentative[path] ?? "none"}, ${b.name} ${rb.tentative[path] ?? "none"}`);
134
+ }
135
+ if (ra.taintedBy && rb.taintedBy && ra.taintedBy[path] !== rb.taintedBy[path]) {
136
+ dis.push(`${f.id} ${path}: tainted by — ${a.name} ${ra.taintedBy[path] ?? "nothing"}, ${b.name} ${rb.taintedBy[path] ?? "nothing"}`);
137
+ }
138
+ }
139
+ }
140
+ for (const f of expressionFixtures(fixtures)) {
141
+ const ra = a.foldExport(f.input, f.exportName), rb = b.foldExport(f.input, f.exportName);
142
+ if (ra.ok !== rb.ok)
143
+ dis.push(`${f.id}: ${a.name} ${ra.ok ? "folds" : "runs"}, ${b.name} ${rb.ok ? "folds" : "runs"}`);
144
+ else if (ra.ok && rb.ok && encodeValue(ra.value) !== encodeValue(rb.value))
145
+ dis.push(`${f.id}: values differ — ${a.name} ${encodeValue(ra.value)} vs ${b.name} ${encodeValue(rb.value)}`);
146
+ const sa = a.shape(f.input, f.exportName), sb = b.shape(f.input, f.exportName);
147
+ if (sa !== "unavailable" && sb !== "unavailable" && sa.accepted !== sb.accepted)
148
+ dis.push(`${f.id}: shape — ${a.name} ${sa.accepted ? "accepts" : "rejects"}, ${b.name} ${sb.accepted ? "accepts" : "rejects"}`);
149
+ }
150
+ return dis;
151
+ }
152
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ {
2
+ "rules": ["F-CallLeak", "F-Val-Live"],
3
+ "project": true,
4
+ "host": "shapes",
5
+ "verdicts": { "leaky.ts": "fold", "pure.ts": "fold", "caller.ts": "fold" },
6
+ "exports": { "caller.ts": { "data": { "doubled": 42 } } },
7
+ "note": "Two project-local calls in one file, one leaking and one not. shared() returns a live object the caller's arguments did not carry in, so caller.ts captures leaky.ts; twice() returns computed plain data, so pure.ts is not captured. Everything folds here, and the difference is only visible in the edges — which is why the taint fixtures are the ones that make it observable."
8
+ }
@@ -0,0 +1,5 @@
1
+ import { shared } from "./leaky";
2
+ import { twice } from "./pure";
3
+
4
+ export const live = shared();
5
+ export const data = twice(21);
@@ -0,0 +1,7 @@
1
+ import { registry } from "@tsad/shapes";
2
+
3
+ export function shared() {
4
+ return registry;
5
+ }
6
+
7
+ export const marker = 1;
@@ -0,0 +1,5 @@
1
+ export function twice(n: number) {
2
+ return { doubled: n * 2 };
3
+ }
4
+
5
+ export const marker = 2;
@@ -0,0 +1,6 @@
1
+ {
2
+ "rules": ["F-Cycle"],
3
+ "project": true,
4
+ "verdicts": { "a.ts": "run", "b.ts": "run" },
5
+ "note": "Resolution meets itself. The requirement is a located error naming the cycle, not an infinite regress, so the only assertion a conforming implementation must satisfy is that both files get a verdict at all."
6
+ }
@@ -0,0 +1,3 @@
1
+ import { b } from "./b";
2
+
3
+ export const a = { b };
@@ -0,0 +1,3 @@
1
+ import { a } from "./a";
2
+
3
+ export const b = { a };
@@ -0,0 +1,19 @@
1
+ {
2
+ "rules": [
3
+ "F-Depth",
4
+ "F-Eval-CallLocal"
5
+ ],
6
+ "project": true,
7
+ "verdicts": {
8
+ "rec.ts": "run",
9
+ "deep.ts": "run"
10
+ },
11
+ "tentative": {
12
+ "rec.ts": "fold",
13
+ "deep.ts": "run"
14
+ },
15
+ "taintedBy": {
16
+ "rec.ts": "deep.ts"
17
+ },
18
+ "note": "A recursion deep enough to exceed any bound an implementation would choose. The value of the bound is the implementation's (#71): the reference stops at 32, chant's expression path at 32 and its cross-file path at the engine's stack, and every one of them reports a fallback rather than a failure or a wrong answer. rec.ts folds alone and the forward edge takes it along."
19
+ }
@@ -0,0 +1,3 @@
1
+ import { down } from "./rec";
2
+
3
+ export const floor = down(50000);
@@ -0,0 +1,3 @@
1
+ export function down(n: number) {
2
+ return n <= 0 ? 0 : down(n - 1);
3
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "rules": [
3
+ "F-Div-Depth",
4
+ "F-Eval-New"
5
+ ],
6
+ "project": true,
7
+ "verdicts": {
8
+ "fn.ts": "run",
9
+ "app.ts": "run"
10
+ },
11
+ "rejectRule": {
12
+ "app.ts": "F-Eval-New"
13
+ },
14
+ "note": "A `new` inside a folded function body is refused before its callee is even looked up: a construction reached through a call would be an entity the file's own declarators never named. fn.ts itself folds; only calling it does not. fn.ts would fold on its own; app.ts imports it and runs, so the forward edge (F-Succ) takes it along.",
15
+ "tentative": {
16
+ "fn.ts": "fold"
17
+ },
18
+ "taintedBy": {
19
+ "fn.ts": "app.ts"
20
+ }
21
+ }
@@ -0,0 +1,3 @@
1
+ import { make } from "./fn";
2
+
3
+ export const t = make();
@@ -0,0 +1,3 @@
1
+ export function make() {
2
+ return new Thing({ name: "t" });
3
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "rules": ["F-Div-Eager", "F-Eval-Ident"],
3
+ "project": true,
4
+ "host": "shapes",
5
+ "verdicts": { "app.ts": "run" },
6
+ "rejectRule": { "app.ts": "F-Eval-Ident" },
7
+ "note": "A registered eager name is called, not referenced: as a value it is a function, and F-Eval-Ident step 3 rejects it with \"call it instead\". Shape sees a bare identifier and accepts."
8
+ }
@@ -0,0 +1,3 @@
1
+ import { count } from "@tsad/shapes";
2
+
3
+ export const f = { counter: count };
@@ -0,0 +1,18 @@
1
+ {
2
+ "rules": [
3
+ "F-Div-NsNew",
4
+ "F-Div",
5
+ "F-Direction",
6
+ "F-Eval-New",
7
+ "S-New",
8
+ "F-Obs-Messages"
9
+ ],
10
+ "export": "b",
11
+ "shape": "accept",
12
+ "fold": "run",
13
+ "note": "S-New leaves the callee's shape unconstrained, so the classifier accepts; the folder requires a plain identifier, because a class is unreachable through a package namespace (F-Namespace). The rejection's location is asserted and its wording is not (F-Obs-Messages).",
14
+ "rejectAt": {
15
+ "line": 3,
16
+ "column": 18
17
+ }
18
+ }
@@ -0,0 +1,3 @@
1
+ import * as ns from "@tsad/shapes";
2
+
3
+ export const b = new ns.Bucket({ name: "b" });
@@ -0,0 +1,20 @@
1
+ {
2
+ "rules": [
3
+ "F-Div-Provenance",
4
+ "F-Host-NoSubstitution",
5
+ "F-Host-Closed-vs-Open"
6
+ ],
7
+ "project": true,
8
+ "host": "shapes",
9
+ "verdicts": {
10
+ "local.ts": "run",
11
+ "app.ts": "run"
12
+ },
13
+ "note": "The name upper is a registered helper, so the classifier accepts the call and J1 yields a {__helper} envelope; but the binding comes from a project file, not the host, and revival will not substitute the host's upper for the one the file imported. The file falls back. A registered name keeps its meaning (F-Eval-CallLocal is checked after the registered shapes), which is why this is not simply a project-local call. local.ts would fold on its own; app.ts imports it and runs, so the forward edge (F-Succ) takes it along.",
14
+ "tentative": {
15
+ "local.ts": "fold"
16
+ },
17
+ "taintedBy": {
18
+ "local.ts": "app.ts"
19
+ }
20
+ }
@@ -0,0 +1,3 @@
1
+ import { upper } from "./local";
2
+
3
+ export const v = upper("a");
@@ -0,0 +1,3 @@
1
+ export function upper(s: string) {
2
+ return s + "!";
3
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "rules": ["F-Div-SameFileNew", "F-Eval-Ident"],
3
+ "export": "wrapper",
4
+ "shape": "accept",
5
+ "fold": "run",
6
+ "rejectAt": { "line": 5, "column": 33 },
7
+ "note": "The same shape F-Prebuild folds in a build, judged by an expression folder with no module graph. Nothing can construct, so `externals` has no instance for `base`, step 1 rejects at the reference rather than building a duplicate, and the shape classifier accepts what the folder refused (F-Direction)."
8
+ }
@@ -0,0 +1,5 @@
1
+ class Bucket { constructor(readonly props: { name: string }) {} }
2
+
3
+ const base = new Bucket({ name: "base" });
4
+
5
+ export const wrapper = { inner: base };
@@ -0,0 +1,15 @@
1
+ {
2
+ "rules": [
3
+ "F-Div-Tag",
4
+ "F-Eval-Tagged",
5
+ "S-Tagged"
6
+ ],
7
+ "export": "t",
8
+ "shape": "accept",
9
+ "fold": "run",
10
+ "note": "S-Tagged treats the interior as opaque and the tag as any identifier; the folder requires the tag to be a registered, tag-foldable intrinsic, and nothing is registered here.",
11
+ "rejectAt": {
12
+ "line": 1,
13
+ "column": 18
14
+ }
15
+ }
@@ -0,0 +1 @@
1
+ export const t = nope`plain`;
@@ -0,0 +1,14 @@
1
+ {
2
+ "rules": [
3
+ "F-Eval-Array",
4
+ "F-Div-SpreadType"
5
+ ],
6
+ "export": "x",
7
+ "shape": "accept",
8
+ "fold": "run",
9
+ "note": "The one place array evaluation departs from ECMAScript on purpose (R10.6): spread requires Array.isArray, so a string, iterable in JavaScript, is refused rather than split into characters. Shape accepts any spread operand; the folder rejects at the spread. A port that assumes \"as ECMAScript\" would fold this to [\"a\", \"b\"].",
10
+ "rejectAt": {
11
+ "line": 1,
12
+ "column": 19
13
+ }
14
+ }
@@ -0,0 +1 @@
1
+ export const x = [..."ab"];
@@ -0,0 +1,19 @@
1
+ {
2
+ "rules": [
3
+ "F-Eval-Binary"
4
+ ],
5
+ "export": "x",
6
+ "shape": "accept",
7
+ "fold": "fold",
8
+ "value": [
9
+ 3.5,
10
+ 0.3333333333333333,
11
+ 0.2,
12
+ 2.9,
13
+ 2.5,
14
+ "Infinity",
15
+ "-Infinity",
16
+ 0.30000000000000004
17
+ ],
18
+ "note": "Division is IEEE double division: no integer division, and division by zero is an infinity, not an error. Infinity has no JSON form, so the expected value writes it as the string ToString would produce; the comparison encodes the fold the same way."
19
+ }
@@ -0,0 +1 @@
1
+ export const x = [7 / 2, 1 / 3, 2 * 0.1, 3 - 0.1, 10 / 4, 5 / 0, -5 / 0, 0.1 * 3];
@@ -0,0 +1,20 @@
1
+ {
2
+ "rules": [
3
+ "F-Eval-Binary",
4
+ "F-Exc-Lazy"
5
+ ],
6
+ "export": "x",
7
+ "shape": "accept",
8
+ "fold": "fold",
9
+ "value": [
10
+ "x",
11
+ "",
12
+ 0,
13
+ 0,
14
+ "",
15
+ null,
16
+ "b",
17
+ null
18
+ ],
19
+ "note": "&&, || and ?? return an operand, never a boolean, and ?? tests nullish where || tests falsy: 0 ?? 1 is 0 and \"\" ?? \"y\" is \"\". The untaken side is not folded (F-Exc-Lazy)."
20
+ }