Skip to content

Commit 125be6a

Browse files
feat: avoid fatal error (#137)
1 parent cefd2c3 commit 125be6a

File tree

3 files changed

+4375
-4902
lines changed

3 files changed

+4375
-4902
lines changed

src/__tests__/index.js

+20-9
Original file line numberDiff line numberDiff line change
@@ -5,34 +5,36 @@ import reduceCalc from '../../dist';
55

66
const postcssOpts = { from: undefined };
77

8-
function testValue(t, fixture, expected = null, opts = {}) {
8+
function testValue(t, fixture, expected = null, opts = {}, plan = 1) {
99
if (expected === null) {
1010
expected = fixture;
1111
}
1212

1313
fixture = `foo{bar:${fixture}}`;
1414
expected = `foo{bar:${expected}}`;
1515

16-
return testCss(t, fixture, expected, opts);
16+
return testCss(t, fixture, expected, opts, plan);
1717
}
1818

19-
function testCss(t, fixture, expected = null, opts = {}) {
19+
function testCss(t, fixture, expected = null, opts = {}, plan = 1) {
2020
if (expected === null) {
2121
expected = fixture;
2222
}
2323

24-
t.plan(1);
24+
t.plan(plan);
2525

2626
return postcss(reduceCalc(opts)).process(fixture, postcssOpts).then(result => {
2727
t.deepEqual(result.css, expected);
28+
29+
return result;
2830
});
2931
}
3032

31-
async function testThrows(t, fixture, expected, opts) {
32-
fixture = `foo{bar:${fixture}}`;
33+
async function testThrows(t, fixture, expected, warning, opts) {
34+
const result = await testValue(t, fixture, expected, opts, 2);
35+
const warnings = result.warnings();
3336

34-
const error = await t.throwsAsync(() => postcss(reduceCalc(opts)).process(fixture, postcssOpts))
35-
t.is(error.message, expected);
37+
t.is(warnings[0].text, warning);
3638
}
3739

3840
test(
@@ -523,7 +525,6 @@ test(
523525
'calc(100% + 1px)',
524526
'calc(100% + 1px)',
525527
{ warnWhenCannotResolve: true },
526-
[ /^Could not reduce expression:/ ]
527528
);
528529

529530
test(
@@ -678,13 +679,15 @@ test(
678679
'should throw an exception when attempting to divide by zero',
679680
testThrows,
680681
'calc(500px/0)',
682+
'calc(500px/0)',
681683
'Cannot divide by zero'
682684
);
683685

684686
test(
685687
'should throw an exception when attempting to divide by unit (#1)',
686688
testThrows,
687689
'calc(500px/2px)',
690+
'calc(500px/2px)',
688691
'Cannot divide by "px", number expected',
689692
);
690693

@@ -1170,3 +1173,11 @@ test(
11701173
'calc(1px + 2unknown)',
11711174
'calc(1px + 2unknown)'
11721175
);
1176+
1177+
test(
1178+
'error with parsing',
1179+
testThrows,
1180+
'calc(10pc + unknown)',
1181+
'calc(10pc + unknown)',
1182+
'Lexical error on line 1: Unrecognized text.\n\n Erroneous area:\n1: 10pc + unknown\n^.........^'
1183+
);

src/lib/transform.js

+44-32
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,58 @@
1-
import selectorParser from 'postcss-selector-parser';
2-
import valueParser from 'postcss-value-parser';
1+
import selectorParser from "postcss-selector-parser";
2+
import valueParser from "postcss-value-parser";
33

44
// eslint-disable-next-line import/no-unresolved
5-
import { parser } from '../parser';
5+
import { parser } from "../parser";
66

7-
import reducer from './reducer';
8-
import stringifier from './stringifier';
7+
import reducer from "./reducer";
8+
import stringifier from "./stringifier";
99

1010
const MATCH_CALC = /((?:-(moz|webkit)-)?calc)/i;
1111

1212
function transformValue(value, options, result, item) {
13-
return valueParser(value).walk(node => {
14-
// skip anything which isn't a calc() function
15-
if (node.type !== 'function' || !MATCH_CALC.test(node.value)) {
16-
return node;
17-
}
13+
return valueParser(value)
14+
.walk(node => {
15+
// skip anything which isn't a calc() function
16+
if (node.type !== "function" || !MATCH_CALC.test(node.value)) {
17+
return node;
18+
}
1819

19-
// stringify calc expression and produce an AST
20-
const contents = valueParser.stringify(node.nodes);
21-
const ast = parser.parse(contents);
20+
// stringify calc expression and produce an AST
21+
const contents = valueParser.stringify(node.nodes);
22+
const ast = parser.parse(contents);
2223

23-
// reduce AST to its simplest form, that is, either to a single value
24-
// or a simplified calc expression
25-
const reducedAst = reducer(ast, options.precision);
24+
// reduce AST to its simplest form, that is, either to a single value
25+
// or a simplified calc expression
26+
const reducedAst = reducer(ast, options.precision);
2627

27-
// stringify AST and write it back
28-
node.type = 'word';
29-
node.value = stringifier(
30-
node.value,
31-
reducedAst,
32-
value,
33-
options,
34-
result,
35-
item);
28+
// stringify AST and write it back
29+
node.type = "word";
30+
node.value = stringifier(
31+
node.value,
32+
reducedAst,
33+
value,
34+
options,
35+
result,
36+
item
37+
);
3638

37-
return false;
38-
}).toString();
39+
return false;
40+
})
41+
.toString();
3942
}
4043

4144
function transformSelector(value, options, result, item) {
4245
return selectorParser(selectors => {
4346
selectors.walk(node => {
4447
// attribute value
4548
// e.g. the "calc(3*3)" part of "div[data-size="calc(3*3)"]"
46-
if (node.type === 'attribute' && node.value) {
49+
if (node.type === "attribute" && node.value) {
4750
node.setValue(transformValue(node.value, options, result, item));
4851
}
4952

5053
// tag value
5154
// e.g. the "calc(3*3)" part of "div:nth-child(2n + calc(3*3))"
52-
if (node.type === 'tag') {
55+
if (node.type === "tag") {
5356
node.value = transformValue(node.value, options, result, item);
5457
}
5558

@@ -59,9 +62,18 @@ function transformSelector(value, options, result, item) {
5962
}
6063

6164
export default (node, property, options, result) => {
62-
const value = property === "selector"
63-
? transformSelector(node[property], options, result, node)
64-
: transformValue(node[property], options, result, node);
65+
let value = node[property];
66+
67+
try {
68+
value =
69+
property === "selector"
70+
? transformSelector(node[property], options, result, node)
71+
: transformValue(node[property], options, result, node);
72+
} catch (error) {
73+
result.warn(error.message, { node });
74+
75+
return;
76+
}
6577

6678
// if the preserve option is enabled and the value has changed, write the
6779
// transformed value into a cloned node which is inserted before the current

0 commit comments

Comments
 (0)