Add check-elemco-sync: guard the method registry against catalog drift - #53
Conversation
… catalog drift js/elemco-methods.js is deliberately hand-maintained, so it can silently drift from the generated ElemCo.jl catalogs: a registry entry can point at a macro or option group that no longer exists in the pinned version, and new backend macros can stay unreachable from the UI unnoticed (e.g. the pending scf.stability/:search + UNO-CAS work will land as new scf options and macros). scripts/check-elemco-sync.js makes the drift loud: - errors (exit 1): registry macro missing from elemco-macros.js; referenced option group/field missing from elemco-options.js; the two generated catalogs pinned to different ElemCo versions - warnings: catalog macros not surfaced by the registry (curation candidates; documented "Alias for @x" macros count as covered by the original) Wired as `npm run check-elemco-sync` and chained onto both update-elemco-* scripts so every catalog regeneration is checked automatically. Currently passes clean: 26 registry entries against 43 macros / 16 option groups @ v0.16.0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a Node-based consistency check to ensure the hand-maintained ElemCo method registry (js/elemco-methods.js) stays in sync with the generated ElemCo catalogs (js/elemco-macros.js, js/elemco-options.js), and wires it into the catalog update workflows.
Changes:
- Introduces
scripts/check-elemco-sync.jsto validate macro and option-group references and report drift as errors/warnings. - Adds an
npm run check-elemco-syncscript and chains it after bothupdate-elemco-*regeneration scripts.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| scripts/check-elemco-sync.js | Adds the sync-checker CLI that loads the catalogs/registry and validates macros, option groups, and version pins. |
| package.json | Registers check-elemco-sync and runs it automatically after ElemCo catalog regeneration. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| for (const [gid, fields] of Object.entries(w.ELEMCO_GLOBAL_EXCLUDE || {})) { | ||
| checkGroup('ELEMCO_GLOBAL_EXCLUDE', gid); | ||
| const known = catalogGroups[gid] ? catalogGroups[gid].options : null; | ||
| for (const f of fields) { | ||
| if (known && !known[f]) { | ||
| errors.push(`ELEMCO_GLOBAL_EXCLUDE: field '${gid}.${f}' not in elemco-options.js (${w.ELEMCO_OPTIONS.sourceRef})`); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Confirmed and fixed in 8e9e616: groups carry fields, so known was always null. Verified by injecting a bogus excluded field: passed before the fix, exits 1 with ELEMCO_GLOBAL_EXCLUDE: field 'wf.bogus_field' not in elemco-options.js after.
| const fs = require('fs'); | ||
| const path = require('path'); | ||
|
|
||
| const JS_DIR = path.join(__dirname, '..', 'js'); | ||
|
|
||
| // The catalog files assign to `window.*`; elemco-methods.js declares consts and | ||
| // copies them onto `window` when present. Evaluate all three against one shared | ||
| // fake window and read everything back from it. | ||
| global.window = {}; | ||
| for (const f of ['elemco-macros.js', 'elemco-options.js', 'elemco-methods.js']) { | ||
| // eslint-disable-next-line no-eval | ||
| eval(fs.readFileSync(path.join(JS_DIR, f), 'utf8')); | ||
| } | ||
| const w = global.window; |
There was a problem hiding this comment.
Done in 8e9e616: the three catalog files now run via vm.runInContext in a context whose only global is the fake window; nothing from this process's globals is visible to them.
Both from Copilot's review of #53: - The ELEMCO_GLOBAL_EXCLUDE field check was dead: catalog groups keep their options under `fields`, so `known` was always null and a bogus excluded field passed silently. Verified by injecting `wf.bogus_field` before (OK) and after (ERROR, exit 1). - The three catalog files ran under eval() in this process's global scope. They now run in a vm context whose only global is the fake `window`; the script reads everything back from that. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Dependabot alert #15, high: host confusion via skipped IDN canonicalization on scheme-relative references. Transitive dev dependency only (electron-builder -> app-builder-lib -> ajv -> fast-uri), so build-time, not shipped. npm audit clean afterwards; no other package moved. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
What
js/elemco-methods.jsis deliberately hand-maintained, so it can silently drift from the generated ElemCo.jl catalogs: a registry entry can point at a macro or option group that no longer exists in the pinned version, and new backend macros can stay unreachable from the UI without anyone noticing (e.g. the pendingscf.stability/:search+ UNO-CAS work will land as new scf options and macros).scripts/check-elemco-sync.jsmakes the drift loud:elemco-macros.js; referenced option group/field missing fromelemco-options.js; the two generated catalogs pinned to different ElemCo versionsWired as
npm run check-elemco-syncand chained onto bothupdate-elemco-*scripts, so every catalog regeneration is checked automatically.Testing
@ciϕ/@scialiases of@ciphiare recognized as covered).@dfhf_gone) and a dangling group (nope) into a copy of the registry produces the two expected errors and exit 1.🤖 Generated with Claude Code