From 2fe0ed69504a73485cd072b17feef813a669c2ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Niedzi=C3=B3=C5=82ka?= Date: Fri, 25 Sep 2026 11:30:37 +0200 Subject: [PATCH] fix(processor): validate external composes references `composes: x from "file.css"` didn't check that `x` exists in `file.css`. The missing class was only detected when generating compositions, which crashed with `TypeError: composition is not iterable`. Fail early with the same `Invalid composes reference` error as local references. Fixes #1167 Co-Authored-By: Claude Opus 5.5 --- .changeset/validate-external-composes.md | 5 +++++ packages/processor/plugins/composition.js | 10 ++++++++++ packages/processor/test/composition.test.js | 10 ++++++++++ 3 files changed, 25 insertions(+) create mode 100644 .changeset/validate-external-composes.md diff --git a/.changeset/validate-external-composes.md b/.changeset/validate-external-composes.md new file mode 100644 index 000000000..19842fa6c --- /dev/null +++ b/.changeset/validate-external-composes.md @@ -0,0 +1,5 @@ +--- +"@modular-css/processor": patch +--- + +Fail with `Invalid composes reference` when `composes: x from "file.css"` references a class that doesn't exist in that file, instead of crashing later with `composition is not iterable`. diff --git a/packages/processor/plugins/composition.js b/packages/processor/plugins/composition.js index 1d434fc2c..d86090f7a 100644 --- a/packages/processor/plugins/composition.js +++ b/packages/processor/plugins/composition.js @@ -75,6 +75,16 @@ module.exports = () => ({ if(source) { // External refs should already exist, so they don't get added ref = selectorKey(source, name); + + if(!files[source].classes[name]) { + const rel = relative(processor.options.cwd, source); + + throw decl.error( + `Invalid composes reference, .${name} does not exist in ${rel}`, { + word: name, + } + ); + } } else if(global) { ref = processor._addGlobal(name); } else { diff --git a/packages/processor/test/composition.test.js b/packages/processor/test/composition.test.js index 52488c6d6..a52244788 100644 --- a/packages/processor/test/composition.test.js +++ b/packages/processor/test/composition.test.js @@ -37,6 +37,16 @@ describe("/processor.js", () => { ); }); + it("should fail if a composition references a non-existant class in another file", async (t) => { + await t.assert.rejects( + async () => processor.string( + path.join(__dirname, "specimens/invalid-external-composition.css"), + `.a { composes: nope from "./simple.css"; }` + ), + /Invalid composes reference, \.nope does not exist in packages\/processor\/test\/specimens\/simple\.css/ + ); + }); + it("should fail if a composition references a non-existant file", async (t) => { await t.assert.rejects( async () => processor.string(