rastrillo / fiesta Public

Clone
git clone https://amadan.net/rastrillo/fiesta

Plain git — no account needed to clone.

Download

Download this file

1// strings_node drives the string lookup one script carries,
2// fiestaPickLang and fiestaWord, in plain Node against a stub page.
3// Both datetime.js and select.js carry a copy (each enhancement is one
4// script tag), so the script's file name is the one argument:
5//
6// echo '{"registry":["en","pt-PT"],"tags":["pt-BR",""]}' |
7// node node/strings_node.mjs datetime.js
8//
9// check/strings_test.go is the only caller. It reads back one JSON
10// object: "pick", fiestaPickLang's answer for each tag on stdin plus
11// one for undefined under "<undefined>", against a registry holding
12// an (empty) table per tag named; and "word", fiestaWord's answer in
13// five scenarios on a stub element, four in a lang="es" document whose
14// table says "Tabla": "both" (attribute "Atributo" and the table),
15// "empty" (an empty attribute and the table), "table" (no attribute)
16// and "neither" (no attribute, no table, so the fallback "English");
17// and "notable", a lang="de" document with only that es table and no
18// attribute, the fallback again. The word scenarios build their own
19// tables, so stdin's registry is for "pick" alone.
20//
21// The page is the least DOM either script touches on load: a document
22// that is still loading, with a root carrying lang, and a self holding
23// the registry. The script's page half registers its listeners and
24// waits for DOMContentLoaded, which never comes; the lookup is read
25// off module.exports, which both scripts fill behind their guard.
26import { readFileSync } from "node:fs";
27import vm from "node:vm";
28
29const name = process.argv[2];
30if (!name) {
31 process.stderr.write("usage: strings_node.mjs <datetime.js | select.js>\n");
32 process.exit(2);
33}
34const src = readFileSync(new URL("../../js/" + name, import.meta.url), "utf8");
35
36const chunks = [];
37for await (const chunk of process.stdin) chunks.push(chunk);
38// Go encodes a nil slice as null, which a default would not fill.
39const stdin = JSON.parse(Buffer.concat(chunks).toString("utf8") || "{}");
40const registry = stdin.registry || [];
41const tags = stdin.tags || [];
42
43// load evaluates the script in a fresh context whose document says
44// lang and whose self.fiestaStrings is strings, and returns what it
45// exported.
46function load(lang, strings) {
47 const root = { lang, getAttribute: (k) => (k === "lang" ? lang : null) };
48 const document = {
49 readyState: "loading",
50 documentElement: root,
51 addEventListener() {},
52 querySelectorAll: () => [],
53 };
54 const self = { fiestaStrings: strings };
55 const module = { exports: {} };
56 const context = { document, self, window: self, module, exports: module.exports, setTimeout, clearTimeout };
57 vm.runInNewContext(src, context, { filename: name });
58 return module.exports;
59}
60
61// An element with attributes and nothing else.
62function element(attrs) {
63 return { getAttribute: (k) => (Object.prototype.hasOwnProperty.call(attrs, k) ? attrs[k] : null) };
64}
65
66const out = { pick: {}, word: {} };
67
68{
69 const tables = {};
70 for (const tag of registry) tables[tag] = {};
71 const { fiestaPickLang } = load("en", tables);
72 if (typeof fiestaPickLang !== "function") {
73 process.stderr.write(name + " does not export fiestaPickLang\n");
74 process.exit(1);
75 }
76 for (const tag of tags) out.pick[tag] = fiestaPickLang(tag, tables);
77 out.pick["<undefined>"] = fiestaPickLang(undefined, tables);
78}
79
80{
81 const table = { es: { "date-set": "Tabla" } };
82 const withTable = load("es", table).fiestaWord;
83 const without = load("es", {}).fiestaWord;
84 if (typeof withTable !== "function") {
85 process.stderr.write(name + " does not export fiestaWord\n");
86 process.exit(1);
87 }
88 out.word.both = withTable(element({ "data-rst-date-set": "Atributo" }), "date-set", "English");
89 out.word.empty = withTable(element({ "data-rst-date-set": "" }), "date-set", "English");
90 out.word.table = withTable(element({}), "date-set", "English");
91 out.word.neither = without(element({}), "date-set", "English");
92 out.word.notable = load("de", table).fiestaWord(element({}), "date-set", "English");
93}
94
95process.stdout.write(JSON.stringify(out));
96