agent-comms 9.0.2 → 9.0.4

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 (192) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +6 -0
  4. package/dist/bridges/claude-code/channel.d.ts.map +1 -1
  5. package/dist/bridges/claude-code/channel.js +3 -1
  6. package/dist/bridges/claude-code/channel.js.map +1 -1
  7. package/dist/bridges/codex/tool.d.ts +2 -1
  8. package/dist/bridges/codex/tool.d.ts.map +1 -1
  9. package/dist/bridges/codex/tool.js +4 -2
  10. package/dist/bridges/codex/tool.js.map +1 -1
  11. package/dist/bridges/mcp/server.d.ts.map +1 -1
  12. package/dist/bridges/mcp/server.js +3 -1
  13. package/dist/bridges/mcp/server.js.map +1 -1
  14. package/dist/bridges/user/web/bridge-port-range.d.ts +52 -0
  15. package/dist/bridges/user/web/bridge-port-range.d.ts.map +1 -0
  16. package/dist/bridges/user/web/bridge-port-range.js +90 -0
  17. package/dist/bridges/user/web/bridge-port-range.js.map +1 -0
  18. package/dist/bridges/user/web/dist/bundle.js +1 -1
  19. package/dist/bridges/user/web/dist/sw.js +1 -1
  20. package/dist/bridges/user/web/frontend/mesh-client.d.ts +6 -2
  21. package/dist/bridges/user/web/frontend/mesh-client.d.ts.map +1 -1
  22. package/dist/bridges/user/web/frontend/mesh-client.js +13 -27
  23. package/dist/bridges/user/web/frontend/mesh-client.js.map +1 -1
  24. package/dist/bridges/user/web/server.d.ts +11 -5
  25. package/dist/bridges/user/web/server.d.ts.map +1 -1
  26. package/dist/bridges/user/web/server.js +78 -21
  27. package/dist/bridges/user/web/server.js.map +1 -1
  28. package/dist/bridges/user/web/test/bridge-port-range.integration.test.d.ts +2 -0
  29. package/dist/bridges/user/web/test/bridge-port-range.integration.test.d.ts.map +1 -0
  30. package/dist/bridges/user/web/test/bridge-port-range.integration.test.js +281 -0
  31. package/dist/bridges/user/web/test/bridge-port-range.integration.test.js.map +1 -0
  32. package/dist/bridges/user/web/test/bridge-web-server.helper.d.ts +13 -0
  33. package/dist/bridges/user/web/test/bridge-web-server.helper.d.ts.map +1 -0
  34. package/dist/bridges/user/web/test/bridge-web-server.helper.js +46 -0
  35. package/dist/bridges/user/web/test/bridge-web-server.helper.js.map +1 -0
  36. package/dist/bridges/user/web/test/bridge-web-server.integration.test.js +4 -2
  37. package/dist/bridges/user/web/test/bridge-web-server.integration.test.js.map +1 -1
  38. package/dist/bridges/user/web/test/lan-web-server.integration.test.js +1 -0
  39. package/dist/bridges/user/web/test/lan-web-server.integration.test.js.map +1 -1
  40. package/dist/bridges/user/web/test/orpc-router.integration.test.js +1 -0
  41. package/dist/bridges/user/web/test/orpc-router.integration.test.js.map +1 -1
  42. package/dist/bridges/user/web/test/web-access.unit.test.d.ts +1 -1
  43. package/dist/bridges/user/web/test/web-access.unit.test.js +19 -375
  44. package/dist/bridges/user/web/test/web-access.unit.test.js.map +1 -1
  45. package/dist/bridges/user/web/test/web-console-route.integration.test.js +1 -0
  46. package/dist/bridges/user/web/test/web-console-route.integration.test.js.map +1 -1
  47. package/dist/bridges/user/web/test/web-server-unbuilt-frontend.integration.test.js +4 -2
  48. package/dist/bridges/user/web/test/web-server-unbuilt-frontend.integration.test.js.map +1 -1
  49. package/dist/bridges/user/web/test/web-server.integration.test.js +1 -0
  50. package/dist/bridges/user/web/test/web-server.integration.test.js.map +1 -1
  51. package/dist/core/bridge-mesh.d.ts +2 -0
  52. package/dist/core/bridge-mesh.d.ts.map +1 -1
  53. package/dist/core/bridge-mesh.js.map +1 -1
  54. package/dist/core/bridge.d.ts +11 -0
  55. package/dist/core/bridge.d.ts.map +1 -1
  56. package/dist/core/bridge.js +17 -2
  57. package/dist/core/bridge.js.map +1 -1
  58. package/dist/core/index.d.ts +1 -1
  59. package/dist/core/index.d.ts.map +1 -1
  60. package/dist/core/index.js +1 -1
  61. package/dist/core/index.js.map +1 -1
  62. package/dist/core/test/build-action.unit.test.d.ts +2 -0
  63. package/dist/core/test/build-action.unit.test.d.ts.map +1 -0
  64. package/dist/core/test/build-action.unit.test.js +28 -0
  65. package/dist/core/test/build-action.unit.test.js.map +1 -0
  66. package/dist/core/tool.d.ts +1 -1
  67. package/dist/core/tool.d.ts.map +1 -1
  68. package/dist/test/bridge-stdout.runner.js +5 -0
  69. package/dist/test/bridge-stdout.runner.js.map +1 -1
  70. package/dist/test/ci-required-checks.unit.test.d.ts +2 -0
  71. package/dist/test/ci-required-checks.unit.test.d.ts.map +1 -0
  72. package/dist/test/ci-required-checks.unit.test.js +137 -0
  73. package/dist/test/ci-required-checks.unit.test.js.map +1 -0
  74. package/dist/test/claude-command.unit.test.js +2 -21
  75. package/dist/test/claude-command.unit.test.js.map +1 -1
  76. package/dist/test/conformance/corpus-files.d.ts +11 -0
  77. package/dist/test/conformance/corpus-files.d.ts.map +1 -0
  78. package/dist/test/conformance/corpus-files.js +71 -0
  79. package/dist/test/conformance/corpus-files.js.map +1 -0
  80. package/dist/test/conformance/corpus-types.d.ts +62 -0
  81. package/dist/test/conformance/corpus-types.d.ts.map +1 -0
  82. package/dist/test/conformance/corpus-types.js +8 -0
  83. package/dist/test/conformance/corpus-types.js.map +1 -0
  84. package/dist/test/conformance/corpus.d.ts +34 -0
  85. package/dist/test/conformance/corpus.d.ts.map +1 -0
  86. package/dist/test/conformance/corpus.js +134 -0
  87. package/dist/test/conformance/corpus.js.map +1 -0
  88. package/dist/test/conformance/read-json.d.ts +2 -0
  89. package/dist/test/conformance/read-json.d.ts.map +1 -0
  90. package/dist/test/conformance/read-json.js +7 -0
  91. package/dist/test/conformance/read-json.js.map +1 -0
  92. package/dist/test/conformance/text.d.ts +10 -0
  93. package/dist/test/conformance/text.d.ts.map +1 -0
  94. package/dist/test/conformance/text.js +64 -0
  95. package/dist/test/conformance/text.js.map +1 -0
  96. package/dist/test/conformance/validate.d.ts +14 -0
  97. package/dist/test/conformance/validate.d.ts.map +1 -0
  98. package/dist/test/conformance/validate.js +85 -0
  99. package/dist/test/conformance/validate.js.map +1 -0
  100. package/dist/test/conformance-functions.helper.d.ts +19 -0
  101. package/dist/test/conformance-functions.helper.d.ts.map +1 -0
  102. package/dist/test/conformance-functions.helper.js +583 -0
  103. package/dist/test/conformance-functions.helper.js.map +1 -0
  104. package/dist/test/conformance.unit.test.d.ts +2 -0
  105. package/dist/test/conformance.unit.test.d.ts.map +1 -0
  106. package/dist/test/conformance.unit.test.js +358 -0
  107. package/dist/test/conformance.unit.test.js.map +1 -0
  108. package/dist/test/error-reporting.unit.test.js +2 -90
  109. package/dist/test/error-reporting.unit.test.js.map +1 -1
  110. package/dist/test/hub-helpers.d.ts +6 -0
  111. package/dist/test/hub-helpers.d.ts.map +1 -1
  112. package/dist/test/hub-helpers.js +17 -0
  113. package/dist/test/hub-helpers.js.map +1 -1
  114. package/dist/test/mcp-stdout-channel.integration.test.js +2 -1
  115. package/dist/test/mcp-stdout-channel.integration.test.js.map +1 -1
  116. package/dist/test/version-report-actions.unit.test.d.ts +1 -1
  117. package/dist/test/version-report-actions.unit.test.js +2 -55
  118. package/dist/test/version-report-actions.unit.test.js.map +1 -1
  119. package/package.json +4 -2
  120. package/src/bridges/claude-code/channel.ts +3 -1
  121. package/src/bridges/codex/tool.ts +5 -2
  122. package/src/bridges/mcp/server.ts +3 -1
  123. package/src/bridges/user/web/bridge-port-range.ts +130 -0
  124. package/src/bridges/user/web/dist/bundle.js +1 -1
  125. package/src/bridges/user/web/dist/sw.js +1 -1
  126. package/src/bridges/user/web/server.ts +104 -29
  127. package/src/bridges/user/web/test/bridge-web-server.helper.ts +54 -0
  128. package/src/core/bridge-mesh.ts +2 -0
  129. package/src/core/bridge.ts +30 -1
  130. package/src/core/index.ts +1 -0
  131. package/src/core/tool.ts +1 -1
  132. package/dist/bridges/user/web/port-discovery.d.ts +0 -14
  133. package/dist/bridges/user/web/port-discovery.d.ts.map +0 -1
  134. package/dist/bridges/user/web/port-discovery.js +0 -40
  135. package/dist/bridges/user/web/port-discovery.js.map +0 -1
  136. package/dist/bridges/user/web/test/port-discovery.unit.test.d.ts +0 -5
  137. package/dist/bridges/user/web/test/port-discovery.unit.test.d.ts.map +0 -1
  138. package/dist/bridges/user/web/test/port-discovery.unit.test.js +0 -180
  139. package/dist/bridges/user/web/test/port-discovery.unit.test.js.map +0 -1
  140. package/dist/core/test/bridge.unit.test.d.ts +0 -5
  141. package/dist/core/test/bridge.unit.test.d.ts.map +0 -1
  142. package/dist/core/test/bridge.unit.test.js +0 -119
  143. package/dist/core/test/bridge.unit.test.js.map +0 -1
  144. package/dist/test/agent-table.unit.test.d.ts +0 -5
  145. package/dist/test/agent-table.unit.test.d.ts.map +0 -1
  146. package/dist/test/agent-table.unit.test.js +0 -53
  147. package/dist/test/agent-table.unit.test.js.map +0 -1
  148. package/dist/test/bind-retry.unit.test.d.ts +0 -2
  149. package/dist/test/bind-retry.unit.test.d.ts.map +0 -1
  150. package/dist/test/bind-retry.unit.test.js +0 -42
  151. package/dist/test/bind-retry.unit.test.js.map +0 -1
  152. package/dist/test/default-command.unit.test.d.ts +0 -2
  153. package/dist/test/default-command.unit.test.d.ts.map +0 -1
  154. package/dist/test/default-command.unit.test.js +0 -26
  155. package/dist/test/default-command.unit.test.js.map +0 -1
  156. package/dist/test/delegation-policy.unit.test.d.ts +0 -5
  157. package/dist/test/delegation-policy.unit.test.d.ts.map +0 -1
  158. package/dist/test/delegation-policy.unit.test.js +0 -52
  159. package/dist/test/delegation-policy.unit.test.js.map +0 -1
  160. package/dist/test/display-name.unit.test.d.ts +0 -5
  161. package/dist/test/display-name.unit.test.d.ts.map +0 -1
  162. package/dist/test/display-name.unit.test.js +0 -65
  163. package/dist/test/display-name.unit.test.js.map +0 -1
  164. package/dist/test/machine-list-groups.unit.test.d.ts +0 -5
  165. package/dist/test/machine-list-groups.unit.test.d.ts.map +0 -1
  166. package/dist/test/machine-list-groups.unit.test.js +0 -61
  167. package/dist/test/machine-list-groups.unit.test.js.map +0 -1
  168. package/dist/test/relay-selection.unit.test.d.ts +0 -5
  169. package/dist/test/relay-selection.unit.test.d.ts.map +0 -1
  170. package/dist/test/relay-selection.unit.test.js +0 -103
  171. package/dist/test/relay-selection.unit.test.js.map +0 -1
  172. package/dist/test/request-timeouts.unit.test.d.ts +0 -2
  173. package/dist/test/request-timeouts.unit.test.d.ts.map +0 -1
  174. package/dist/test/request-timeouts.unit.test.js +0 -28
  175. package/dist/test/request-timeouts.unit.test.js.map +0 -1
  176. package/dist/test/room-discovery.unit.test.d.ts +0 -2
  177. package/dist/test/room-discovery.unit.test.d.ts.map +0 -1
  178. package/dist/test/room-discovery.unit.test.js +0 -29
  179. package/dist/test/room-discovery.unit.test.js.map +0 -1
  180. package/dist/test/room-lookup.unit.test.d.ts +0 -2
  181. package/dist/test/room-lookup.unit.test.d.ts.map +0 -1
  182. package/dist/test/room-lookup.unit.test.js +0 -59
  183. package/dist/test/room-lookup.unit.test.js.map +0 -1
  184. package/dist/test/room-path.unit.test.d.ts +0 -2
  185. package/dist/test/room-path.unit.test.d.ts.map +0 -1
  186. package/dist/test/room-path.unit.test.js +0 -54
  187. package/dist/test/room-path.unit.test.js.map +0 -1
  188. package/dist/test/send-outcome.unit.test.d.ts +0 -2
  189. package/dist/test/send-outcome.unit.test.d.ts.map +0 -1
  190. package/dist/test/send-outcome.unit.test.js +0 -52
  191. package/dist/test/send-outcome.unit.test.js.map +0 -1
  192. package/src/bridges/user/web/port-discovery.ts +0 -49
@@ -0,0 +1,71 @@
1
+ import { readdirSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ /**
4
+ * Which files under the corpus root are corpus files, by the one rule `conformance/README.md` states. Every loader of the corpus (this one, the native crates' and the wasm runner's) implements the same rule, and each runs it over the fixture tree in `conformance/fixtures/loader-selection` so the three cannot disagree.
5
+ */
6
+ /** Directories that hold data cases refer to or the runners themselves, never cases, wherever they appear. */
7
+ const NON_CASE_DIRECTORIES = new Set([
8
+ "fixtures",
9
+ "schema",
10
+ "runner",
11
+ ]);
12
+ /** The files the corpus root itself holds. */
13
+ const ROOT_FILES = new Set([
14
+ "README.md",
15
+ "case.schema.json",
16
+ "manifest.json",
17
+ "manifest.schema.json",
18
+ ]);
19
+ /** The characters a directory or file name outside the root's own files may use, so every loader orders names the same way. */
20
+ const NAME_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
21
+ /** The depth at which a directory holds corpus files: `<kind>/<name>.json`. */
22
+ const AREA_DEPTH = 1;
23
+ function byName(left, right) {
24
+ if (left.name === right.name) {
25
+ return 0;
26
+ }
27
+ return left.name < right.name ? -1 : 1;
28
+ }
29
+ function scan(root, relative, depth, selection) {
30
+ const entries = readdirSync(join(root, relative), { withFileTypes: true })
31
+ .filter((entry) => !entry.name.startsWith("."))
32
+ .sort(byName);
33
+ for (const entry of entries) {
34
+ const path = relative === "" ? entry.name : `${relative}/${entry.name}`;
35
+ if (entry.isDirectory()) {
36
+ if (NON_CASE_DIRECTORIES.has(entry.name)) {
37
+ continue;
38
+ }
39
+ if (depth < AREA_DEPTH && NAME_PATTERN.test(entry.name)) {
40
+ scan(root, path, depth + 1, selection);
41
+ }
42
+ else {
43
+ selection.problems.push(path);
44
+ }
45
+ }
46
+ else if (entry.isFile() && depth === 0 && ROOT_FILES.has(entry.name)) {
47
+ continue;
48
+ }
49
+ else if (entry.isFile() &&
50
+ depth === AREA_DEPTH &&
51
+ entry.name.endsWith(".json") &&
52
+ NAME_PATTERN.test(entry.name)) {
53
+ selection.selected.push(path);
54
+ }
55
+ else {
56
+ selection.problems.push(path);
57
+ }
58
+ }
59
+ }
60
+ /**
61
+ * Applies the selection rule to the tree at `root`. A name starting with a dot is ignored at any depth, a directory named `fixtures`, `schema` or `runner` is skipped at any depth, and everything else must be a `.json` file at `<kind>/<name>.json`, with names of lower-case ASCII letters, digits, dots, hyphens and underscores, or one of the root's own files; anything else is returned in `problems`, for the caller to fail on.
62
+ */
63
+ export function selectCorpusFiles(root) {
64
+ const selection = {
65
+ selected: [],
66
+ problems: [],
67
+ };
68
+ scan(root, "", 0, selection);
69
+ return selection;
70
+ }
71
+ //# sourceMappingURL=corpus-files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"corpus-files.js","sourceRoot":"","sources":["../../../src/test/conformance/corpus-files.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * The shapes of the corpus cases the TypeScript runner executes. `conformance/case.schema.json` is the definition; these types state what a document that passed it holds, so a value is trusted only after the schema has accepted it.
3
+ */
4
+ /** The case kinds the schema defines, and so the names of the corpus directories. */
5
+ export declare const KINDS: readonly ["function", "validate"];
6
+ /** The values of `skip`: the implementation that skips a case, never the host it runs on. */
7
+ export declare const SKIP_VALUES: readonly ["ts", "rust"];
8
+ /** Any JSON value, in which a string may also be written as `{ "codeUnits": [...] }`. */
9
+ export type CorpusValue = null | boolean | number | string | readonly CorpusValue[] | {
10
+ readonly [key: string]: CorpusValue;
11
+ };
12
+ /** A string as UTF-16 code units: a JSON string, or the code units themselves for content a JSON string cannot carry. */
13
+ export type Text = string | {
14
+ readonly codeUnits: readonly number[];
15
+ };
16
+ interface CaseBase {
17
+ readonly id: string;
18
+ readonly from: string;
19
+ readonly skip?: (typeof SKIP_VALUES)[number];
20
+ readonly reason?: string;
21
+ }
22
+ export interface FunctionCase extends CaseBase {
23
+ readonly kind: "function";
24
+ readonly function: string;
25
+ readonly args: readonly CorpusValue[];
26
+ readonly expect?: CorpusValue;
27
+ readonly expectSubset?: CorpusValue;
28
+ readonly expectUndefined?: true;
29
+ readonly throws?: {
30
+ readonly code?: string;
31
+ readonly message?: readonly Text[];
32
+ };
33
+ }
34
+ export interface ValidateIssue {
35
+ readonly path: readonly (string | number)[];
36
+ readonly code?: string;
37
+ readonly message?: readonly Text[];
38
+ }
39
+ export interface ValidateCase extends CaseBase {
40
+ readonly kind: "validate";
41
+ readonly schema: string;
42
+ readonly input: CorpusValue;
43
+ readonly expect: {
44
+ readonly ok: true;
45
+ readonly value?: CorpusValue;
46
+ } | {
47
+ readonly ok: false;
48
+ readonly issues: readonly ValidateIssue[];
49
+ };
50
+ }
51
+ export type CorpusCase = FunctionCase | ValidateCase;
52
+ export interface CorpusFile {
53
+ readonly cases: readonly CorpusCase[];
54
+ }
55
+ export interface Manifest {
56
+ readonly files: Readonly<Record<string, {
57
+ readonly cases: number;
58
+ readonly skip: readonly string[];
59
+ }>>;
60
+ }
61
+ export {};
62
+ //# sourceMappingURL=corpus-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"corpus-types.d.ts","sourceRoot":"","sources":["../../../src/test/conformance/corpus-types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,qFAAqF;AACrF,eAAO,MAAM,KAAK,mCAAoC,CAAC;AAEvD,6FAA6F;AAC7F,eAAO,MAAM,WAAW,yBAA0B,CAAC;AAEnD,yFAAyF;AACzF,MAAM,MAAM,WAAW,GACnB,IAAI,GACJ,OAAO,GACP,MAAM,GACN,MAAM,GACN,SAAS,WAAW,EAAE,GACtB;IAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW,CAAA;CAAE,CAAC;AAE5C,yHAAyH;AACzH,MAAM,MAAM,IAAI,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAEtE,UAAU,QAAQ;IAChB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;IAC7C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,YAAa,SAAQ,QAAQ;IAC5C,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,SAAS,WAAW,EAAE,CAAC;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,YAAY,CAAC,EAAE,WAAW,CAAC;IACpC,QAAQ,CAAC,eAAe,CAAC,EAAE,IAAI,CAAC;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE;QAChB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,IAAI,EAAE,CAAC;KACpC,CAAC;CACH;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IAC5C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,IAAI,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,YAAa,SAAQ,QAAQ;IAC5C,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,MAAM,EACX;QAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;QAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,CAAA;KAAE,GACnD;QAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,CAAA;KAAE,CAAC;CACvE;AAED,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,YAAY,CAAC;AAErD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,CAAC;CACvC;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CACtB,MAAM,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAC,CAC7E,CAAC;CACH"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * The shapes of the corpus cases the TypeScript runner executes. `conformance/case.schema.json` is the definition; these types state what a document that passed it holds, so a value is trusted only after the schema has accepted it.
3
+ */
4
+ /** The case kinds the schema defines, and so the names of the corpus directories. */
5
+ export const KINDS = ["function", "validate"];
6
+ /** The values of `skip`: the implementation that skips a case, never the host it runs on. */
7
+ export const SKIP_VALUES = ["ts", "rust"];
8
+ //# sourceMappingURL=corpus-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"corpus-types.js","sourceRoot":"","sources":["../../../src/test/conformance/corpus-types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,qFAAqF;AACrF,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,UAAU,EAAE,UAAU,CAAU,CAAC;AAEvD,6FAA6F;AAC7F,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,CAAU,CAAC"}
@@ -0,0 +1,34 @@
1
+ import type { CorpusFile, Manifest } from "./corpus-types.js";
2
+ /**
3
+ * Loads and checks a whole corpus root by every rule `conformance/README.md` states: the files selected, each file valid, ids unique across files, and the corpus equal to its manifest. The real corpus and every fixture corpus under `conformance/fixtures/corpora` go through this one function, so a rule has one definition.
4
+ */
5
+ export interface LoadedFile {
6
+ readonly name: string;
7
+ readonly file: CorpusFile;
8
+ }
9
+ export interface CheckedCorpus {
10
+ readonly files: readonly LoadedFile[];
11
+ /** Everything wrong with the corpus; empty when it is sound. */
12
+ readonly problems: readonly string[];
13
+ }
14
+ /** The case ids this implementation registers to run and the ones it skips because they are marked for it alone. A case marked for the other implementation is registered and run here. */
15
+ export declare function collect(files: readonly LoadedFile[]): {
16
+ readonly registered: readonly string[];
17
+ readonly skipped: readonly string[];
18
+ };
19
+ /**
20
+ * The completeness check, per implementation: what this implementation registered and skipped must add up to the manifest's total, and what it skips must be marked in the manifest. Cases marked for the other implementation count as registered here, so they cannot fail it.
21
+ */
22
+ export declare function completenessProblems(total: number, markedIds: ReadonlySet<string>, registered: readonly string[], skipped: readonly string[]): readonly string[];
23
+ export declare function checkCorpus(root: string): CheckedCorpus;
24
+ /** One case as the runner registered it with the test framework, recorded in the loop that registers it. */
25
+ export interface Registration {
26
+ readonly file: string;
27
+ readonly id: string;
28
+ readonly skip: "ts" | "rust" | undefined;
29
+ }
30
+ /**
31
+ * What a run did, against what the manifest says the corpus holds: every file has as many registrations as the manifest has cases, the cases this implementation skips are the ones carrying `skip: ts` and are listed in the manifest, and every other registration ran. `registrations` is filled where the runner registers each case and `ran` where each registered case's body starts, so a runner that skips, filters or mis-keys cases reads as a failure here, and the corpus alone cannot make it pass.
32
+ */
33
+ export declare function runCompletenessProblems(manifest: Manifest, registrations: readonly Registration[], ran: ReadonlySet<string>): readonly string[];
34
+ //# sourceMappingURL=corpus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"corpus.d.ts","sourceRoot":"","sources":["../../../src/test/conformance/corpus.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAI9D;;GAEG;AAEH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,CAAC;IACtC,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAkBD,2LAA2L;AAC3L,wBAAgB,OAAO,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG;IACrD,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC,CAOA;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,EAC9B,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,OAAO,EAAE,SAAS,MAAM,EAAE,GACzB,SAAS,MAAM,EAAE,CAoBnB;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CA2EvD;AAED,4GAA4G;AAC5G,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,CAAC;CAC1C;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,SAAS,YAAY,EAAE,EACtC,GAAG,EAAE,WAAW,CAAC,MAAM,CAAC,GACvB,SAAS,MAAM,EAAE,CAiCnB"}
@@ -0,0 +1,134 @@
1
+ import { join } from "node:path";
2
+ import { selectCorpusFiles } from "./corpus-files.js";
3
+ import { readJson } from "./read-json.js";
4
+ import { validateCorpusFile, validateManifest } from "./validate.js";
5
+ /** What the files of a corpus say about themselves, in the manifest's own shape. */
6
+ function describeFiles(files) {
7
+ return Object.fromEntries(files.map(({ name, file }) => [
8
+ name,
9
+ JSON.stringify({
10
+ cases: file.cases.length,
11
+ skip: file.cases
12
+ .filter((testCase) => testCase.skip !== undefined)
13
+ .map((testCase) => testCase.id)
14
+ .sort(),
15
+ }),
16
+ ]));
17
+ }
18
+ /** The case ids this implementation registers to run and the ones it skips because they are marked for it alone. A case marked for the other implementation is registered and run here. */
19
+ export function collect(files) {
20
+ const cases = files.flatMap(({ file }) => file.cases);
21
+ return {
22
+ registered: cases.filter(({ skip }) => skip !== "ts").map(({ id }) => id),
23
+ skipped: cases.filter(({ skip }) => skip === "ts").map(({ id }) => id),
24
+ };
25
+ }
26
+ /**
27
+ * The completeness check, per implementation: what this implementation registered and skipped must add up to the manifest's total, and what it skips must be marked in the manifest. Cases marked for the other implementation count as registered here, so they cannot fail it.
28
+ */
29
+ export function completenessProblems(total, markedIds, registered, skipped) {
30
+ const problems = [];
31
+ if (registered.length + skipped.length !== total) {
32
+ problems.push(`registered ${String(registered.length)} plus skipped ${String(skipped.length)} is not the manifest's ${String(total)}`);
33
+ }
34
+ for (const id of skipped) {
35
+ if (!markedIds.has(id)) {
36
+ problems.push(`${id} is skipped here and not marked in the manifest`);
37
+ }
38
+ }
39
+ if (new Set([...registered, ...skipped]).size !==
40
+ registered.length + skipped.length) {
41
+ problems.push("a case is both registered and skipped, or registered twice");
42
+ }
43
+ return problems;
44
+ }
45
+ export function checkCorpus(root) {
46
+ const selection = selectCorpusFiles(root);
47
+ const problems = selection.problems.map((path) => `${path}: not a corpus file and not a recognised root file`);
48
+ const files = [];
49
+ const ids = new Set();
50
+ for (const name of selection.selected) {
51
+ const result = validateCorpusFile(readJson(join(root, name)));
52
+ if (!result.ok) {
53
+ problems.push(...result.problems.map((problem) => `${name}: ${problem}`));
54
+ continue;
55
+ }
56
+ const directory = name.slice(0, name.indexOf("/"));
57
+ for (const { id, kind } of result.value.cases) {
58
+ if (kind !== directory) {
59
+ problems.push(`${name}: case ${id} is of kind ${kind}, and the directory names kind ${directory}`);
60
+ }
61
+ if (ids.has(id)) {
62
+ problems.push(`${name}: case id ${id} is used by another file`);
63
+ }
64
+ ids.add(id);
65
+ }
66
+ files.push({ name, file: result.value });
67
+ }
68
+ let manifest;
69
+ try {
70
+ manifest = validateManifest(readJson(join(root, "manifest.json")));
71
+ }
72
+ catch (error) {
73
+ manifest = {
74
+ ok: false,
75
+ problems: [error instanceof Error ? error.message : String(error)],
76
+ };
77
+ }
78
+ if (!manifest.ok) {
79
+ problems.push(...manifest.problems.map((problem) => `manifest.json: ${problem}`));
80
+ }
81
+ else {
82
+ const recorded = Object.fromEntries(Object.entries(manifest.value.files).map(([name, entry]) => [
83
+ name,
84
+ JSON.stringify({ cases: entry.cases, skip: entry.skip }),
85
+ ]));
86
+ const actual = describeFiles(files);
87
+ const counts = collect(files);
88
+ problems.push(...completenessProblems(Object.values(manifest.value.files).reduce((sum, entry) => sum + entry.cases, 0), new Set(Object.values(manifest.value.files).flatMap((entry) => entry.skip)), counts.registered, counts.skipped));
89
+ for (const name of new Set([
90
+ ...Object.keys(recorded),
91
+ ...Object.keys(actual),
92
+ ])) {
93
+ if (recorded[name] !== actual[name]) {
94
+ problems.push(`manifest.json does not match ${name}: the file holds ${actual[name] ?? "nothing"}, the manifest records ${recorded[name] ?? "nothing"}`);
95
+ }
96
+ }
97
+ }
98
+ return { files, problems };
99
+ }
100
+ /**
101
+ * What a run did, against what the manifest says the corpus holds: every file has as many registrations as the manifest has cases, the cases this implementation skips are the ones carrying `skip: ts` and are listed in the manifest, and every other registration ran. `registrations` is filled where the runner registers each case and `ran` where each registered case's body starts, so a runner that skips, filters or mis-keys cases reads as a failure here, and the corpus alone cannot make it pass.
102
+ */
103
+ export function runCompletenessProblems(manifest, registrations, ran) {
104
+ const problems = [];
105
+ const perFile = new Map();
106
+ const seen = new Set();
107
+ for (const { file, id, skip } of registrations) {
108
+ perFile.set(file, (perFile.get(file) ?? 0) + 1);
109
+ if (seen.has(id)) {
110
+ problems.push(`${id} was registered twice`);
111
+ }
112
+ seen.add(id);
113
+ const entry = manifest.files[file];
114
+ if (skip === "ts" && entry?.skip.includes(id) !== true) {
115
+ problems.push(`${id} is skipped here and not listed in the manifest`);
116
+ }
117
+ if (skip !== "ts" && !ran.has(id)) {
118
+ problems.push(`${id} was registered and did not run`);
119
+ }
120
+ }
121
+ for (const [file, entry] of Object.entries(manifest.files)) {
122
+ const count = perFile.get(file) ?? 0;
123
+ if (count !== entry.cases) {
124
+ problems.push(`${file}: ${String(count)} cases registered, the manifest has ${String(entry.cases)}`);
125
+ }
126
+ }
127
+ for (const file of perFile.keys()) {
128
+ if (!(file in manifest.files)) {
129
+ problems.push(`${file} was registered and is not in the manifest`);
130
+ }
131
+ }
132
+ return problems;
133
+ }
134
+ //# sourceMappingURL=corpus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"corpus.js","sourceRoot":"","sources":["../../../src/test/conformance/corpus.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function readJson(path: string): unknown;
2
+ //# sourceMappingURL=read-json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-json.d.ts","sourceRoot":"","sources":["../../../src/test/conformance/read-json.ts"],"names":[],"mappings":"AAKA,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE9C"}
@@ -0,0 +1,7 @@
1
+ import { readFileSync } from "node:fs";
2
+ /** Strict: a file that is not valid UTF-8 is an error, never read with replacement characters, and a leading byte order mark is kept and so refused by the parse, so every loader sees the same text (the Rust loader refuses both too). */
3
+ const decoder = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
4
+ export function readJson(path) {
5
+ return JSON.parse(decoder.decode(readFileSync(path)));
6
+ }
7
+ //# sourceMappingURL=read-json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-json.js","sourceRoot":"","sources":["../../../src/test/conformance/read-json.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,4OAA4O;AAC5O,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAE3E,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACxD,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { Text } from "./corpus-types.js";
2
+ /** The string a corpus text denotes. */
3
+ export declare function textToString(text: Text): string;
4
+ /** The UTF-16 code units a corpus text denotes. */
5
+ export declare function textToCodeUnits(text: Text): readonly number[];
6
+ /** The name of a special number, as a corpus file writes it, or undefined for any other number. */
7
+ export declare function specialNumberName(value: number): string | undefined;
8
+ /** A value with every `{ "codeUnits": [...] }` replaced by the string it denotes and every `{ "$number": name }` by the number it names, at any depth. The schema has already refused an object that holds either key and anything else. */
9
+ export declare function decodeValue(value: unknown): unknown;
10
+ //# sourceMappingURL=text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/test/conformance/text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAkB9C,wCAAwC;AACxC,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAI/C;AAED,mDAAmD;AACnD,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,MAAM,EAAE,CAQ7D;AAUD,mGAAmG;AACnG,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAOnE;AAED,4OAA4O;AAC5O,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAwBnD"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * The corpus carries every string as a sequence of UTF-16 code units, either as a JSON string or as `{ "codeUnits": [...] }` (`conformance/README.md`). A JavaScript string is already that sequence, so decoding is the identity for the first form and `String.fromCharCode` for the second.
3
+ */
4
+ function isRecord(value) {
5
+ return typeof value === "object" && value !== null && !Array.isArray(value);
6
+ }
7
+ function isCodeUnitsObject(value) {
8
+ const units = value.codeUnits;
9
+ return Array.isArray(units) && units.every((u) => typeof u === "number");
10
+ }
11
+ /** The string a corpus text denotes. */
12
+ export function textToString(text) {
13
+ return typeof text === "string"
14
+ ? text
15
+ : String.fromCharCode(...text.codeUnits);
16
+ }
17
+ /** The UTF-16 code units a corpus text denotes. */
18
+ export function textToCodeUnits(text) {
19
+ if (typeof text !== "string") {
20
+ return text.codeUnits;
21
+ }
22
+ return Array.from({ length: text.length }, (_, index) => text.charCodeAt(index));
23
+ }
24
+ /** The numbers a corpus file names with `{ "$number": name }`, a closed lookup: the canonical JSON form writes a negative zero as 0 and has no infinity or NaN. */
25
+ const NAMED_NUMBERS = {
26
+ "-0": -0,
27
+ Infinity: Number.POSITIVE_INFINITY,
28
+ "-Infinity": Number.NEGATIVE_INFINITY,
29
+ NaN: Number.NaN,
30
+ };
31
+ /** The name of a special number, as a corpus file writes it, or undefined for any other number. */
32
+ export function specialNumberName(value) {
33
+ if (Number.isNaN(value))
34
+ return "NaN";
35
+ if (Object.is(value, -0))
36
+ return "-0";
37
+ if (value === Number.POSITIVE_INFINITY)
38
+ return "Infinity";
39
+ if (value === Number.NEGATIVE_INFINITY)
40
+ return "-Infinity";
41
+ return undefined;
42
+ }
43
+ /** A value with every `{ "codeUnits": [...] }` replaced by the string it denotes and every `{ "$number": name }` by the number it names, at any depth. The schema has already refused an object that holds either key and anything else. */
44
+ export function decodeValue(value) {
45
+ if (Array.isArray(value)) {
46
+ return value.map((item) => decodeValue(item));
47
+ }
48
+ if (isRecord(value)) {
49
+ const named = value.$number;
50
+ if (typeof named === "string" && Object.keys(value).length === 1) {
51
+ const decoded = NAMED_NUMBERS[named];
52
+ if (decoded === undefined) {
53
+ throw new Error(`$number names ${named}, which no corpus file may`);
54
+ }
55
+ return decoded;
56
+ }
57
+ if (isCodeUnitsObject(value)) {
58
+ return String.fromCharCode(...value.codeUnits);
59
+ }
60
+ return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, decodeValue(item)]));
61
+ }
62
+ return value;
63
+ }
64
+ //# sourceMappingURL=text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.js","sourceRoot":"","sources":["../../../src/test/conformance/text.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { CorpusFile, Manifest } from "./corpus-types.js";
2
+ /**
3
+ * Validates corpus files and the manifest against the schemas in `conformance/`, which is the whole definition of the format. The checks beside the schema are the rules JSON Schema cannot express and `conformance/README.md` lists: a case id is not repeated within a file, a manifest's `skip` lists are in ascending order, and no JSON string holds an unpaired surrogate (content that needs one is written as `{ "codeUnits": [...] }`). Nothing else is validated by hand.
4
+ */
5
+ export type Validation<T> = {
6
+ readonly ok: true;
7
+ readonly value: T;
8
+ } | {
9
+ readonly ok: false;
10
+ readonly problems: readonly string[];
11
+ };
12
+ export declare function validateCorpusFile(value: unknown): Validation<CorpusFile>;
13
+ export declare function validateManifest(value: unknown): Validation<Manifest>;
14
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/test/conformance/validate.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE9D;;GAEG;AAEH,MAAM,MAAM,UAAU,CAAC,CAAC,IACpB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GACxC;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAgFjE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,CAAC,UAAU,CAAC,CAWzE;AAWD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC,CAWrE"}
@@ -0,0 +1,85 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { fileURLToPath } from "node:url";
3
+ import Ajv2020Module from "ajv/dist/2020.js";
4
+ function readSchema(name) {
5
+ const parsed = JSON.parse(readFileSync(fileURLToPath(new URL(`../../../conformance/${name}`, import.meta.url)), "utf8"));
6
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
7
+ throw new Error(`${name} must hold a JSON object`);
8
+ }
9
+ return Object.fromEntries(Object.entries(parsed));
10
+ }
11
+ // Strict mode, so a schema keyword Ajv does not know is an error rather than ignored; unions of types are what the schema's open "any JSON value" definitions use.
12
+ // ajv ships CommonJS with a default export, which Node16 resolution types as the module and not the class.
13
+ const Ajv2020 = Ajv2020Module.default;
14
+ const ajv = new Ajv2020({
15
+ allErrors: true,
16
+ strict: true,
17
+ allowUnionTypes: true,
18
+ });
19
+ // The generic states what a document the schema accepted holds; it is the schema, not this code, that makes it true.
20
+ const checkCorpusFile = ajv.compile(readSchema("case.schema.json"));
21
+ const checkManifest = ajv.compile(readSchema("manifest.schema.json"));
22
+ function describeErrors(errors) {
23
+ if (errors === null || errors === undefined) {
24
+ return ["the schema rejected the document"];
25
+ }
26
+ return errors.map(({ instancePath, message }) => `${instancePath === "" ? "(root)" : instancePath} ${message ?? "is invalid"}`);
27
+ }
28
+ function isRecord(value) {
29
+ return typeof value === "object" && value !== null && !Array.isArray(value);
30
+ }
31
+ /** Where a JSON string, or an object key, holds an unpaired surrogate: such a document is read differently by different loaders. */
32
+ function malformedStrings(value, where) {
33
+ if (typeof value === "string") {
34
+ return value.isWellFormed() ? [] : [`${where} holds an unpaired surrogate`];
35
+ }
36
+ if (Array.isArray(value)) {
37
+ return value.flatMap((item, index) => malformedStrings(item, `${where}/${String(index)}`));
38
+ }
39
+ if (isRecord(value)) {
40
+ return Object.entries(value).flatMap(([key, item]) => [
41
+ ...malformedStrings(key, `${where}/(key)`),
42
+ ...malformedStrings(item, `${where}/${key}`),
43
+ ]);
44
+ }
45
+ return [];
46
+ }
47
+ function ruleProblems(file) {
48
+ const problems = [];
49
+ const ids = new Set();
50
+ for (const testCase of file.cases) {
51
+ if (ids.has(testCase.id)) {
52
+ problems.push(`case id ${testCase.id} is used twice in the file`);
53
+ }
54
+ ids.add(testCase.id);
55
+ }
56
+ return problems;
57
+ }
58
+ export function validateCorpusFile(value) {
59
+ const malformed = malformedStrings(value, "");
60
+ if (malformed.length > 0) {
61
+ return { ok: false, problems: malformed };
62
+ }
63
+ if (!checkCorpusFile(value)) {
64
+ return { ok: false, problems: describeErrors(checkCorpusFile.errors) };
65
+ }
66
+ const problems = ruleProblems(value);
67
+ return problems.length === 0 ? { ok: true, value } : { ok: false, problems };
68
+ }
69
+ /** Whether the ids are distinct and in ascending UTF-16 code unit order, which is the order every loader sorts in for the ASCII ids the schema allows. */
70
+ function isAscending(ids) {
71
+ return ids.every((id, index) => {
72
+ const before = ids[index - 1];
73
+ return before === undefined || before < id;
74
+ });
75
+ }
76
+ export function validateManifest(value) {
77
+ if (!checkManifest(value)) {
78
+ return { ok: false, problems: describeErrors(checkManifest.errors) };
79
+ }
80
+ const problems = Object.entries(value.files).flatMap(([name, entry]) => isAscending(entry.skip)
81
+ ? []
82
+ : [`${name}: "skip" must list distinct ids in ascending order`]);
83
+ return problems.length === 0 ? { ok: true, value } : { ok: false, problems };
84
+ }
85
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../src/test/conformance/validate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ type CorpusFunction = (...args: readonly unknown[]) => unknown;
2
+ /** The outcome of validating an input: what the schema made of it, or every issue it found. */
3
+ export type ValidateResult = {
4
+ readonly ok: true;
5
+ readonly value: unknown;
6
+ } | {
7
+ readonly ok: false;
8
+ readonly issues: readonly {
9
+ readonly path: readonly (string | number)[];
10
+ readonly code: string;
11
+ readonly message: string;
12
+ }[];
13
+ };
14
+ export declare const FUNCTIONS: Readonly<Record<string, CorpusFunction>>;
15
+ export declare const SCHEMAS: Readonly<Record<string, (input: unknown) => ValidateResult>>;
16
+ /** Exposed for the CommsError code check the runner makes on a `throws` expectation. */
17
+ export declare function errorCode(error: unknown): string | undefined;
18
+ export {};
19
+ //# sourceMappingURL=conformance-functions.helper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conformance-functions.helper.d.ts","sourceRoot":"","sources":["../../src/test/conformance-functions.helper.ts"],"names":[],"mappings":"AAwGA,KAAK,cAAc,GAAG,CAAC,GAAG,IAAI,EAAE,SAAS,OAAO,EAAE,KAAK,OAAO,CAAC;AAE/D,+FAA+F;AAC/F,MAAM,MAAM,cAAc,GACtB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAC9C;IACE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,MAAM,EAAE,SAAS;QACxB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;QAC5C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;KAC1B,EAAE,CAAC;CACL,CAAC;AAuZN,eAAO,MAAM,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAqS9D,CAAC;AAqBF,eAAO,MAAM,OAAO,EAAE,QAAQ,CAC5B,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,cAAc,CAAC,CAgBnD,CAAC;AAEF,wFAAwF;AACxF,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAE5D"}