File size: 2,821 Bytes
10656db
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#!/usr/bin/env node
/* gen-css-keywords.mjs: regenerate public/dssl/css-keywords.js from the MDN CSS data (the `mdn-data` package).
 *
 *   npm install --prefix /tmp/mdn mdn-data
 *   node scripts/gen-css-keywords.mjs /tmp/mdn/node_modules/mdn-data
 *
 * The compiler refuses a value word it does not know (a typo should be loud). That list used to be written by hand, so valid CSS such as
 * `font-variant-numeric: tabular-nums` was refused. This reads every value grammar CSS defines and keeps the bare keywords.
 * Not run at install time: the result is committed, so the engine has no dependency. */
import { readFileSync, writeFileSync } from 'node:fs';
import { createRequire } from 'node:module';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

const dir = process.argv[2];
if (!dir) { console.error('usage: node scripts/gen-css-keywords.mjs <path to mdn-data>'); process.exit(2); }
const require = createRequire(path.join(dir, 'x.js'));
const props = require(path.join(dir, 'css/properties.json'));
const defs = require(path.join(dir, 'css/definitions.json'));
const syntaxes = require(path.join(dir, 'css/syntaxes.json'));

const words = new Set();
const take = (syntax) => {
  if (!syntax || typeof syntax !== 'string') return;
  const s = syntax.replace(/<[^>]*>/g, ' ').replace(/\{[^}]*\}/g, ' ').replace(/'[^']*'/g, ' ').replace(/"[^"]*"/g, ' ');
  for (const m of s.matchAll(/(?<![\w.-])(-?[a-z][a-z0-9-]*)(?![\w(-])/g)) words.add(m[1]);
};
for (const p of Object.values(props)) take(p.syntax);
for (const d of Object.values(defs || {})) take(typeof d === 'string' ? d : d && d.syntax);
for (const d of Object.values(syntaxes || {})) take(typeof d === 'string' ? d : d && d.syntax);
// syntax glue words that are not values
for (const w of ['e', 'n', 'ch']) words.delete(w);
const list = [...words].filter((w) => w.length > 0).sort();
// every property CSS has, except the obsolete ones and the custom-property placeholder
const names = Object.entries(props).filter(([n, p]) => n !== '--*' && p.status !== 'obsolete').map(([n]) => n).sort();
const out = `/* css-keywords.js: GENERATED by scripts/gen-css-keywords.mjs from the MDN CSS data (${list.length} words, ${names.length} properties). Do not edit by hand.
 * Every bare keyword any CSS property accepts, so valid CSS is never refused as "unknown value", and every property name,
 * so \`direction\` or \`-webkit-user-select\` is never refused as "unknown property". */
export const CSS_VALUE_WORDS = ${JSON.stringify(list.join(','))};
export const CSS_PROPERTY_NAMES = ${JSON.stringify(names.join(','))};
`;
writeFileSync(path.join(path.dirname(fileURLToPath(import.meta.url)), '../public/dssl/css-keywords.js'), out);
console.log(`wrote public/dssl/css-keywords.js with ${list.length} words and ${names.length} properties`);