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(