@hyperfixi/testing-framework 4.1.0 → 4.3.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.
@@ -376,8 +376,15 @@ export async function initDirectPathHosts(): Promise<DirectPathHosts> {
376
376
  for (const steps of scriptOf(c)) parts.push(await run(host, c, code, lang, steps));
377
377
  return parts.join(' ‖ ');
378
378
  };
379
- const rejects = (host: ScriptHost, code: string): string | undefined =>
380
- host.parse(code)?.errors?.[0]?.message.split('\n')[0];
379
+ // Two failure channels: parse errors, and the tokenizer THROWING on a
380
+ // character it does not know (the text a refused translation leaves as written).
381
+ const rejects = (host: ScriptHost, code: string): string | undefined => {
382
+ try {
383
+ return host.parse(code)?.errors?.[0]?.message.split('\n')[0];
384
+ } catch (e) {
385
+ return (e as Error).message.split('\n')[0] ?? 'threw';
386
+ }
387
+ };
381
388
 
382
389
  return {
383
390
  async runCase(c) {
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Value matrix gate — the `branch` position's operator-phrase cells (`is equal
3
+ * to`, `includes`, `is an Element`, …). See value-matrix.ts for the matrix
4
+ * and value-matrix-gate.ts for the assertions.
5
+ *
6
+ * @vitest-environment node
7
+ * Required, not a preference: under happy-dom the engines bind happy-dom's
8
+ * DOM constructors, not the jsdom window's (see
9
+ * shipped-examples-execution.test.ts).
10
+ */
11
+ import { describeValueMatrixShard } from './value-matrix-gate';
12
+
13
+ describeValueMatrixShard('branch', 'phrases');
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Value matrix gate — the `branch` cells. See value-matrix.ts for the matrix and
3
+ * value-matrix-gate.ts for the assertions; one position per file so the
4
+ * shards run in parallel.
5
+ *
6
+ * @vitest-environment node
7
+ * Required, not a preference: under happy-dom the engines bind happy-dom's
8
+ * DOM constructors, not the jsdom window's (see
9
+ * shipped-examples-execution.test.ts).
10
+ */
11
+ import { describeValueMatrixShard } from './value-matrix-gate';
12
+
13
+ describeValueMatrixShard('branch');
@@ -9,16 +9,17 @@
9
9
  *
10
10
  * This does. A CELL is one value expression in one position:
11
11
  *
12
- * - OPERANDS: eleven kinds (literal, variable, selector, possessive, `of`,
12
+ * - OPERANDS: twelve kinds (literal, variable, selector, possessive, `of`,
13
13
  * dotted, call, array, parens, a reference's property: `event's type`,
14
- * `the id of target`, and a sigil variable: `$n`), each with instances
15
- * of the value types it produces;
14
+ * `the id of target`, a sigil variable: `$n`, and a CSS length: `100px`),
15
+ * each with instances of the value types it produces;
16
16
  * - OPERATORS: arithmetic, comparison, equality, logic, membership, and the
17
17
  * prefix and postfix forms (`not`, `-`, `no`, `is empty`, `is null`,
18
18
  * `exists`, `as`), and core's operator PHRASES (`is greater than or equal
19
19
  * to`, `does not include`, `is an Element`, …);
20
- * - POSITIONS: a `put` value, a `set` value, an `if` condition, a `repeat
21
- * while` condition, a loop's count (`repeat … times`), an `increment …
20
+ * - POSITIONS: a `put` value, a `set` value, an `if` condition, an `if`
21
+ * condition with no `then` before a command that names no target
22
+ * (`branch`), a `repeat while` condition, a loop's count (`repeat … times`), an `increment …
22
23
  * by` amount, a `set` value in the second command of a chain (`chain`),
23
24
  * what a `get` reads (`get`), and two written targets: what a `set`
24
25
  * writes (`assign`) and what an `increment` counts (`count`).
@@ -112,15 +113,27 @@ export type OperandKind =
112
113
  | 'array'
113
114
  | 'parens'
114
115
  | 'reference'
115
- | 'sigil';
116
+ | 'sigil'
117
+ | 'length';
116
118
 
117
119
  export type Position =
118
- 'put' | 'set' | 'if' | 'while' | 'times' | 'increment' | 'chain' | 'get' | 'assign' | 'count';
120
+ | 'put'
121
+ | 'set'
122
+ | 'if'
123
+ | 'branch'
124
+ | 'while'
125
+ | 'times'
126
+ | 'increment'
127
+ | 'chain'
128
+ | 'get'
129
+ | 'assign'
130
+ | 'count';
119
131
 
120
132
  export const POSITIONS: readonly Position[] = [
121
133
  'put',
122
134
  'set',
123
135
  'if',
136
+ 'branch',
124
137
  'while',
125
138
  'times',
126
139
  'increment',
@@ -164,7 +177,7 @@ export interface MatrixCell {
164
177
  */
165
178
  export const FIXTURE =
166
179
  '<div id="out">∅</div>' +
167
- '<p id="a" class="x" title="t1">6</p>' +
180
+ '<p id="a" class="x" title="t1" aria-pressed="true">6</p>' +
168
181
  '<div id="w"><p class="w">w</p><p class="w">v</p></div>' +
169
182
  '<button id="b">b</button>';
170
183
 
@@ -197,12 +210,16 @@ export const OPERANDS: readonly Operand[] = [
197
210
  { kind: 'possessive', type: 'num', text: "obj's v" },
198
211
  { kind: 'possessive', type: 'num', text: "arr's length" },
199
212
  { kind: 'possessive', type: 'num', text: "#a's textContent's length" },
213
+ // A property name a lexicon translates and no reader brings back: es wrote
214
+ // `hijos`, which read back as a property named `hijos`.
215
+ { kind: 'possessive', type: 'num', text: "#w's children's length" },
200
216
  { kind: 'of', type: 'nstr', text: 'textContent of #a' },
201
217
  { kind: 'of', type: 'nstr', text: 'the textContent of #a' },
202
218
  { kind: 'of', type: 'num', text: 'v of obj' },
203
219
  { kind: 'of', type: 'num', text: 'length of arr' },
204
220
  { kind: 'of', type: 'str', text: '@title of #a' },
205
221
  { kind: 'of', type: 'num', text: 'v of w of obj' },
222
+ { kind: 'of', type: 'num', text: 'the length of the children of #w' },
206
223
  { kind: 'of', type: 'arr', text: 'textContent of .w' },
207
224
  { kind: 'dotted', type: 'nstr', text: '#a.textContent' },
208
225
  { kind: 'dotted', type: 'str', text: 'me.id' },
@@ -213,8 +230,15 @@ export const OPERANDS: readonly Operand[] = [
213
230
  { kind: 'call', type: 'nstr', text: 'String(n)' },
214
231
  { kind: 'call', type: 'str', text: 's.toUpperCase()' },
215
232
  { kind: 'call', type: 'bool', text: 'Array.isArray(arr)' },
233
+ // A word a lexicon translates, inside a call's arguments, which every reader
234
+ // takes as written: es `Math.max(n, verdadero)`.
235
+ { kind: 'call', type: 'num', text: 'Math.max(n, true)' },
216
236
  { kind: 'array', type: 'arr', text: '[1, 2]' },
217
237
  { kind: 'array', type: 'arr', text: '[n, 2]' },
238
+ // A word some language's lexicon translates, inside an array in a larger
239
+ // expression: every reader takes a bracket group whole, so a renderer that
240
+ // localized `true` there (es `2 is in [verdadero, n]`) lost it in all 23.
241
+ { kind: 'array', type: 'arr', text: '[true, n]' },
218
242
  { kind: 'parens', type: 'num', text: '(n + 1)' },
219
243
  { kind: 'parens', type: 'str', text: '(s + "c")' },
220
244
  { kind: 'parens', type: 'bool', text: '(n > 1)' },
@@ -235,6 +259,10 @@ export const OPERANDS: readonly Operand[] = [
235
259
  // a variable, but no cell had one: semantic's English dropped a whole loop
236
260
  // counted by one (`repeat $n times`), and every translation with it.
237
261
  { kind: 'sigil', type: 'num', text: '$n' },
262
+ // A number with a CSS unit is one string upstream (`100px`): every reader
263
+ // split it, so `set my *width to 100px` was refused in all 24 languages.
264
+ { kind: 'length', type: 'str', text: '100px' },
265
+ { kind: 'length', type: 'str', text: '50%' },
238
266
  ];
239
267
 
240
268
  /** An operator slot, and the value types that fill it. */
@@ -330,7 +358,16 @@ export const BINARY_OPERATORS: readonly BinaryOperator[] = [
330
358
  representative: true,
331
359
  signatures: [sig('num', 'arr', '2', '[1, 2, 6]', 'bool')],
332
360
  },
333
- { op: 'matches', representative: true, signatures: [sig('one', 'none', '#a', '.x', 'bool')] },
361
+ {
362
+ op: 'matches',
363
+ representative: true,
364
+ // An attribute selector whose value a lexicon translates: es wrote
365
+ // `<[aria-pressed=verdadero]/>`, another selector, in all 23 languages.
366
+ signatures: [
367
+ sig('one', 'none', '#a', '.x', 'bool'),
368
+ sig('one', 'none', '#a', '<[aria-pressed=true]/>', 'bool'),
369
+ ],
370
+ },
334
371
  // Operator PHRASES (the after-85 handoff, part 2): the words each language
335
372
  // renders for them are read back by the join and the sense table, which no
336
373
  // single-word operator exercises. One of each class is representative, so the
@@ -623,6 +660,7 @@ const TEMPLATES: Record<Position, (expression: string) => string> = {
623
660
  put: e => `on click put ${e} into #out`,
624
661
  set: e => `on click set x to ${e} then put x into #out`,
625
662
  if: e => `on click if ${e} then put "Y" into #out else put "N" into #out end`,
663
+ branch: e => `on click if ${e} add .y else add .n end then put my className into #out`,
626
664
  while: e => `on click set i to 0 then repeat while i < ${e} increment i end then put i into #out`,
627
665
  times: e => `on click set i to 0 then repeat ${e} times increment i end then put i into #out`,
628
666
  increment: e => `on click set i to 1 then increment i by ${e} then put i into #out`,
@@ -649,10 +687,18 @@ const TEMPLATES: Record<Position, (expression: string) => string> = {
649
687
  * `it`, but its role took no literal, so English dropped `get "hello"`, `get
650
688
  * 3` and `get true` whole (and every translation with them) while `get n` and
651
689
  * `get #a's textContent` read.
690
+ *
691
+ * A `branch` condition is every `if` condition but the names (none failed
692
+ * there that `if` did not). The `if` cells write `then` and a `put` with its
693
+ * target, so a reader always saw where the condition ended. Without `then`, an
694
+ * SOV language writes the branch's first role right after the condition, and
695
+ * its reader has to find the seam: tr read `if 2 is in arr add .a end` as
696
+ * `if 2 add .a to is in arr end` (its destination marker is optional, and `in`
697
+ * is also one), with every operand, and the `if` cells all passed.
652
698
  */
653
699
  function positionsFor(type: ValueType, bare: boolean, group: MatrixCell['group']): Position[] {
654
700
  const out: Position[] = ['put', 'set'];
655
- if (type === 'bool' || bare) out.push('if');
701
+ if (type === 'bool' || bare) out.push('if', 'branch');
656
702
  if (type === 'num' || type === 'nstr') out.push('while', 'times', 'increment');
657
703
  if (group !== 'operand-operator') out.push('chain', 'get');
658
704
  return out;