From a48c56d0eb83d40dc92c60b26cc09fd4ca66aaca Mon Sep 17 00:00:00 2001 From: Cameron Moon Date: Wed, 4 Jun 2025 14:25:46 +1000 Subject: [PATCH 1/2] Raise error on invalid @value definitions --- index.js | 7 ++++++- index.test.js | 8 +++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 16d079e..c6c82de 100644 --- a/index.js +++ b/index.js @@ -38,7 +38,12 @@ const replaceValueSymbols = (valueString, replacements) => { }; const getDefinition = (atRule, existingDefinitions, requiredDefinitions) => { - const [/* match */, name, middle, value, end] = matchValueDefinition.exec(atRule.params); + const matches = matchValueDefinition.exec(atRule.params); + if (!matches) { + throw atRule.error('Invalid @value definition'); + } + + const [/* match */, name, middle, value, end] = matches; const valueWithReplacements = replaceValueSymbols(value, existingDefinitions); if (!requiredDefinitions) { diff --git a/index.test.js b/index.test.js index 9e1ab6a..687d412 100644 --- a/index.test.js +++ b/index.test.js @@ -67,12 +67,18 @@ test('gives an error when path to imported file is wrong', async (t) => { await t.expect(processor.process(input, parserOpts)).rejects.toThrow("Can't resolve './non-existent-file.css'"); }); -test('gives an error when @value statement is invalid', async (t) => { +test('gives an error when @value import statement is invalid', async (t) => { const input = '@value , from "./colors.css"'; const processor = postcss([plugin]); await t.expect(processor.process(input, parserOpts)).rejects.toThrow('@value statement "" is invalid!'); }); +test('gives an error when @value declaration is invalid', async (t) => { + const input = '@value oops;'; + const processor = postcss([plugin]); + await t.expect(processor.process(input, parserOpts)).rejects.toThrow('Invalid @value definition'); +}); + test('shouldn\'t break on draft spec syntax', async (t) => { await run( t, From 0deb388e0d764a6825af68c8160706edefddd40d Mon Sep 17 00:00:00 2001 From: Cameron Moon Date: Wed, 4 Jun 2025 14:41:00 +1000 Subject: [PATCH 2/2] warn, don't error --- index.js | 5 ++++- index.test.js | 18 +++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/index.js b/index.js index c6c82de..8c80a2b 100644 --- a/index.js +++ b/index.js @@ -40,7 +40,7 @@ const replaceValueSymbols = (valueString, replacements) => { const getDefinition = (atRule, existingDefinitions, requiredDefinitions) => { const matches = matchValueDefinition.exec(atRule.params); if (!matches) { - throw atRule.error('Invalid @value definition'); + return null; } const [/* match */, name, middle, value, end] = matches; @@ -115,6 +115,9 @@ const walk = async (requiredDefinitions, walkFile, root, result) => { } const newDefinitions = getDefinition(atRule, existingDefinitions, requiredDefinitions); + if (!newDefinitions) { + result.warn(`Invalid value definition: ${atRule.params}`); + } return Object.assign(existingDefinitions, newDefinitions); }; diff --git a/index.test.js b/index.test.js index 687d412..579766a 100644 --- a/index.test.js +++ b/index.test.js @@ -51,7 +51,7 @@ test('should remove exports if noEmitExports is true', async (t) => { await run(t, '@value red blue;', '', { noEmitExports: true }); }); -test('gives an error when there is no semicolon between lines', async (t) => { +test('gives a warning when there is no semicolon between lines', async (t) => { const input = '@value red blue\n@value green yellow'; const processor = postcss([plugin]); const result = await processor.process(input, { from: undefined }); @@ -61,6 +61,16 @@ test('gives an error when there is no semicolon between lines', async (t) => { t.expect(warnings[0].text).toBe('Invalid value definition: red blue\n@value green yellow'); }); +test('gives a warning when @value definition is invalid', async (t) => { + const input = '@value oops:;'; + const processor = postcss([plugin]); + const result = await processor.process(input, { from: undefined }); + const warnings = result.warnings(); + + t.expect(warnings.length).toBe(1); + t.expect(warnings[0].text).toBe('Invalid value definition: oops:'); +}); + test('gives an error when path to imported file is wrong', async (t) => { const input = '@value red from "./non-existent-file.css"'; const processor = postcss([plugin]); @@ -73,12 +83,6 @@ test('gives an error when @value import statement is invalid', async (t) => { await t.expect(processor.process(input, parserOpts)).rejects.toThrow('@value statement "" is invalid!'); }); -test('gives an error when @value declaration is invalid', async (t) => { - const input = '@value oops;'; - const processor = postcss([plugin]); - await t.expect(processor.process(input, parserOpts)).rejects.toThrow('Invalid @value definition'); -}); - test('shouldn\'t break on draft spec syntax', async (t) => { await run( t,