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`);
|