Skip to content

Commit 0aa00b7

Browse files
committed
✅ add unit test for checkDelegates()
1 parent d520bf2 commit 0aa00b7

File tree

6 files changed

+88
-61
lines changed

6 files changed

+88
-61
lines changed

.github/workflows/check.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ jobs:
1313
name: 'nvm install lts/* && npm ci'
1414
with:
1515
node-version: lts/*
16+
- run: npm run test
1617
- run: npm run check

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
# ECMA, TC39 Meeting Notes
1+
# TC39 Meeting Notes
22

33
See [`meetings/`](https://github.com/tc39/notes/tree/master/meetings).

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"private": true,
33
"scripts": {
4-
"check": "./scripts/check-delegates.js",
5-
"test": "echo \"Error: no test specified\" && exit 1"
4+
"check": "node -e 'import(\"./scripts/check-delegates.mjs\").then(cd => cd.checkDelegates())'",
5+
"test": "node ./scripts/check-delegates-test.mjs"
66
}
77
}

scripts/check-delegates-test.mjs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { strict as assert } from 'node:assert';
2+
import { checkDelegates } from './check-delegates.mjs';
3+
4+
const lex = `Rob Palmer (RPR)\nUjjwal Sharma (USA)\nChris de Almeida (CDA)`;
5+
const missing = `Chris de Almeida (CDA)\nRob Palmer\nUjjwal Sharma (USA)`;
6+
const uppercaseLatin = `Chris de Almeida (CDA)\nRob Palmer (竄)\nUjjwal Sharma (USA)`;
7+
const twoLetter = `Chris de Almeida (CDA)\nRob Palmer (RP)\nUjjwal Sharma (USA)`;
8+
const threeLetter = `Chris de Almeida (CDA)\nRob Palmer (ROBPALMER)\nUjjwal Sharma (USA)`;
9+
const duplicate = `Chris de Almeida (CDA)\nRob Palmer (RPR)\nUjjwal Sharma (USA)\nUjjwal Sharma (USA)`;
10+
const valid = `Chris de Almeida (CDA)\nRob Palmer (RPR)\nUjjwal Sharma (USA)`;
11+
12+
assert.throws(()=>checkDelegates(lex), { message: /Not in lexicographic order/});
13+
assert.throws(()=>checkDelegates(missing), { message: /Missing abbreviation for/});
14+
assert.throws(()=>checkDelegates(uppercaseLatin), { message: /Abbreviations must be all uppercase Latin letters/});
15+
assert.throws(()=>checkDelegates(twoLetter), { message: /not in allowlist. New delegate abbreviations must be three letters/});
16+
assert.throws(()=>checkDelegates(threeLetter), { message: /New delegate abbreviations must be three letters/});
17+
assert.throws(()=>checkDelegates(duplicate), { message: /Conflicting usage on line/});
18+
19+
assert.doesNotThrow(()=>checkDelegates(valid));

scripts/check-delegates.js

Lines changed: 0 additions & 58 deletions
This file was deleted.

scripts/check-delegates.mjs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#!/usr/bin/env node
2+
3+
import fs from 'fs';
4+
5+
export function checkDelegates(contents = fs.readFileSync('./delegates.txt', 'utf8').toString()) {
6+
7+
console.debug('checking delegates...');
8+
9+
// List of delegate abbreviations that predate the 3-letter
10+
// requirement. Do not change this!
11+
const TWO_LETTER_ABBRS = new Set([
12+
'AC', 'AH', 'AK', 'AR', 'AS', 'BB', 'BE', 'BG', 'BM', 'BN', 'BS',
13+
'BT', 'BZ', 'CF', 'CM', 'CP', 'DC', 'DD', 'DE', 'DH', 'DL', 'DS',
14+
'DT', 'EA', 'EF', 'ET', 'EY', 'FN', 'FP', 'GB', 'GI', 'GN', 'GY',
15+
'IH', 'IS', 'IT', 'JB', 'JH', 'JK', 'JM', 'JN', 'JP', 'JS', 'JT',
16+
'KG', 'KM', 'KR', 'KS', 'LB', 'LH', 'LL', 'LM', 'MB', 'MF', 'MH',
17+
'MM', 'MP', 'MS', 'NC', 'NH', 'NL', 'NM', 'OH', 'PJ', 'PL', 'RB',
18+
'RH', 'RW', 'RX', 'SC', 'SK', 'SM', 'SP', 'TC', 'TD', 'TS', 'TW',
19+
'VM', 'WH', 'YK', 'ZB',
20+
]);
21+
22+
23+
const re = /^(?<name>[^(]+)(?: \((?<abbr>[^)]*)\))?$/;
24+
const abbrs = new Map;
25+
const lines = contents.split('\n');
26+
27+
let lineNumber = 1;
28+
let previousLine = '';
29+
30+
for (const line of lines) {
31+
if (line.length === 0) continue;
32+
const match = re.exec(line);
33+
const {name, abbr} = match.groups;
34+
35+
if (previousLine.localeCompare(line, 'en') > 0) {
36+
throw new Error(`Line ${lineNumber}: Not in lexicographic order.`);
37+
}
38+
39+
if (abbr == null) {
40+
throw new Error(`Line ${lineNumber}: Missing abbreviation for ${JSON.stringify(line)}.`);
41+
}
42+
43+
if (!/^[A-Z]+$/.test(abbr)) {
44+
throw new Error(`Line ${lineNumber}: Abbreviations must be all uppercase Latin letters.`);
45+
}
46+
47+
if (abbr.length === 2) {
48+
if (!TWO_LETTER_ABBRS.has(abbr)) {
49+
throw new Error(`Line ${lineNumber}: 2-letter abbreviation ${JSON.stringify(abbr)} not in allowlist. New delegate abbreviations must be three letters.`);
50+
}
51+
} else if (abbr.length !== 3) {
52+
throw new Error(`Line ${lineNumber}: Invalid abbreviation ${JSON.stringify(abbr)}. New delegate abbreviations must be three letters.`);
53+
}
54+
55+
if (abbrs.has(abbr)) {
56+
throw new Error(`Line ${lineNumber}: Duplicate abbreviation ${JSON.stringify(abbr)}. Conflicting usage on line ${abbrs.get(abbr)}.`);
57+
}
58+
abbrs.set(abbr, lineNumber);
59+
60+
previousLine = line;
61+
++lineNumber;
62+
}
63+
64+
console.debug('...delegates are valid\n');
65+
}

0 commit comments

Comments
 (0)