Fix code quality violations and exclude Manifest from checks

Document application modes (development/debug/production)
Add global file drop handler, order column normalization, SPA hash fix
Serve CDN assets via /_vendor/ URLs instead of merging into bundles
Add production minification with license preservation
Improve JSON formatting for debugging and production optimization
Add CDN asset caching with CSS URL inlining for production builds
Add three-mode system (development, debug, production)
Update Manifest CLAUDE.md to reflect helper class architecture
Refactor Manifest.php into helper classes for better organization
Pre-manifest-refactor checkpoint: Add app_mode documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2026-01-14 10:38:22 +00:00
parent bb9046af1b
commit d523f0f600
2355 changed files with 231384 additions and 32223 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "postcss-calc",
"version": "8.2.4",
"version": "10.1.1",
"description": "PostCSS plugin to reduce calc()",
"keywords": [
"css",
@@ -9,6 +9,11 @@
"calculation",
"calc"
],
"homepage": "https://github.com/postcss/postcss-calc",
"repository": {
"type": "git",
"url": "https://github.com/postcss/postcss-calc.git"
},
"main": "src/index.js",
"types": "types/index.d.ts",
"files": [
@@ -18,45 +23,28 @@
],
"author": "Andy Jansson",
"license": "MIT",
"repository": "https://github.com/postcss/postcss-calc.git",
"eslintConfig": {
"extends": [
"eslint:recommended",
"prettier"
],
"env": {
"node": true,
"es2017": true
},
"ignorePatterns": [
"src/parser.js"
],
"rules": {
"curly": "error"
}
"engines": {
"node": "^18.12 || ^20.9 || >=22.0"
},
"devDependencies": {
"@types/node": "^17.0.15",
"eslint": "^8.8.0",
"eslint-config-prettier": "^8.3.0",
"jison-gho": "^0.6.1-216",
"postcss": "^8.2.2",
"prettier": "^2.5.1",
"typescript": "^4.5.5",
"uvu": "^0.5.3"
"@types/node": "^22.10.10",
"eslint": "^9.19.0",
"eslint-config-prettier": "^10.0.1",
"jison-gho": "0.6.1-216",
"postcss": "^8.5.1",
"prettier": "^3.4.2",
"typescript": "~5.7.3"
},
"dependencies": {
"postcss-selector-parser": "^6.0.9",
"postcss-selector-parser": "^7.0.0",
"postcss-value-parser": "^4.2.0"
},
"peerDependencies": {
"postcss": "^8.2.2"
"postcss": "^8.4.38"
},
"scripts": {
"build": "jison src/parser.jison -o src/parser.js",
"lint": "eslint src && tsc",
"pretest": "pnpm run build",
"test": "uvu src/__tests__"
},
"readme": "# PostCSS Calc [<img src=\"https://postcss.github.io/postcss/logo.svg\" alt=\"PostCSS\" width=\"90\" height=\"90\" align=\"right\">][PostCSS]\n\n[![NPM Version][npm-img]][npm-url]\n[![Support Chat][git-img]][git-url]\n\n[PostCSS Calc] lets you reduce `calc()` references whenever it's possible.\nWhen multiple units are mixed together in the same expression, the `calc()`\nstatement is left as is, to fallback to the [W3C calc() implementation].\n\n## Installation\n\n```bash\nnpm install postcss-calc\n```\n\n## Usage\n\n```js\n// dependencies\nvar fs = require(\"fs\")\nvar postcss = require(\"postcss\")\nvar calc = require(\"postcss-calc\")\n\n// css to be processed\nvar css = fs.readFileSync(\"input.css\", \"utf8\")\n\n// process css\nvar output = postcss()\n .use(calc())\n .process(css)\n .css\n```\n\nUsing this `input.css`:\n\n```css\nh1 {\n font-size: calc(16px * 2);\n height: calc(100px - 2em);\n width: calc(2*var(--base-width));\n margin-bottom: calc(16px * 1.5);\n}\n```\n\nyou will get:\n\n```css\nh1 {\n font-size: 32px;\n height: calc(100px - 2em);\n width: calc(2*var(--base-width));\n margin-bottom: 24px\n}\n```\nCheckout [tests] for more examples.\n\n### Options\n\n#### `precision` (default: `5`)\n\nAllow you to define the precision for decimal numbers.\n\n```js\nvar out = postcss()\n .use(calc({precision: 10}))\n .process(css)\n .css\n```\n\n#### `preserve` (default: `false`)\n\nAllow you to preserve calc() usage in output so browsers will handle decimal\nprecision themselves.\n\n```js\nvar out = postcss()\n .use(calc({preserve: true}))\n .process(css)\n .css\n```\n\n#### `warnWhenCannotResolve` (default: `false`)\n\nAdds warnings when calc() are not reduced to a single value.\n\n```js\nvar out = postcss()\n .use(calc({warnWhenCannotResolve: true}))\n .process(css)\n .css\n```\n\n#### `mediaQueries` (default: `false`)\n\nAllows calc() usage as part of media query declarations.\n\n```js\nvar out = postcss()\n .use(calc({mediaQueries: true}))\n .process(css)\n .css\n```\n\n#### `selectors` (default: `false`)\n\nAllows calc() usage as part of selectors.\n\n```js\nvar out = postcss()\n .use(calc({selectors: true}))\n .process(css)\n .css\n```\n\nExample:\n\n```css\ndiv[data-size=\"calc(3*3)\"] {\n width: 100px;\n}\n```\n\n---\n\n## Related PostCSS plugins\nTo replace the value of CSS custom properties at build time, try [PostCSS Custom Properties].\n\n## Contributing\n\nWork on a branch, install dev-dependencies, respect coding style & run tests\nbefore submitting a bug fix or a feature.\n\n```bash\ngit clone git@github.com:postcss/postcss-calc.git\ngit checkout -b patch-1\nnpm install\nnpm test\n```\n\n## [Changelog](CHANGELOG.md)\n\n## [License](LICENSE)\n\n[git-img]: https://img.shields.io/badge/support-chat-blue.svg\n[git-url]: https://gitter.im/postcss/postcss\n[npm-img]: https://img.shields.io/npm/v/postcss-calc.svg\n[npm-url]: https://www.npmjs.com/package/postcss-calc\n\n[PostCSS]: https://github.com/postcss\n[PostCSS Calc]: https://github.com/postcss/postcss-calc\n[PostCSS Custom Properties]: https://github.com/postcss/postcss-custom-properties\n[tests]: src/__tests__/index.js\n[W3C calc() implementation]: https://www.w3.org/TR/css3-values/#calc-notation\n"
"build": "jison ./parser.jison -o src/parser.js",
"lint": "eslint . && tsc",
"test": "node --test"
}
}

View File

@@ -1,421 +0,0 @@
'use strict';
const { test } = require('uvu');
const assert = require('uvu/assert');
const convertUnit = require('../lib/convertUnit.js');
test('valid conversions', () => {
const conversions = [
// source value, source unit, expected value, target unit
[10, 'px', 10, 'px'],
[10, 'px', 0.26458, 'cm'],
[10, 'px', 2.64583, 'mm'],
[10, 'px', 10.58333, 'q'],
[10, 'px', 0.10417, 'in'],
[10, 'px', 7.5, 'pt'],
[10, 'px', 0.625, 'pc'],
[10, 'cm', 377.95276, 'px'],
[10, 'cm', 10, 'cm'],
[10, 'cm', 100, 'mm'],
[10, 'cm', 400, 'q'],
[10, 'cm', 3.93701, 'in'],
[10, 'cm', 283.46457, 'pt'],
[10, 'cm', 23.62205, 'pc'],
[10, 'mm', 37.79528, 'px'],
[10, 'mm', 1, 'cm'],
[10, 'mm', 10, 'mm'],
[10, 'mm', 40, 'q'],
[10, 'mm', 0.3937, 'in'],
[10, 'mm', 28.34646, 'pt'],
[10, 'mm', 2.3622, 'pc'],
[10, 'q', 9.44882, 'px'],
[10, 'q', 0.25, 'cm'],
[10, 'q', 2.5, 'mm'],
[10, 'q', 0.09843, 'in'],
[10, 'q', 7.08661, 'pt'],
[10, 'q', 0.59055, 'pc'],
[10, 'in', 960, 'px'],
[10, 'in', 25.4, 'cm'],
[10, 'in', 254, 'mm'],
[10, 'in', 1016, 'q'],
[10, 'in', 10, 'in'],
[10, 'in', 720, 'pt'],
[10, 'in', 60, 'pc'],
[10, 'pt', 13.33333, 'px'],
[10, 'pt', 0.35278, 'cm'],
[10, 'pt', 3.52778, 'mm'],
[10, 'pt', 14.11111, 'q'],
[10, 'pt', 0.13889, 'in'],
[10, 'pt', 10, 'pt'],
[10, 'pt', 0.83333, 'pc'],
[10, 'pc', 160, 'px'],
[10, 'pc', 4.23333, 'cm'],
[10, 'pc', 42.33333, 'mm'],
[10, 'pc', 169.33333, 'q'],
[10, 'pc', 1.66667, 'in'],
[10, 'pc', 120, 'pt'],
[10, 'pc', 10, 'pc'],
[10, 'deg', 10, 'deg'],
[10, 'deg', 11.11111, 'grad'],
[10, 'deg', 0.17453, 'rad'],
[10, 'deg', 0.02778, 'turn'],
[10, 'grad', 9, 'deg'],
[10, 'grad', 10, 'grad'],
[10, 'grad', 0.15708, 'rad'],
[10, 'grad', 0.025, 'turn'],
[10, 'rad', 572.9578, 'deg'],
[10, 'rad', 636.61977, 'grad'],
[10, 'rad', 10, 'rad'],
[10, 'rad', 1.59155, 'turn'],
[10, 'turn', 3600, 'deg'],
[10, 'turn', 4000, 'grad'],
[10, 'turn', 62.83185, 'rad'],
[10, 'turn', 10, 'turn'],
[10, 's', 10, 's'],
[10, 's', 10000, 'ms'],
[10, 'ms', 0.01, 's'],
[10, 'ms', 10, 'ms'],
[10, 'Hz', 10, 'Hz'],
[10, 'Hz', 0.01, 'kHz'],
[10, 'kHz', 10000, 'Hz'],
[10, 'kHz', 10, 'kHz'],
[10, 'dpi', 10, 'dpi'],
[10, 'dpi', 25.4, 'dpcm'],
[10, 'dpi', 960, 'dppx'],
[10, 'dpcm', 3.93701, 'dpi'],
[10, 'dpcm', 10, 'dpcm'],
[10, 'dpcm', 377.95276, 'dppx'],
[10, 'dppx', 0.10417, 'dpi'],
[10, 'dppx', 0.26458, 'dpcm'],
[10, 'dppx', 10, 'dppx'],
];
conversions.forEach(function (e) {
const value = e[0];
const unit = e[1];
const expected = e[2];
const targetUnit = e[3];
assert.is(
convertUnit(value, unit, targetUnit),
expected,
unit + ' -> ' + targetUnit
);
});
});
test('invalid conversions', () => {
const invalid_units = {
px: [
'deg',
'grad',
'rad',
'turn',
's',
'ms',
'Hz',
'kHz',
'dpi',
'dpcm',
'dppx',
],
cm: [
'deg',
'grad',
'rad',
'turn',
's',
'ms',
'Hz',
'kHz',
'dpi',
'dpcm',
'dppx',
],
mm: [
'deg',
'grad',
'rad',
'turn',
's',
'ms',
'Hz',
'kHz',
'dpi',
'dpcm',
'dppx',
],
q: [
'deg',
'grad',
'rad',
'turn',
's',
'ms',
'Hz',
'kHz',
'dpi',
'dpcm',
'dppx',
],
in: [
'deg',
'grad',
'rad',
'turn',
's',
'ms',
'Hz',
'kHz',
'dpi',
'dpcm',
'dppx',
],
pt: [
'deg',
'grad',
'rad',
'turn',
's',
'ms',
'Hz',
'kHz',
'dpi',
'dpcm',
'dppx',
],
pc: [
'deg',
'grad',
'rad',
'turn',
's',
'ms',
'Hz',
'kHz',
'dpi',
'dpcm',
'dppx',
],
deg: [
'px',
'cm',
'mm',
'in',
'pt',
'pc',
's',
'ms',
'Hz',
'kHz',
'dpi',
'dpcm',
'dppx',
],
grad: [
'px',
'cm',
'mm',
'in',
'pt',
'pc',
's',
'ms',
'Hz',
'kHz',
'dpi',
'dpcm',
'dppx',
],
rad: [
'px',
'cm',
'mm',
'in',
'pt',
'pc',
's',
'ms',
'Hz',
'kHz',
'dpi',
'dpcm',
'dppx',
],
turn: [
'px',
'cm',
'mm',
'in',
'pt',
'pc',
's',
'ms',
'Hz',
'kHz',
'dpi',
'dpcm',
'dppx',
],
s: [
'px',
'cm',
'mm',
'in',
'pt',
'pc',
'deg',
'grad',
'rad',
'turn',
'Hz',
'kHz',
'dpi',
'dpcm',
'dppx',
],
ms: [
'px',
'cm',
'mm',
'in',
'pt',
'pc',
'deg',
'grad',
'rad',
'turn',
'Hz',
'kHz',
'dpi',
'dpcm',
'dppx',
],
Hz: [
'px',
'cm',
'mm',
'in',
'pt',
'pc',
'deg',
'grad',
'rad',
'turn',
's',
'ms',
'dpi',
'dpcm',
'dppx',
],
kHz: [
'px',
'cm',
'mm',
'in',
'pt',
'pc',
'deg',
'grad',
'rad',
'turn',
's',
'ms',
'dpi',
'dpcm',
'dppx',
],
dpi: [
'px',
'cm',
'mm',
'in',
'pt',
'pc',
'deg',
'grad',
'rad',
'turn',
's',
'ms',
'Hz',
'kHz',
],
dpcm: [
'px',
'cm',
'mm',
'in',
'pt',
'pc',
'deg',
'grad',
'rad',
'turn',
's',
'ms',
'Hz',
'kHz',
],
dppx: [
'px',
'cm',
'mm',
'in',
'pt',
'pc',
'deg',
'grad',
'rad',
'turn',
's',
'ms',
'Hz',
'kHz',
],
};
for (const unit in invalid_units) {
invalid_units[unit].forEach((targetUnit) => {
let failed = false;
try {
convertUnit(10, unit, targetUnit);
} catch (e) {
failed = true;
}
assert.ok(failed, unit + ' -> ' + targetUnit);
});
}
});
test('precision', () => {
const precision = 10;
const conversions = [
// source value, source unit, expected value, target unit
[10, 'px', 0.2645833333, 'cm'],
[10, 'px', 2.6458333333, 'mm'],
[10, 'px', 0.1041666667, 'in'],
[10, 'cm', 377.9527559055, 'px'],
];
conversions.forEach((e) => {
const value = e[0];
const unit = e[1];
const expected = e[2];
const targetUnit = e[3];
assert.is(
convertUnit(value, unit, targetUnit, precision),
expected,
unit + ' -> ' + targetUnit
);
});
});
test('falsey precision', () => {
assert.is(convertUnit(10, 'px', 'cm', false), 0.26458333333333334);
});
test.run();

View File

@@ -1,903 +0,0 @@
'use strict';
const { test } = require('uvu');
const assert = require('uvu/assert');
const postcss = require('postcss');
const reduceCalc = require('../index.js');
const postcssOpts = { from: undefined };
function testValue(fixture, expected, opts = {}) {
fixture = `foo{bar:${fixture}}`;
expected = `foo{bar:${expected}}`;
return async () => {
const result = await postcss(reduceCalc(opts)).process(
fixture,
postcssOpts
);
assert.is(result.css, expected);
};
}
function testCss(fixture, expected, opts = {}) {
return async () => {
const result = await postcss(reduceCalc(opts)).process(
fixture,
postcssOpts
);
assert.is(result.css, expected);
};
}
function testThrows(fixture, expected, warning, opts = {}) {
fixture = `foo{bar:${fixture}}`;
expected = `foo{bar:${expected}}`;
return async () => {
const result = await postcss(reduceCalc(opts)).process(
fixture,
postcssOpts
);
const warnings = result.warnings();
assert.is(result.css, expected);
assert.is(warnings[0].text, warning);
};
}
test('should reduce simple calc (1)', testValue('calc(1px + 1px)', '2px'));
test(
'should reduce simple calc (2)',
testValue('calc(1px + 1px);baz:calc(2px+3px)', '2px;baz:5px')
);
test('should reduce simple calc (3)', testValue('calc(1rem * 1.5)', '1.5rem'));
test('should reduce simple calc (4)', testValue('calc(3em - 1em)', '2em'));
test('should reduce simple calc (5', testValue('calc(2ex / 2)', '1ex'));
test(
'should reduce simple calc (6)',
testValue('calc(50px - (20px - 30px))', '60px')
);
test(
'should reduce simple calc (7)',
testValue('calc(100px - (100px - 100%))', '100%')
);
test(
'should reduce simple calc (8)',
testValue('calc(100px + (100px - 100%))', 'calc(200px - 100%)')
);
test(
'should reduce additions and subtractions (1)',
testValue('calc(100% - 10px + 20px)', 'calc(100% + 10px)')
);
test(
'should reduce additions and subtractions (2)',
testValue('calc(100% + 10px - 20px)', 'calc(100% - 10px)')
);
test(
'should reduce additions and subtractions (3)',
testValue('calc(1px - (2em + 3%))', 'calc(1px - 2em - 3%)')
);
test(
'should reduce additions and subtractions (4)',
testValue('calc((100vw - 50em) / 2)', 'calc(50vw - 25em)')
);
test(
'should reduce additions and subtractions (5)',
testValue('calc(10px - (100vw - 50em) / 2)', 'calc(10px - 50vw + 25em)')
);
test(
'should reduce additions and subtractions (6)',
testValue('calc(1px - (2em + 4vh + 3%))', 'calc(1px - 2em - 4vh - 3%)')
);
test(
'should reduce additions and subtractions (7)',
testValue(
'calc(0px - (24px - (var(--a) - var(--b)) / 2 + var(--c)))',
'calc(-24px + (var(--a) - var(--b))/2 - var(--c))'
)
);
test(
'should reduce additions and subtractions (8)',
testValue('calc(1px + (2em + (3vh + 4px)))', 'calc(5px + 2em + 3vh)')
);
test(
'should reduce additions and subtractions (9)',
testValue('calc(1px - (2em + 4px - 6vh) / 2)', 'calc(-1px - 1em + 3vh)')
);
test(
'should reduce multiplication',
testValue('calc(((var(--a) + 4px) * 2) * 2)', 'calc((var(--a) + 4px)*2*2)')
);
test(
'should reduce multiplication before reducing additions',
testValue(
'calc(((var(--a) + 4px) * 2) * 2 + 4px)',
'calc((var(--a) + 4px)*2*2 + 4px)'
)
);
test(
'should reduce division',
testValue('calc(((var(--a) + 4px) / 2) / 2)', 'calc((var(--a) + 4px)/2/2)')
);
test(
'should reduce division before reducing additions',
testValue(
'calc(((var(--a) + 4px) / 2) / 2 + 4px)',
'calc((var(--a) + 4px)/2/2 + 4px)'
)
);
test(
'should ignore value surrounding calc function (1)',
testValue('a calc(1px + 1px)', 'a 2px')
);
test(
'should ignore value surrounding calc function (2)',
testValue('calc(1px + 1px) a', '2px a')
);
test(
'should ignore value surrounding calc function (3)',
testValue('a calc(1px + 1px) b', 'a 2px b')
);
test(
'should ignore value surrounding calc function (4)',
testValue('a calc(1px + 1px) b calc(1em + 2em) c', 'a 2px b 3em c')
);
test(
'should reduce nested calc',
testValue('calc(100% - calc(50% + 25px))', 'calc(50% - 25px)')
);
test(
'should reduce vendor-prefixed nested calc',
testValue(
'-webkit-calc(100% - -webkit-calc(50% + 25px))',
'-webkit-calc(50% - 25px)'
)
);
test('should reduce uppercase calc (1)', testValue('CALC(1px + 1px)', '2px'));
test(
'should reduce uppercase calc (2)',
testValue('CALC(1px + CALC(2px / 2))', '2px')
);
test(
'should reduce uppercase calc (3)',
testValue('-WEBKIT-CALC(1px + 1px)', '2px')
);
test(
'should reduce uppercase calc (4)',
testValue('-WEBKIT-CALC(1px + -WEBKIT-CALC(2px / 2))', '2px')
);
test(
'should ignore calc with css variables (1)',
testValue('calc(var(--mouseX) * 1px)', 'calc(var(--mouseX)*1px)')
);
test(
'should ignore calc with css variables (2)',
testValue(
'calc(10px - (100px * var(--mouseX)))',
'calc(10px - 100px*var(--mouseX))'
)
);
test(
'should ignore calc with css variables (3)',
testValue(
'calc(10px - (100px + var(--mouseX)))',
'calc(-90px - var(--mouseX))'
)
);
test(
'should ignore calc with css variables (4)',
testValue(
'calc(10px - (100px / var(--mouseX)))',
'calc(10px - 100px/var(--mouseX))'
)
);
test(
'should ignore calc with css variables (5)',
testValue(
'calc(10px - (100px - var(--mouseX)))',
'calc(-90px + var(--mouseX))'
)
);
test(
'should ignore calc with css variables (6)',
testValue('calc(var(--popupHeight) / 2)', 'calc(var(--popupHeight)/2)')
);
test(
'should ignore calc with css variables (7)',
testValue(
'calc(var(--popupHeight) / 2 + var(--popupWidth) / 2)',
'calc(var(--popupHeight)/2 + var(--popupWidth)/2)'
)
);
test(
'should reduce calc with newline characters',
testValue('calc(\n1rem \n* 2 \n* 1.5)', '3rem')
);
test(
'should preserve calc with incompatible units',
testValue('calc(100% + 1px)', 'calc(100% + 1px)')
);
test(
'should parse fractions without leading zero',
testValue('calc(2rem - .14285em)', 'calc(2rem - 0.14285em)')
);
test('should handle precision correctly (1)', testValue('calc(1/100)', '0.01'));
test(
'should handle precision correctly (2)',
testValue('calc(5/1000000)', '0.00001')
);
test(
'should handle precision correctly (3)',
testValue('calc(5/1000000)', '0.000005', { precision: 6 })
);
test(
'should reduce browser-prefixed calc (1)',
testValue('-webkit-calc(1px + 1px)', '2px')
);
test(
'should reduce browser-prefixed calc (2)',
testValue('-moz-calc(1px + 1px)', '2px')
);
test(
'should discard zero values (#2) (1)',
testValue('calc(100vw / 2 - 6px + 0px)', 'calc(50vw - 6px)')
);
test(
'should discard zero values (#2) (2)',
testValue('calc(500px - 0px)', '500px')
);
test(
'should not perform addition on unitless values (#3)',
testValue('calc(1px + 1)', 'calc(1px + 1)')
);
test(
'should reduce consecutive substractions (#24) (1)',
testValue('calc(100% - 120px - 60px)', 'calc(100% - 180px)')
);
test(
'should reduce consecutive substractions (#24) (2)',
testValue('calc(100% - 10px - 20px)', 'calc(100% - 30px)')
);
test(
'should reduce mixed units of time (postcss-calc#33)',
testValue('calc(1s - 50ms)', '0.95s')
);
test(
'should correctly reduce calc with mixed units (cssnano#211)',
testValue('calc(99.99% * 1/1 - 0rem)', '99.99%')
);
test(
'should apply optimization (cssnano#320)',
testValue('calc(50% + (5em + 5%))', 'calc(55% + 5em)')
);
test(
'should reduce substraction from zero',
testValue('calc( 0 - 10px)', '-10px')
);
test(
'should reduce subtracted expression from zero',
testValue('calc( 0 - calc(1px + 1em) )', 'calc(-1px - 1em)')
);
test(
'should reduce substracted expression from zero (1)',
testValue('calc( 0 - (100vw - 10px) / 2 )', 'calc(-50vw + 5px)')
);
test(
'should reduce substracted expression from zero (2)',
testValue('calc( 0px - (100vw - 10px))', 'calc(10px - 100vw)')
);
test(
'should reduce substracted expression from zero (3)',
testValue('calc( 0px - (100vw - 10px) * 2 )', 'calc(20px - 200vw)')
);
test(
'should reduce substracted expression from zero (4)',
testValue('calc( 0px - (100vw + 10px))', 'calc(-10px - 100vw)')
);
test(
'should reduce substracted expression from zero (css-variable)',
testValue(
'calc( 0px - (var(--foo, 4px) / 2))',
'calc(0px - var(--foo, 4px)/2)'
)
);
test(
'should reduce nested expression',
testValue('calc( (1em - calc( 10px + 1em)) / 2)', '-5px')
);
test(
'should skip constant function',
testValue(
'calc(constant(safe-area-inset-left))',
'calc(constant(safe-area-inset-left))'
)
);
test(
'should skip env function',
testValue(
'calc(env(safe-area-inset-left))',
'calc(env(safe-area-inset-left))'
)
);
test(
'should skip env function (#1)',
testValue(
'calc(env(safe-area-inset-left, 50px 20px))',
'calc(env(safe-area-inset-left, 50px 20px))'
)
);
test(
'should skip unknown function',
testValue(
'calc(unknown(safe-area-inset-left))',
'calc(unknown(safe-area-inset-left))'
)
);
test(
'should preserve the original declaration when `preserve` option is set to true',
testCss('foo{bar:calc(1rem * 1.5)}', 'foo{bar:1.5rem;bar:calc(1rem * 1.5)}', {
preserve: true,
})
);
test(
'should not yield warnings when nothing is wrong',
testValue('calc(500px - 0px)', '500px', { warnWhenCannotResolve: true })
);
test(
'should warn when calc expression cannot be reduced to a single value',
testValue('calc(100% + 1px)', 'calc(100% + 1px)', {
warnWhenCannotResolve: true,
})
);
test(
'should reduce mixed units of time (#33)',
testValue('calc(1s - 50ms)', '0.95s')
);
test(
'should not parse variables as calc expressions (#35)',
testCss(
'foo:nth-child(2n + $var-calc){}',
'foo:nth-child(2n + $var-calc){}',
{ selectors: true }
)
);
test(
'should apply algebraic reduction (cssnano#319)',
testValue('calc((100px - 1em) + (-50px + 1em))', '50px')
);
test(
'should discard zero values (reduce-css-calc#2) (1)',
testValue('calc(100vw / 2 - 6px + 0px)', 'calc(50vw - 6px)')
);
test(
'should discard zero values (reduce-css-calc#2) (2)',
testValue('calc(500px - 0px)', '500px')
);
test(
'should not perform addition on unitless values (reduce-css-calc#3)',
testValue('calc(1px + 1)', 'calc(1px + 1)')
);
test(
'should return the same and not thrown an exception for attribute selectors without a value',
testCss('button[disabled]{}', 'button[disabled]{}', { selectors: true })
);
test(
'should ignore reducing custom property',
testCss(
':root { --foo: calc(var(--bar) / 8); }',
':root { --foo: calc(var(--bar)/8); }'
)
);
test(
'should ignore media queries',
testCss(
'@media (min-width:calc(10px+10px)){}',
'@media (min-width:calc(10px+10px)){}'
)
);
test(
'should reduce calc in media queries when `mediaQueries` option is set to true',
testCss('@media (min-width:calc(10px+10px)){}', '@media (min-width:20px){}', {
mediaQueries: true,
})
);
test(
'should ignore selectors (1)',
testCss('div[data-size="calc(3*3)"]{}', 'div[data-size="calc(3*3)"]{}')
);
test(
'should ignore selectors (2)',
testCss('div:nth-child(2n + calc(3*3)){}', 'div:nth-child(2n + calc(3*3)){}')
);
test(
'should reduce calc in selectors when `selectors` option is set to true (1)',
testCss('div[data-size="calc(3*3)"]{}', 'div[data-size="9"]{}', {
selectors: true,
})
);
test(
'should reduce calc in selectors when `selectors` option is set to true (2)',
testCss('div:nth-child(2n + calc(3*3)){}', 'div:nth-child(2n + 9){}', {
selectors: true,
})
);
test(
'should not reduce 100% to 1 (reduce-css-calc#44)',
testCss(
'.@supports (width:calc(100% - constant(safe-area-inset-left))){.a{width:calc(100% - constant(safe-area-inset-left))}}',
'.@supports (width:calc(100% - constant(safe-area-inset-left))){.a{width:calc(100% - constant(safe-area-inset-left))}}'
)
);
test(
'should not break css variables that have "calc" in their names',
testCss(
'a{transform: translateY(calc(-100% - var(--tooltip-calculated-offset)))}',
'a{transform: translateY(calc(-100% - var(--tooltip-calculated-offset)))}'
)
);
test(
'should handle complex calculations (reduce-css-calc#45) (1)',
testValue(
'calc(100% + (2 * 100px) - ((75.37% - 63.5px) - 900px))',
'calc(24.63% + 1163.5px)'
)
);
test(
'should handle complex calculations (reduce-css-calc#45) (2)',
testValue(
'calc(((((100% + (2 * 30px) + 63.5px) / 0.7537) - (100vw - 60px)) / 2) + 30px)',
'calc(66.33939% + 141.92915px - 50vw)'
)
);
test(
'should handle advanced arithmetic (1)',
testValue(
'calc(((75.37% - 63.5px) - 900px) + (2 * 100px))',
'calc(75.37% - 763.5px)'
)
);
test(
'should handle advanced arithmetic (2)',
testValue(
'calc((900px - (10% - 63.5px)) + (2 * 100px))',
'calc(1163.5px - 10%)'
)
);
test(
'should handle nested calc statements (reduce-css-calc#49)',
testValue('calc(calc(2.25rem + 2px) - 1px * 2)', '2.25rem')
);
test(
'should throw an exception when attempting to divide by zero',
testThrows('calc(500px/0)', 'calc(500px/0)', 'Cannot divide by zero')
);
test(
'should throw an exception when attempting to divide by unit (#1)',
testThrows(
'calc(500px/2px)',
'calc(500px/2px)',
'Cannot divide by "px", number expected'
)
);
test(
'nested var (reduce-css-calc#50)',
testValue(
'calc(var(--xxx, var(--yyy)) / 2)',
'calc(var(--xxx, var(--yyy))/2)'
)
);
test(
'should not throw an exception when unknow function exist in calc',
testValue(
'calc(unknown(#fff) - other-unknown(200px))',
'calc(unknown(#fff) - other-unknown(200px))'
)
);
test(
'should not throw an exception when unknow function exist in calc (#1)',
testValue(
'calc(unknown(#fff) * other-unknown(200px))',
'calc(unknown(#fff)*other-unknown(200px))'
)
);
test(
'should not strip calc with single CSS custom variable',
testValue('calc(var(--foo))', 'calc(var(--foo))')
);
test(
'should strip unnecessary calc with single CSS custom variable',
testValue('calc(calc(var(--foo)))', 'calc(var(--foo))')
);
test(
'should not strip calc with single CSS custom variables and value',
testValue('calc(var(--foo) + 10px)', 'calc(var(--foo) + 10px)')
);
test('should reduce calc (uppercase)', testValue('CALC(1PX + 1PX)', '2PX'));
test(
'should reduce calc (uppercase) (#1)',
testValue('CALC(VAR(--foo) + VAR(--bar))', 'CALC(VAR(--foo) + VAR(--bar))')
);
test(
'should reduce calc (uppercase) (#2)',
testValue('CALC( (1EM - CALC( 10PX + 1EM)) / 2)', '-5PX')
);
test(
'should handle nested calc function (#1)',
testValue(
'calc(calc(var(--foo) + var(--bar)) + var(--baz))',
'calc(var(--foo) + var(--bar) + var(--baz))'
)
);
test(
'should handle nested calc function (#2)',
testValue(
'calc(var(--foo) + calc(var(--bar) + var(--baz)))',
'calc(var(--foo) + var(--bar) + var(--baz))'
)
);
test(
'should handle nested calc function (#3)',
testValue(
'calc(calc(var(--foo) - var(--bar)) - var(--baz))',
'calc(var(--foo) - var(--bar) - var(--baz))'
)
);
test(
'should handle nested calc function (#4)',
testValue(
'calc(var(--foo) - calc(var(--bar) - var(--baz)))',
'calc(var(--foo) - var(--bar) + var(--baz))'
)
);
test(
'should handle nested calc function (#5)',
testValue(
'calc(calc(var(--foo) + var(--bar)) - var(--baz))',
'calc(var(--foo) + var(--bar) - var(--baz))'
)
);
test(
'should handle nested calc function (#6)',
testValue(
'calc(var(--foo) + calc(var(--bar) - var(--baz)))',
'calc(var(--foo) + var(--bar) - var(--baz))'
)
);
test(
'should handle nested calc function (#7)',
testValue(
'calc(calc(var(--foo) - var(--bar)) + var(--baz))',
'calc(var(--foo) - var(--bar) + var(--baz))'
)
);
test(
'should handle nested calc function (#8)',
testValue(
'calc(var(--foo) - calc(var(--bar) + var(--baz)))',
'calc(var(--foo) - var(--bar) - var(--baz))'
)
);
test(
'should handle nested calc function (#9)',
testValue(
'calc(calc(var(--foo) + var(--bar)) * var(--baz))',
'calc((var(--foo) + var(--bar))*var(--baz))'
)
);
test(
'should handle nested calc function (#10)',
testValue(
'calc(var(--foo) * calc(var(--bar) + var(--baz)))',
'calc(var(--foo)*(var(--bar) + var(--baz)))'
)
);
test(
'should handle nested calc function (#11)',
testValue(
'calc(calc(var(--foo) + var(--bar)) / var(--baz))',
'calc((var(--foo) + var(--bar))/var(--baz))'
)
);
test(
'should handle nested calc function (#12)',
testValue(
'calc(var(--foo) / calc(var(--bar) + var(--baz)))',
'calc(var(--foo)/(var(--bar) + var(--baz)))'
)
);
test(
'should handle nested calc function (#13)',
testValue(
'calc(100vh - 5rem - calc(10rem + 100px))',
'calc(100vh - 15rem - 100px)'
)
);
test(
'should handle nested calc function (#14)',
testValue('calc(100% - calc(10px + 2vw))', 'calc(100% - 10px - 2vw)')
);
test(
'should handle nested calc function (#15)',
testValue('calc(100% - calc(10px - 2vw))', 'calc(100% - 10px + 2vw)')
);
test(
'should preserve division precedence',
testValue(
'calc(100%/(var(--aspect-ratio)))',
'calc(100%/(var(--aspect-ratio)))'
)
);
test(
'should preserve division precedence (2)',
testValue(
`calc(
(var(--fluid-screen) - ((var(--fluid-min-width) / 16) * 1rem)) /
((var(--fluid-max-width) / 16) - (var(--fluid-min-width) / 16))
)`,
'calc((var(--fluid-screen) - ((var(--fluid-min-width)/16)*1rem))/(var(--fluid-max-width)/16 - var(--fluid-min-width)/16))'
)
);
test(
'should preserve division precedence (3)',
testValue('calc(1/(10/var(--dot-size)))', 'calc(1/(10/var(--dot-size)))')
);
test(
'should correctly preserve parentheses',
testValue(
'calc(1/((var(--a) - var(--b))/16))',
'calc(1/(var(--a) - var(--b))/16)'
)
);
test('precision for calc', testValue('calc(100% / 3 * 3)', '100%'));
test(
'precision for nested calc',
testValue('calc(calc(100% / 3) * 3)', '100%')
);
test('plus sign', testValue('calc(+100px + +100px)', '200px'));
test('plus sign (#1)', testValue('calc(+100px - +100px)', '0px'));
test('plus sign (#2)', testValue('calc(200px * +1)', '200px'));
test('plus sign (#3)', testValue('calc(200px / +1)', '200px'));
test('minus sign', testValue('calc(-100px + -100px)', '-200px'));
test('minus sign (#2)', testValue('calc(-100px - -100px)', '0px'));
test('minus sign (#3)', testValue('calc(200px * -1)', '-200px'));
test('minus sign (#4)', testValue('calc(200px / -1)', '-200px'));
test('whitespace', testValue('calc( 100px + 100px )', '200px'));
test('whitespace (#1)', testValue('calc(\t100px\t+\t100px\t)', '200px'));
test('whitespace (#2)', testValue('calc(\n100px\n+\n100px\n)', '200px'));
test(
'whitespace (#4)',
testValue('calc(\r\n100px\r\n+\r\n100px\r\n)', '200px')
);
test(
'comments',
testValue('calc(/*test*/100px/*test*/ + /*test*/100px/*test*/)', '200px')
);
test(
'comments (#1)',
testValue('calc(/*test*/100px/*test*/*/*test*/2/*test*/)', '200px')
);
test(
'comments nested',
testValue(
'calc(/*test*/100px + calc(/*test*/100px/*test*/ + /*test*/100px/*test*/))',
'300px'
)
);
test('exponent composed', testValue('calc(1.1e+1px + 1.1e+1px)', '22px'));
test('exponent composed (#1)', testValue('calc(10e+1px + 10e+1px)', '200px'));
test(
'exponent composed (#2)',
testValue('calc(1.1e+10px + 1.1e+10px)', '22000000000px')
);
test('exponent composed (#3)', testValue('calc(9e+1 * 1px)', '90px'));
test('exponent composed (#4)', testValue('calc(9e+1% + 10%)', '100%'));
test(
'exponent composed (uppercase)',
testValue('calc(1.1E+1px + 1.1E+1px)', '22px')
);
test('convert units', testValue('calc(1cm + 1px)', '1.02646cm'));
test('convert units (#1)', testValue('calc(1px + 1cm)', '38.79528px'));
test('convert units (#2)', testValue('calc(10Q + 10Q)', '20Q'));
test('convert units (#3)', testValue('calc(100.9q + 10px)', '111.48333q'));
test('convert units (#4)', testValue('calc(10px + 100.9q)', '105.33858px'));
test('convert units (#5)', testValue('calc(10cm + 1px)', '10.02646cm'));
test('convert units (#6)', testValue('calc(10mm + 1px)', '10.26458mm'));
test('convert units (#7)', testValue('calc(10px + 1q)', '10.94488px'));
test('convert units (#8)', testValue('calc(10cm + 1q)', '10.025cm'));
test('convert units (#9)', testValue('calc(10mm + 1q)', '10.25mm'));
test('convert units (#10)', testValue('calc(10in + 1q)', '10.00984in'));
test('convert units (#11)', testValue('calc(10pt + 1q)', '10.70866pt'));
test('convert units (#12)', testValue('calc(10pc + 1q)', '10.05906pc'));
test('convert units (#13)', testValue('calc(1q + 10px)', '11.58333q'));
test('convert units (#14)', testValue('calc(1q + 10cm)', '401q'));
test('convert units (#15)', testValue('calc(1q + 10mm)', '41q'));
test('convert units (#16)', testValue('calc(1q + 10in)', '1017q'));
test('convert units (#17)', testValue('calc(1q + 10pt)', '15.11111q'));
test('convert units (#18)', testValue('calc(1q + 10pc)', '170.33333q'));
test(
'unknown units',
testValue('calc(1unknown + 2unknown)', 'calc(1unknown + 2unknown)')
);
test(
'unknown units with known',
testValue('calc(1unknown + 2px)', 'calc(1unknown + 2px)')
);
test(
'unknown units with known (#1)',
testValue('calc(1px + 2unknown)', 'calc(1px + 2unknown)')
);
test(
'error with parsing',
testThrows(
'calc(10pc + unknown)',
'calc(10pc + unknown)',
'Lexical error on line 1: Unrecognized text.\n\n Erroneous area:\n1: 10pc + unknown\n^.........^'
)
);
test.run();

View File

@@ -17,10 +17,38 @@ function isValueType(node) {
case 'ChValue':
case 'RemValue':
case 'VhValue':
case 'SvhValue':
case 'LvhValue':
case 'DvhValue':
case 'VwValue':
case 'SvwValue':
case 'LvwValue':
case 'DvwValue':
case 'VminValue':
case 'SvminValue':
case 'LvminValue':
case 'DvminValue':
case 'VmaxValue':
case 'SvmaxValue':
case 'LvmaxValue':
case 'DvmaxValue':
case 'VbValue':
case 'SvbValue':
case 'LvbValue':
case 'DvbValue':
case 'ViValue':
case 'SviValue':
case 'LviValue':
case 'DviValue':
case 'CqwValue':
case 'CqhValue':
case 'CqiValue':
case 'CqbValue':
case 'CqminValue':
case 'CqmaxValue':
case 'PercentageValue':
case 'LhValue':
case 'RlhValue':
case 'Number':
return true;
}
@@ -333,6 +361,12 @@ function includesNoCssProperties(node) {
* @return {import('../parser').CalcNode}
*/
function reduce(node, precision) {
if (
node.type === 'MathExpression' &&
(node.left.type === 'CalcKeyword' || node.right.type === 'CalcKeyword')
) {
return node;
}
if (node.type === 'MathExpression') {
if (isAddSubOperator(node.operator)) {
// reduceAddSubExpression will call reduce recursively

View File

@@ -31,6 +31,8 @@ function stringify(node, prec) {
let str = '';
if (left.type === 'MathExpression' && order[op] < order[left.operator]) {
str += `(${stringify(left, prec)})`;
} else if (left.type === 'CalcKeyword') {
str += left.value;
} else {
str += stringify(left, prec);
}
@@ -42,6 +44,8 @@ function stringify(node, prec) {
order[op] < order[right.operator]
) {
str += `(${stringify(right, prec)})`;
} else if (right.type === 'CalcKeyword') {
str += right.value;
} else {
str += stringify(right, prec);
}
@@ -54,6 +58,8 @@ function stringify(node, prec) {
return node.value.toString();
case 'ParenthesizedExpression':
return `(${stringify(node.content, prec)})`;
case 'CalcKeyword':
return node.value;
default:
return round(node.value, prec) + node.unit;
}
@@ -73,12 +79,19 @@ module.exports = function (calc, node, originalValue, options, result, item) {
let str = stringify(node, options.precision);
const shouldPrintCalc =
node.type === 'MathExpression' || node.type === 'Function';
node.type === 'MathExpression' ||
node.type === 'Function' ||
node.type === 'ParenthesizedExpression' ||
node.type === 'CalcKeyword';
if (shouldPrintCalc) {
// if calc expression couldn't be resolved to a single value, re-wrap it as
// a calc()
str = `${calc}(${str})`;
if (node.type === 'ParenthesizedExpression') {
str = `${calc}${str}`;
} else {
str = `${calc}(${str})`;
}
// if the warnWhenCannotResolve option is on, inform the user that the calc
// expression could not be resolved to a single value

View File

@@ -7,7 +7,7 @@ const { parser } = require('../parser.js');
const reducer = require('./reducer.js');
const stringifier = require('./stringifier.js');
const MATCH_CALC = /((?:-(moz|webkit)-)?calc)/i;
const MATCH_CALC = /((?:-(moz|webkit)-)?calc(?!-))/i;
/**
* @param {string} value

View File

@@ -23,9 +23,37 @@ export interface DimensionExpression {
| 'ChValue'
| 'RemValue'
| 'VhValue'
| 'SvhValue'
| 'LvhValue'
| 'DvhValue'
| 'VwValue'
| 'SvwValue'
| 'LvwValue'
| 'DvwValue'
| 'VminValue'
| 'VmaxValue';
| 'SvminValue'
| 'LvminValue'
| 'DvminValue'
| 'VmaxValue'
| 'SvmaxValue'
| 'LvmaxValue'
| 'DvmaxValue'
| 'VbValue'
| 'SvbValue'
| 'LvbValue'
| 'DvbValue'
| 'ViValue'
| 'SviValue'
| 'LviValue'
| 'DviValue'
| 'CqwValue'
| 'CqhValue'
| 'CqbValue'
| 'CqiValue'
| 'CqminValue'
| 'CqmaxValue'
| 'LhValue'
| 'RlhValue';
value: number;
unit: string;
}
@@ -40,9 +68,19 @@ export interface FunctionExpression {
value: string;
}
export interface CalcKeywordExpression {
type: 'CalcKeyword';
value: string;
}
export type ValueExpression = DimensionExpression | NumberExpression;
export type CalcNode = MathExpression | ValueExpression | FunctionExpression | ParenthesizedExpression;
export type CalcNode =
| MathExpression
| ValueExpression
| FunctionExpression
| ParenthesizedExpression
| CalcKeywordExpression;
export interface Parser {
parse: (arg: string) => CalcNode;

View File

@@ -1,111 +0,0 @@
/* description: Parses expressions. */
/* lexical grammar */
%lex
%options case-insensitive
%%
\s+ /* skip whitespace */
(\-(webkit|moz)\-)?calc\b return 'CALC';
[a-z][a-z0-9-]*\s*\((?:(?:\"(?:\\.|[^\"\\])*\"|\'(?:\\.|[^\'\\])*\')|\([^)]*\)|[^\(\)]*)*\) return 'FUNCTION';
"*" return 'MUL';
"/" return 'DIV';
"+" return 'ADD';
"-" return 'SUB';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)em\b return 'EMS';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)ex\b return 'EXS';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)ch\b return 'CHS';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)rem\b return 'REMS';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)vw\b return 'VWS';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)vh\b return 'VHS';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)vmin\b return 'VMINS';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)vmax\b return 'VMAXS';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)cm\b return 'LENGTH';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)mm\b return 'LENGTH';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)Q\b return 'LENGTH';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)in\b return 'LENGTH';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)pt\b return 'LENGTH';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)pc\b return 'LENGTH';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)px\b return 'LENGTH';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)deg\b return 'ANGLE';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)grad\b return 'ANGLE';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)rad\b return 'ANGLE';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)turn\b return 'ANGLE';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)s\b return 'TIME';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)ms\b return 'TIME';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)Hz\b return 'FREQ';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)kHz\b return 'FREQ';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)dpi\b return 'RES';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)dpcm\b return 'RES';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)dppx\b return 'RES';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)\% return 'PERCENTAGE';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)\b return 'NUMBER';
(([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)-?([a-zA-Z_]|[\240-\377]|(\\[0-9a-fA-F]{1,6}(\r\n|[ \t\r\n\f])?|\\[^\r\n\f0-9a-fA-F]))([a-zA-Z0-9_-]|[\240-\377]|(\\[0-9a-fA-F]{1,6}(\r\n|[ \t\r\n\f])?|\\[^\r\n\f0-9a-fA-F]))*\b return 'UNKNOWN_DIMENSION';
"(" return 'LPAREN';
")" return 'RPAREN';
<<EOF>> return 'EOF';
/lex
%left ADD SUB
%left MUL DIV
%left UPREC
%start expression
%%
expression
: math_expression EOF { return $1; }
;
math_expression
: CALC LPAREN math_expression RPAREN { $$ = $3; }
| math_expression ADD math_expression { $$ = { type: 'MathExpression', operator: $2, left: $1, right: $3 }; }
| math_expression SUB math_expression { $$ = { type: 'MathExpression', operator: $2, left: $1, right: $3 }; }
| math_expression MUL math_expression { $$ = { type: 'MathExpression', operator: $2, left: $1, right: $3 }; }
| math_expression DIV math_expression { $$ = { type: 'MathExpression', operator: $2, left: $1, right: $3 }; }
| LPAREN math_expression RPAREN { $$ = { type: 'ParenthesizedExpression', content: $2 }; }
| function { $$ = $1; }
| dimension { $$ = $1; }
| number { $$ = $1; }
;
function
: FUNCTION { $$ = { type: 'Function', value: $1 }; }
;
dimension
: LENGTH { $$ = { type: 'LengthValue', value: parseFloat($1), unit: /[a-z]+$/i.exec($1)[0] }; }
| ANGLE { $$ = { type: 'AngleValue', value: parseFloat($1), unit: /[a-z]+$/i.exec($1)[0] }; }
| TIME { $$ = { type: 'TimeValue', value: parseFloat($1), unit: /[a-z]+$/i.exec($1)[0] }; }
| FREQ { $$ = { type: 'FrequencyValue', value: parseFloat($1), unit: /[a-z]+$/i.exec($1)[0] }; }
| RES { $$ = { type: 'ResolutionValue', value: parseFloat($1), unit: /[a-z]+$/i.exec($1)[0] }; }
| UNKNOWN_DIMENSION { $$ = { type: 'UnknownDimension', value: parseFloat($1), unit: /[a-z]+$/i.exec($1)[0] }; }
| EMS { $$ = { type: 'EmValue', value: parseFloat($1), unit: 'em' }; }
| EXS { $$ = { type: 'ExValue', value: parseFloat($1), unit: 'ex' }; }
| CHS { $$ = { type: 'ChValue', value: parseFloat($1), unit: 'ch' }; }
| REMS { $$ = { type: 'RemValue', value: parseFloat($1), unit: 'rem' }; }
| VHS { $$ = { type: 'VhValue', value: parseFloat($1), unit: 'vh' }; }
| VWS { $$ = { type: 'VwValue', value: parseFloat($1), unit: 'vw' }; }
| VMINS { $$ = { type: 'VminValue', value: parseFloat($1), unit: 'vmin' }; }
| VMAXS { $$ = { type: 'VmaxValue', value: parseFloat($1), unit: 'vmax' }; }
| PERCENTAGE { $$ = { type: 'PercentageValue', value: parseFloat($1), unit: '%' }; }
| ADD dimension { var prev = $2; $$ = prev; }
| SUB dimension { var prev = $2; prev.value *= -1; $$ = prev; }
;
number
: NUMBER { $$ = { type: 'Number', value: parseFloat($1) }; }
| ADD NUMBER { $$ = { type: 'Number', value: parseFloat($2) }; }
| SUB NUMBER { $$ = { type: 'Number', value: parseFloat($2) * -1 }; }
;

File diff suppressed because it is too large Load Diff

View File

@@ -11,10 +11,11 @@ export = pluginCreator;
* @param {PostCssCalcOptions} opts
* @return {import('postcss').Plugin}
*/
declare function pluginCreator(opts: PostCssCalcOptions): import('postcss').Plugin;
declare function pluginCreator(opts: PostCssCalcOptions): import("postcss").Plugin;
declare namespace pluginCreator {
export { postcss, PostCssCalcOptions };
}
declare var postcss: true;
type PostCssCalcOptions = {
precision?: number | false;
preserve?: boolean;
@@ -22,4 +23,3 @@ type PostCssCalcOptions = {
mediaQueries?: boolean;
selectors?: boolean;
};
declare var postcss: true;

View File

@@ -4,11 +4,11 @@ export = reduce;
* @param {number} precision
* @return {import('../parser').CalcNode}
*/
declare function reduce(node: import('../parser').CalcNode, precision: number): import('../parser').CalcNode;
declare function reduce(node: import("../parser").CalcNode, precision: number): import("../parser").CalcNode;
declare namespace reduce {
export { Collectible };
}
type Collectible = {
preOperator: '+' | '-';
node: import('../parser').CalcNode;
preOperator: "+" | "-";
node: import("../parser").CalcNode;
};

View File

@@ -1,4 +1,4 @@
declare function _exports(calc: string, node: import('../parser').CalcNode, originalValue: string, options: {
declare function _exports(calc: string, node: import("../parser").CalcNode, originalValue: string, options: {
precision: number | false;
warnWhenCannotResolve: boolean;
}, result: import("postcss").Result, item: import("postcss").ChildNode): string;

View File

@@ -1,4 +1,4 @@
declare function _exports(node: any, property: 'value' | 'params' | 'selector', options: {
declare function _exports(node: any, property: "value" | "params" | "selector", options: {
precision: number;
preserve: boolean;
warnWhenCannotResolve: boolean;