postcss / postcss-calc

PostCSS plugin to reduce calc()
MIT License
213 stars 34 forks source link

Parse error with CSS custom properties with default values including a nested calc #77

Open wessberg opened 5 years ago

wessberg commented 5 years ago

The following CSS:

div {
    margin-right: calc(var(--b, calc(var(--c) * 1)));
}

Leads to the following parser error:

JisonParserError: Parse error on line 1: 
var(--b, calc(var(--c)*1))
-------------------------^
Expecting end of input, "ADD", "SUB", "MUL", "DIV", got unexpected "RPAREN"

Looking at the Stack trace, here's the chain of the last few operations leading to the issue:

at Parser.parseError (/node_modules/postcss-calc/dist/parser.js:1164:15)
at Parser.parse (/node_modules/postcss-calc/dist/parser.js:1680:30)
at /node_modules/postcss-calc/dist/lib/transform.js:30:30

Removing the last * 1 part removes the parser error.

alexander-akait commented 5 years ago

Thanks for issue, it is bug

eric1iu commented 5 years ago

Looks like the same error for this:

JisonParserError: Parse error on line 1: 
  max(5px, calc(env(safe-area-inset-right) - 4px))
  -----------------------------------------------^
  Expecting end of input, "ADD", "SUB", "MUL", "DIV", got unexpected "RPAREN"
alexander-akait commented 5 years ago

Yes, right now i rewrite plugin and parser, i think release will be on end of week or next week

eric1iu commented 5 years ago

As a workaround, disable postcss-calc in package.json to pass gatsby build in my case.

  "cssnano": {
    "preset": [
      "default",
      {
        "calc": false
      }
    ]
  }

Will enable again once this bug fixed. Thanks!

drinchev commented 5 years ago

Btw I have the very same problem without having nested variables :

const postcssCalc = require('postcss-calc');

const css = `
.baz{
  height:calc( calc(16px + 0.8)+calc(1.5 + 0.9));
}
`

postcssCalc.process( css ).catch( error => console.error(error.toString()) );

This breaks with error :

JisonParserError: Parse error on line 1:
calc(16px + 0.8)2.4
----------------^
Expecting end of input, "ADD", "SUB", "MUL", "DIV", got unexpected "NUMBER"

I assume having nested calc with no space between breaks it, since

height:calc( calc(16px + 0.8)+ calc(1.5 + 0.9));
//                            ^ note space

works normally.

alexander-akait commented 5 years ago

@drinchev feel free to send a PR

drinchev commented 5 years ago

@evilebottnawi Actually my bug is unrelated to this one.

Just checked and it seems to work with the latest master branch.


test(
  'should handle nested calc statements with 2 calc parameters',
  testValue,
  'calc(calc(16px + 0.8)+ calc(1.5 + 0.9))',
  'calc(16px + 3.2)'
);

test(
  'should handle nested calc statements with 2 calc parameters with no spaces',
  testValue,
  'calc( calc(16px + 0.8)+calc(1.5 + 0.9))',
  'calc(16px + 3.2)'
);

Both tests work on current master, but don't pass in 7.0.1 tag.

Any plans to release soon?

7.0.1 is dependency of the current cssnano, which is dependency of the current create-react-app.

alexander-akait commented 5 years ago

@drinchev thanks for investigate looks on this in near future

rhythm-sharma commented 4 years ago

@wessberg, Thanks for opening this issue. I was also struggling with same calc() issue inside CSS file

GreenGremlin commented 4 years ago

I get a similar error when using css-loader's @value properties in calc functions.

@value avatar-size: 36px;

.avatar {
  width: avatar-size;
  height: avatar-size;
  margin-top: calc((avatar-size) / 2);
}

Results in this error

  Erroneous area:
1: (avatar-size) / 2
^...^
    at Object.parseError (/Users/jonathan/app/node_modules/postcss-calc/dist/parser.js:1164:15)
    at Object.lexer_parseError [as parseError] (/Users/jonathan/app/node_modules/postcss-calc/dist/parser.js:2297:44)
    at Object.lexer_next [as next] (/Users/jonathan/app/node_modules/postcss-calc/dist/parser.js:3292:22)
    at Object.lexer_fastLex [as fastLex] (/Users/jonathan/app/node_modules/postcss-calc/dist/parser.js:3367:18)
    at fastLex (/Users/jonathan/app/node_modules/postcss-calc/dist/parser.js:1567:27)
    at Parser.parse (/Users/jonathan/app/node_modules/postcss-calc/dist/parser.js:1641:30)
    at /Users/jonathan/app/node_modules/postcss-calc/dist/lib/transform.js:33:28
    at walk (/Users/jonathan/app/node_modules/postcss-value-parser/lib/walk.js:19:7)
    at ValueParser.walk (/Users/jonathan/app/node_modules/postcss-value-parser/lib/index.js:18:3)
    at transformValue (/Users/jonathan/app/node_modules/postcss-calc/dist/lib/transform.js:24:50)
    at _default (/Users/jonathan/app/node_modules/postcss-calc/dist/lib/transform.js:66:100)
    at /Users/jonathan/app/node_modules/postcss-calc/dist/index.js:25:51
    at /Users/jonathan/app/node_modules/postcss/lib/container.js:135:18
    at Rule.each (/Users/jonathan/app/node_modules/postcss/lib/container.js:101:16)
    at Rule.walk (/Users/jonathan/app/node_modules/postcss/lib/container.js:131:17)
    at /Users/jonathan/app/node_modules/postcss/lib/container.js:148:24
    at Root.each (/Users/jonathan/app/node_modules/postcss/lib/container.js:101:16)
    at Root.walk (/Users/jonathan/app/node_modules/postcss/lib/container.js:131:17)
    at /Users/jonathan/app/node_modules/postcss-calc/dist/index.js:23:9
    at initializePlugin (/Users/jonathan/app/node_modules/cssnano/dist/index.js:31:51)

The @value properties are processed by css-loader, which runs after postcss-loader. If nothing else, it seems appropriate for postcss-calc to just ignore calc values that fail to parse.

GreenGremlin commented 4 years ago

I was able to work around my issue by including the postcss-modules-values plugin before postcss-calc.

HZooly commented 4 years ago

Any example of this for removing postcss-calc from Gatsby build please? I can't achieve this...

I tried to edit my postcss.config.js, unsuccessful.

Semigradsky commented 4 years ago

This bug happens because 'function' regexp not matching function which has many brackets inside: https://github.com/postcss/postcss-calc/blob/6260789750bbf73006190ef00ab43abfb278b4dc/src/parser.jison#L13

As I understand it is not possible to match nested brackets by regex so it should be rewritten from regex.

while0pass commented 4 years ago

After transition from v7.0.0 to v7.0.[12], postcss-calc got a regression bug. Now I get the following error, though it has never been raised before:

:root {
  /* ... */
  --main-gap-mobile: calc((100vw - var(--main-width-mobile)) / 2);
}

JisonParserError in plugin "gulp-postcss"
Message:
    Parse error on line 1:
- calc((100v...
--^
Expecting "ADD", "SUB", "LENGTH", "ANGLE", "TIME", "FREQ", "RES", "UNKNOWN_DIMENSION", "EMS", "EXS", "CHS", "REMS", "VHS", "VWS", "VMINS", "VMAXS", "PERCENTAGE", "NUMBER", "dimension", got unexpected "CALC"
Details:
    hash: [object Object]
    fileName: ./src/styles/main.css
    domainEmitter: [object Object]
    domain: [object Object]
    domainThrown: false

Stack:
JisonParserError: Parse error on line 1:
- calc((100v...
--^
Expecting "ADD", "SUB", "LENGTH", "ANGLE", "TIME", "FREQ", "RES", "UNKNOWN_DIMENSION", "EMS", "EXS", "CHS", "REMS", "VHS", "VWS", "VMINS", "VMAXS", "PERCENTAGE", "NUMBER", "dimension", got unexpected "CALC"
    at Parser.parseError (./node_modules/postcss-calc/dist/parser.js:1200:15)
    at Parser.parse (./node_modules/postcss-calc/dist/parser.js:1716:30)
    at ./node_modules/postcss-calc/dist/lib/transform.js:33:30
    at walk (./node_modules/postcss-calc/node_modules/postcss-value-parser/lib/walk.js:7:16)
    at ValueParser.walk (./node_modules/postcss-calc/node_modules/postcss-value-parser/lib/index.js:18:3)
    at transformValue (./node_modules/postcss-calc/dist/lib/transform.js:24:50)
    at _default (./node_modules/postcss-calc/dist/lib/transform.js:66:100)
    at ./node_modules/postcss-calc/dist/index.js:27:32
    at ./node_modules/postcss-import/node_modules/postcss/lib/container.js:144:26
    at Rule.each (./node_modules/postcss-import/node_modules/postcss/lib/container.js:110:22)```
julkue commented 4 years ago

In my case it was caused by a third party library: https://github.com/sampotts/plyr/issues/1816

jpabeem commented 3 years ago

It seems wrapping a variable inside #{} (fix: https://github.com/creativetimofficial/ct-light-bootstrap-dashboard-pro-react/issues/37#issuecomment-478605836 ) was able to solve my issue.

wongjn commented 3 years ago

As per Semigradsky's comment, I think it is something to do with when there are too many parenthesis levels in the formula:

var(--a) + max(1px, min((1vw - 5.9px), 10px))
--------------------------------------------^
Expecting end of input, "ADD", "SUB", "MUL", "DIV", got unexpected "RPAREN"
Pomax commented 3 years ago

Hm, looking at this issue, all these calc() instructions aren't valid as per the CSS spec, which SCSS still has to obey, so this doesn't look like a bug in flagging errors, but a bug in how it's reporting what is wrong?

Semigradsky commented 3 years ago

margin-right: calc(var(--b, calc(var(--c) * 1))) and --main-gap-mobile: calc((100vw - var(--main-width-mobile)) / 2) are valid. You can check it just by add them via chrome devtools.

Pomax commented 3 years ago

You're right - although that first one still makes no sense: those calc() wrappers do nothing, and a decent tool would remove them since calc(var(--b, calc(var(--c) * 1))) is identical to var(--b, var(--c)) (postcss-calc might certainly exhibit this bug for that input, but because it can be simplified so much it's not unambiguously that the symptom stems from the same cause)

bwstoppel commented 2 years ago

In case this helps anyone, calc(var(--base-padding) * -1) throws an error whereas calc(-1 * var(--base-padding)) does not.

ludofischer commented 2 years ago

In case this helps anyone, calc(var(--base-padding) -1) throws an error whereas calc(-1 var(--base-padding)) does not.

But does it just print an error message or does it crash?

bwstoppel commented 2 years ago

It fails and prints a generic error. Something like "failed at line 1 column 26." I don't have the error in front of me anymore. The error message was not accurate. I found the issue by removing and adding back styles until I narrowed it down to the culprit.