Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix false positives for negative numbers in function-calc-no-invalid #3921

Merged
merged 1 commit into from Apr 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 21 additions & 9 deletions lib/rules/function-calc-no-invalid/__tests__/index.js
Expand Up @@ -49,6 +49,18 @@ testRule(rule, {
},
{
code: ".foo {width: calc(100px - calc(80px * 2));}"
},
{
code: "a { margin-left: calc(-6 * 20px); }"
},
{
code: "a { margin-left: calc(+6 * 20px); }"
},
{
code: "a { margin-left: calc(-6 * -20px); }"
},
{
code: "a { margin-left: calc(+6 * +20px); }"
}
],

Expand All @@ -72,14 +84,14 @@ testRule(rule, {
description: "invalid",
message: messages.expectedExpression(),
line: 1,
column: 19
column: 21
},
{
code: ".foo {width: calc(100% - - 80px);}",
description: "invalid",
message: messages.expectedExpression(),
line: 1,
column: 26
column: 28
},
{
code: ".foo {width: calc(100% -);}",
Expand Down Expand Up @@ -283,19 +295,19 @@ testRule(rule, {
code: ".foo {width: calc(100% - -#{$foo});}",
message: messages.expectedExpression(),
line: 1,
column: 26
column: 27
},
{
code: ".foo {width: calc(-#{$foo});}",
message: messages.expectedExpression(),
line: 1,
column: 19
column: 20
},
{
code: ".foo {width: calc(100% - - -#{$foo});}",
message: messages.expectedExpression(),
line: 1,
column: 26
column: 29
}
]
});
Expand Down Expand Up @@ -346,19 +358,19 @@ testRule(rule, {
code: ".foo {width: calc(100% - -@foo);}",
message: messages.expectedExpression(),
line: 1,
column: 26
column: 27
},
{
code: ".foo {width: calc(-@foo);}",
message: messages.expectedExpression(),
line: 1,
column: 19
column: 20
},
{
code: ".foo {width: calc(100% - - -@foo);}",
message: messages.expectedExpression(),
line: 1,
column: 26
column: 29
}
]
});
Expand Down Expand Up @@ -389,7 +401,7 @@ testRule(rule, {
code: "export default <a style={{ width: 'calc(100% - - 80px)' }} />;",
message: messages.expectedExpression(),
line: 1,
column: 47
column: 49
}
]
});
Expand Up @@ -66,6 +66,94 @@ it("parseCalcExpression parse to ast", () => {
unit: "px",
value: 80
});
expect(parse("calc(-100 * -80px)")).toEqual({
left: {
source: { end: { index: 9 }, start: { index: 5 } },
type: "Value",
sign: "-",
value: -100
},
operator: "*",
right: {
source: { end: { index: 17 }, start: { index: 12 } },
type: "LengthValue",
unit: "px",
sign: "-",
value: -80
},
source: {
end: { index: 18 },
operator: { end: { index: 11 }, start: { index: 10 } },
start: { index: 0 }
},
type: "MathExpression"
});
expect(parse("calc(-100px * -2)")).toEqual({
left: {
source: { end: { index: 11 }, start: { index: 5 } },
type: "LengthValue",
unit: "px",
sign: "-",
value: -100
},
operator: "*",
right: {
source: { end: { index: 16 }, start: { index: 14 } },
type: "Value",
sign: "-",
value: -2
},
source: {
end: { index: 17 },
operator: { end: { index: 13 }, start: { index: 12 } },
start: { index: 0 }
},
type: "MathExpression"
});
expect(parse("calc(+100 * +80px)")).toEqual({
left: {
source: { end: { index: 9 }, start: { index: 5 } },
type: "Value",
sign: "+",
value: 100
},
operator: "*",
right: {
source: { end: { index: 17 }, start: { index: 12 } },
type: "LengthValue",
unit: "px",
sign: "+",
value: 80
},
source: {
end: { index: 18 },
operator: { end: { index: 11 }, start: { index: 10 } },
start: { index: 0 }
},
type: "MathExpression"
});
expect(parse("calc(+100px * +2)")).toEqual({
left: {
source: { end: { index: 11 }, start: { index: 5 } },
type: "LengthValue",
unit: "px",
sign: "+",
value: 100
},
operator: "*",
right: {
source: { end: { index: 16 }, start: { index: 14 } },
type: "Value",
sign: "+",
value: 2
},
source: {
end: { index: 17 },
operator: { end: { index: 13 }, start: { index: 12 } },
start: { index: 0 }
},
type: "MathExpression"
});
});

it("parseCalcExpression case insensitive", () => {
Expand Down Expand Up @@ -681,4 +769,9 @@ it("parseCalcExpression syntax error", () => {
expect(() => parse("calc(100% - - -@foo)")).toThrow();
expect(() => parse("calc(100% - -foo())")).toThrow();
expect(() => parse("calc(100% - -foo(bar, baz))")).toThrow();
expect(() => parse("calc(--100)")).toThrow();
expect(() => parse("calc(++100)")).toThrow();
expect(() => parse("calc(+-100)")).toThrow();
expect(() => parse("calc(-+100)")).toThrow();
expect(() => parse("calc(+var(foo))")).toThrow();
});
89 changes: 59 additions & 30 deletions lib/utils/parseCalcExpression/parser.jison
Expand Up @@ -16,36 +16,36 @@
"+" return 'ADD';
"-" return 'SUB';

[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)em\b return 'LENGTH'; // em
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)ex\b return 'LENGTH'; // ex
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)ch\b return 'LENGTH'; // ch
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)rem\b return 'LENGTH'; // rem
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)vw\b return 'LENGTH'; // vw
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)vh\b return 'LENGTH'; // vh
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)vmin\b return 'LENGTH'; // vmin
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)vmax\b return 'LENGTH'; // vmax
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)vm\b return 'LENGTH'; // vm (non-standard name)
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)px\b return 'LENGTH'; // px
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)mm\b return 'LENGTH'; // mm
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)cm\b return 'LENGTH'; // cm
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)in\b return 'LENGTH'; // in
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)pt\b return 'LENGTH'; // pt
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)pc\b return 'LENGTH'; // pc
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)Q\b return 'LENGTH'; // Q
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)fr\b return 'LENGTH'; // fr
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)deg\b return 'ANGLE'; // deg
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)grad\b return 'ANGLE'; // grad
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)turn\b return 'ANGLE'; // turn
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)rad\b return 'ANGLE'; // rad
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)s\b return 'TIME'; // s
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)ms\b return 'TIME'; // ms
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)Hz\b return 'FREQ'; // Hz
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)kHz\b return 'FREQ'; // kHz
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)dpi\b return 'RES'; // dpi
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)dpcm\b return 'RES'; // dpcm
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)dppx\b return 'RES'; // dppm
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)\% return 'PERCENTAGE';
[+-]?([0-9]+("."[0-9]+)?|"."[0-9]+)\b return 'NUMBER';
([0-9]+("."[0-9]+)?|"."[0-9]+)em\b return 'LENGTH'; // em
([0-9]+("."[0-9]+)?|"."[0-9]+)ex\b return 'LENGTH'; // ex
([0-9]+("."[0-9]+)?|"."[0-9]+)ch\b return 'LENGTH'; // ch
([0-9]+("."[0-9]+)?|"."[0-9]+)rem\b return 'LENGTH'; // rem
([0-9]+("."[0-9]+)?|"."[0-9]+)vw\b return 'LENGTH'; // vw
([0-9]+("."[0-9]+)?|"."[0-9]+)vh\b return 'LENGTH'; // vh
([0-9]+("."[0-9]+)?|"."[0-9]+)vmin\b return 'LENGTH'; // vmin
([0-9]+("."[0-9]+)?|"."[0-9]+)vmax\b return 'LENGTH'; // vmax
([0-9]+("."[0-9]+)?|"."[0-9]+)vm\b return 'LENGTH'; // vm (non-standard name)
([0-9]+("."[0-9]+)?|"."[0-9]+)px\b return 'LENGTH'; // px
([0-9]+("."[0-9]+)?|"."[0-9]+)mm\b return 'LENGTH'; // mm
([0-9]+("."[0-9]+)?|"."[0-9]+)cm\b return 'LENGTH'; // cm
([0-9]+("."[0-9]+)?|"."[0-9]+)in\b return 'LENGTH'; // in
([0-9]+("."[0-9]+)?|"."[0-9]+)pt\b return 'LENGTH'; // pt
([0-9]+("."[0-9]+)?|"."[0-9]+)pc\b return 'LENGTH'; // pc
([0-9]+("."[0-9]+)?|"."[0-9]+)Q\b return 'LENGTH'; // Q
([0-9]+("."[0-9]+)?|"."[0-9]+)fr\b return 'LENGTH'; // fr
([0-9]+("."[0-9]+)?|"."[0-9]+)deg\b return 'ANGLE'; // deg
([0-9]+("."[0-9]+)?|"."[0-9]+)grad\b return 'ANGLE'; // grad
([0-9]+("."[0-9]+)?|"."[0-9]+)turn\b return 'ANGLE'; // turn
([0-9]+("."[0-9]+)?|"."[0-9]+)rad\b return 'ANGLE'; // rad
([0-9]+("."[0-9]+)?|"."[0-9]+)s\b return 'TIME'; // s
([0-9]+("."[0-9]+)?|"."[0-9]+)ms\b return 'TIME'; // ms
([0-9]+("."[0-9]+)?|"."[0-9]+)Hz\b return 'FREQ'; // Hz
([0-9]+("."[0-9]+)?|"."[0-9]+)kHz\b return 'FREQ'; // kHz
([0-9]+("."[0-9]+)?|"."[0-9]+)dpi\b return 'RES'; // dpi
([0-9]+("."[0-9]+)?|"."[0-9]+)dpcm\b return 'RES'; // dpcm
([0-9]+("."[0-9]+)?|"."[0-9]+)dppx\b return 'RES'; // dppm
([0-9]+("."[0-9]+)?|"."[0-9]+)\% return 'PERCENTAGE';
([0-9]+("."[0-9]+)?|"."[0-9]+)\b return 'NUMBER';

"(" return 'LPAREN';
")" return 'RPAREN';
Expand Down Expand Up @@ -111,6 +111,35 @@ expression
}
};
}
| SUB math_expression %prec UPREC {
if (@1.range[1] !== $2.source.start.index) {
throw new Error('Unexpected spaces was found between sign and value');
}
if (typeof $2.value !== 'number') {
throw new Error('Unexpected sign');
}
if ($2.sign) {
throw new Error('Unexpected continuous sign');
}
$$ = $2;
$$.sign = '-'
$$.value = -$2.value;
$$.source.start.index = @1.range[0];
}
| ADD math_expression %prec UPREC {
if (@1.range[1] !== $2.source.start.index) {
throw new Error('Unexpected spaces was found between sign and value');
}
if (typeof $2.value !== 'number') {
throw new Error('Unexpected sign');
}
if ($2.sign) {
throw new Error('Unexpected continuous sign');
}
$$ = $2;
$$.sign = '+'
$$.source.start.index = @1.range[0];
}
| LPAREN math_expression RPAREN {
$$ = $2;
$$.source.start = { index: @1.range[0] };
Expand Down