├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ └── feature_request.yml └── workflows │ └── test.yml ├── .gitignore ├── .npmrc ├── .prettierrc ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── eslint.config.js ├── package.json ├── parser.jison ├── pnpm-lock.yaml ├── src ├── index.js ├── lib │ ├── convertUnit.js │ ├── reducer.js │ ├── stringifier.js │ └── transform.js └── parser.d.ts ├── test ├── convertUnit.js └── index.js ├── tsconfig.json └── types ├── index.d.ts └── lib ├── convertUnit.d.ts ├── reducer.d.ts ├── stringifier.d.ts └── transform.d.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | indent_style = space 10 | indent_size = 2 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [Makefile] 16 | indent_style = tab 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: Create a bug report to help us improve 3 | title: "[Bug]: " 4 | labels: [bug, triage] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: Thank you for taking the time to complete this bug report! 9 | - type: markdown 10 | attributes: 11 | value: Please make sure to provide the information we ask for. This will allow us to help you better. 12 | - type: textarea 13 | id: what-happened 14 | attributes: 15 | label: Describe the bug 16 | description: A clear and concise description of the current behaviour. 17 | placeholder: A bug happened! 18 | validations: 19 | required: true 20 | - type: textarea 21 | id: expected 22 | attributes: 23 | label: Expected behaviour 24 | description: A description of what you expect to happen. 25 | placeholder: I expect to see X or Y 26 | validations: 27 | required: true 28 | - type: textarea 29 | id: reproduction 30 | attributes: 31 | label: Steps to reproduce 32 | description: Please add a link to a repository with a minimal reproduction. Or describe accurately how we can reproduce/verify the bug. 33 | placeholder: | 34 | Example steps (replace with your own): 35 | 1. Clone my repo at https://github.com//example 36 | 2. npm run minify 37 | 3. You should see the error come up 38 | validations: 39 | required: true 40 | - type: input 41 | id: version 42 | attributes: 43 | label: Version 44 | description: The version of postcss-calc you are using. 45 | placeholder: ex. 8.2.0 46 | validations: 47 | required: true 48 | - type: textarea 49 | id: envinfo 50 | attributes: 51 | label: Environment 52 | description: | 53 | Please paste the output of running `npx envinfo --system`. 54 | This will be automatically formatted as a code block, so no need for backticks. 55 | placeholder: | 56 | System: 57 | OS: 58 | CPU: 59 | Memory: 60 | Shell: 61 | render: shell 62 | validations: 63 | required: true 64 | - type: textarea 65 | id: nanoinfo 66 | attributes: 67 | label: Package details 68 | description: | 69 | Please paste the output of running `npm ls postcss-calc postcss`. 70 | This will be automatically formatted as a code block, so no need for backticks. 71 | placeholder: | 72 | ├── postcss-calc@8.1.0 73 | └── postcss@8.3.5 74 | render: shell 75 | validations: 76 | required: true 77 | - type: textarea 78 | id: context 79 | attributes: 80 | label: Additional context 81 | description: Anything else that might be relevant 82 | validations: 83 | required: false 84 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature request 2 | description: Suggest a feature or an improvement 3 | title: "[Feature Request]: " 4 | labels: [enhancement, triage] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: Thank you for taking the time to suggest a new feature! 9 | - type: markdown 10 | attributes: 11 | value: Please describe the feature in detail. Why would it would be a good addition to postcss-calc? 12 | - type: textarea 13 | id: description 14 | attributes: 15 | label: What should be improved? 16 | description: Is your feature request related to a problem? Please describe it. 17 | placeholder: Ex. `foo-bar` is not minimised 18 | validations: 19 | required: true 20 | - type: textarea 21 | id: solution 22 | attributes: 23 | label: Describe the solution you would like 24 | description: A clear and concise description of what you want to happen. 25 | placeholder: Ex. reduce `foo-bar` to the `foo` shorthand. This works in all browsers. 26 | validations: 27 | required: true 28 | - type: textarea 29 | id: alternatives 30 | attributes: 31 | label: Possible alternatives 32 | description: Describe any alternatives you have considered. 33 | placeholder: Ex. it could be replaced by `baz`, but that is potentially unsafe in Chrome. 34 | validations: 35 | required: false 36 | - type: textarea 37 | id: extra 38 | attributes: 39 | label: Additional context 40 | description: Add any other relevant information. 41 | placeholder: Ex. It could be a good idea to double check that `foo` works in Edge and IE. 42 | validations: 43 | required: false 44 | - type: checkboxes 45 | id: can-work 46 | attributes: 47 | label: Are you willing to work on this? 48 | description: Are you willing to help us add this feature? If you are not sure how, feel free to ask for guidance. 49 | options: 50 | - label: Yes, I would like to help 51 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | permissions: {} 10 | 11 | jobs: 12 | lint: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4.2.2 16 | - uses: pnpm/action-setup@v4.0.0 17 | with: 18 | version: 10.1.0 19 | - uses: actions/setup-node@v4.2.0 20 | with: 21 | node-version: 22 22 | cache: 'pnpm' 23 | - run: pnpm install --frozen-lockfile 24 | - name: Lint 25 | run: pnpm lint 26 | 27 | test: 28 | runs-on: ubuntu-latest 29 | strategy: 30 | matrix: 31 | node-version: [18, 20, 22] 32 | steps: 33 | - uses: actions/checkout@v4.2.2 34 | - uses: pnpm/action-setup@v4.0.0 35 | with: 36 | version: 10.1.0 37 | - name: Instal Node.js ${{ matrix.node-version }} 38 | uses: actions/setup-node@v4.2.0 39 | with: 40 | node-version: ${{ matrix.node-version }} 41 | cache: 'pnpm' 42 | - name: Install dependencies 43 | run: pnpm install --frozen-lockfile 44 | - name: Run tests 45 | run: pnpm test 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | test/fixtures/*.actual.css 3 | src/parser.js 4 | yarn-error.log 5 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | auto-install-peers=true 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "singleQuote": true 4 | } 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines. 4 | 5 | ## [10.1.1](https://github.com/postcss/postcss-calc/compare/v10.1.0...v10.1.1) (2025-01-31) 6 | 7 | 8 | ### Bug Fixes 9 | 10 | * handle calc keywords correctly ([#234](https://github.com/postcss/postcss-calc/issues/234)) ([87d57ef](https://github.com/postcss/postcss-calc/commit/87d57ef74d897fb2b9f1ecc759bedaecee3989e6)), closes [#210](https://github.com/postcss/postcss-calc/issues/210) 11 | 12 | ## [10.1.0](https://github.com/postcss/postcss-calc/compare/v10.0.2...v10.1.0) (2025-01-07) 13 | 14 | 15 | ### Features 16 | 17 | * add support for lh & rlh units ([9b6d7a1](https://github.com/postcss/postcss-calc/commit/9b6d7a16553f9d61ef8097f4e5425ae0c8a7574f)) 18 | 19 | 20 | ### Bug Fixes 21 | 22 | * Ignore calc-size from detection ([#230](https://github.com/postcss/postcss-calc/issues/230)) ([cac6f39](https://github.com/postcss/postcss-calc/commit/cac6f39951617b45bc5bed84be3ed099df619bbf)) 23 | 24 | ## [10.0.2](https://github.com/postcss/postcss-calc/compare/v10.0.1...v10.0.2) (2024-08-16) 25 | 26 | 27 | ### Bug Fixes 28 | 29 | * add support for svh, lvh, dvh, svw, lvw, dvw, svmin, lvmin, dvmin, svmax, lvmax, dvmax units ([f5eaea1](https://github.com/postcss/postcss-calc/commit/f5eaea129f0546451638c6508009a5cfff1a6ddc)) 30 | 31 | # [11.0.1](https://github.com/postcss/postcss-calc/compare/v10.0.0...v10.0.1) (2024-08-05) 32 | 33 | ## Bug Fixes 34 | 35 | * add support for container query units ([#214](https://github.com/postcss/postcss-calc/issues/214)) ([3f2b43a](https://github.com/postcss/postcss-calc/commit/3f2b43a9d65589c907fa8cbb79a6141603c56c3d)), closes [#199](https://github.com/postcss/postcss-calc/issues/199) 36 | * update postcss-selector-parser ([3606777](https://github.com/postcss/postcss-calc/commit/3606777a1611bdfa67672e4dadd6c1b1871e163f)) 37 | * update postcss-selector-parser ([a03fb73](https://github.com/postcss/postcss-calc/commit/a03fb73c0d60845c2f98918d8108e231b8f7f80d)) 38 | 39 | # 10.0.0 (2024-04-26) 40 | 41 | ## Breaking Changes 42 | 43 | * drop support for Node.js 14, 16, 19 and 21 44 | 45 | # 9.0.1 (2023-05-05) 46 | 47 | ## Bug Fixes 48 | 49 | * fix disappearing calc expression when source contains extra brackets ([18bb47bd0](https://github.com/postcss/postcss-calc/commit/18bb47bd095d2a5b224b0a60521e52f620474b3d)) 50 | 51 | # 9.0.0 (2023-04-29) 52 | 53 | ## Breaking Changes 54 | 55 | * drop support for Node.js versions before 14 56 | 57 | # [8.2.4](https://github.com/postcss/postcss-calc/compare/v8.2.3...v8.2.4) (2022-02-05) 58 | 59 | ## Patch Changes 60 | 61 | * convert source to CommonJS and publish untranspiled code ([b55adcb](https://github.com/postcss/postcss-calc/commit/b55adcb285ea8d385bf802a0f7edeb2d12be1549)) 62 | 63 | # [8.2.3](https://github.com/postcss/postcss-calc/compare/v8.2.2...v8.2.3) (2022-01-28) 64 | 65 | ## Bug Fixes 66 | 67 | * improve types ([f2cce1b](https://github.com/postcss/postcss-calc/commit/f2cce1bc1d47af7ab02891c61b4c1485d6e6dfd3)) 68 | 69 | ## [8.2.2](https://github.com/postcss/postcss-calc/compare/v8.2.1...v8.2.2) (2022-01-12) 70 | 71 | ## Bug Fixes 72 | 73 | * respect CSS var when reducing ([99d9fa5](https://github.com/postcss/postcss-calc/commit/99d9fa53a7fba3586590d0c45a0982b09e8bf5c6)) 74 | 75 | # [8.2.1](https://github.com/postcss/postcss-calc/compare/v8.2.0...v8.2.1) (2022-01-11) 76 | 77 | ## Bug Fixes 78 | 79 | * preserve brackets around functions ([0b70a1d](https://github.com/postcss/postcss-calc/commit/0b70a1d5773f17373991b1294e3ae618600aae7d)), closes [#113](https://github.com/postcss/postcss-calc/issues/113) [#115](https://github.com/postcss/postcss-calc/issues/115) 80 | 81 | # [8.2.0](https://github.com/postcss/postcss-calc/compare/v8.1.0...v8.2.0) (2022-01-07) 82 | 83 | ## Features 84 | 85 | * add types ([#155](https://github.com/postcss/postcss-calc/issues/155)) ([4c96c79](https://github.com/postcss/postcss-calc/commit/4c96c793fbc7807bb138d05b92a93bd29a2e94ac)) 86 | 87 | # [8.1.0](https://github.com/postcss/postcss-calc/compare/v8.0.0...v8.1.0) (2022-01-03) 88 | 89 | ## Features 90 | 91 | - avoid fatal error ([#137](https://github.com/postcss/postcss-calc/issues/137)) ([125be6a](https://github.com/postcss/postcss-calc/commit/125be6ad1b1899ecd72d9a70dfe1b0690d4214b2)) 92 | 93 | # 8.0.0 94 | 95 | - Breaking: Updated PostCSS from v7.x to v8.x ([#125](https://github.com/postcss/postcss-calc/pull/125)) 96 | 97 | # 7.0.5 98 | 99 | - Fixed: reduction 100 | 101 | # 7.0.4 102 | 103 | - Fixed: strips away important factors from multiplications in calc() ([#107](https://github.com/postcss/postcss-calc/issues/107)) 104 | 105 | # 7.0.3 106 | 107 | - Fixed: substracted css-variable from zero ([#111](https://github.com/postcss/postcss-calc/issues/111)) 108 | 109 | # 7.0.2 110 | 111 | - Fixed: incorrect reduction of subtraction from zero ([#88](https://github.com/postcss/postcss-calc/issues/88)) 112 | - Fixed: doesn't remove calc for single function 113 | - Fixed: relax parser on unknown units ([#76](https://github.com/postcss/postcss-calc/issues/76)) 114 | - Fixed: handle numbers with exponen composed ([#83](https://github.com/postcss/postcss-calc/pull/83)) 115 | - Fixed: handle plus sign before value ([#79](https://github.com/postcss/postcss-calc/pull/79)) 116 | - Fixed: better handle precision for nested calc ([#75](https://github.com/postcss/postcss-calc/pull/75)) 117 | - Fixed: properly handle nested add and sub expression inside sub expression ([#64](https://github.com/postcss/postcss-calc/issues/64)) 118 | - Fixed: handle uppercase units and functions ([#71](https://github.com/postcss/postcss-calc/pull/71)) 119 | - Fixed: do not break `calc` with single var ([cssnano/cssnano#725](https://github.com/cssnano/cssnano/issues/725)) 120 | - Updated: `postcss` to 7.0.27 (patch) 121 | - Updated: `postcss-selector-parser` to 6.0.2 122 | - Updated: `postcss-value-parser` to 4.0.2 123 | 124 | # 7.0.1 125 | 126 | - Updated: `postcss` to 7.0.2 (patch) 127 | - Updated: `postcss-selector-parser` to 5.0.0-rc.4 (patch) 128 | - Updated: `postcss-value-parser` to 3.3.1 (patch) 129 | 130 | # 7.0.0 131 | 132 | - Changed: Updated postcss-selector-parser to version 5.0.0-rc.3 133 | - Changed: Dropped reduce-css-calc as a dependency 134 | - Fixed: Support constant() and env() ([#42](https://github.com/postcss/postcss-calc/issues/42), [#48](https://github.com/postcss/postcss-calc/issues/48)) 135 | - Fixed: Support custom properties with "calc" in its name ([#50](https://github.com/postcss/postcss-calc/issues/50)) 136 | - Fixed: Remove unnecessary whitespace around `*` and `/` ([cssnano#625](https://github.com/cssnano/cssnano/issues/625)) 137 | - Fixed: Arithmetic bugs around subtraction ([#49](https://github.com/postcss/postcss-calc/issues/49)) 138 | - Fixed: Handling of nested calc statements ([reduce-css-calc#49](https://github.com/MoOx/reduce-css-calc/issues/49)) 139 | - Fixed: Bugs regarding complex calculations ([reduce-cs-calc#45](https://github.com/MoOx/reduce-css-calc/issues/45)) 140 | - Fixed: `100%` incorrectly being transformed to `1` ([reduce-css-calc#44](https://github.com/MoOx/reduce-css-calc/issues/44)) 141 | - Added: support for case-insensitive calc statements 142 | 143 | # 6.0.2 - 2018-09-25 144 | 145 | - Fixed: use PostCSS 7 (thanks to @douglasduteil) 146 | 147 | # 6.0.1 - 2017-10-10 148 | 149 | - Fixed: throwing error for attribute selectors without a value 150 | 151 | # 6.0.0 - 2017-05-08 152 | 153 | - Breaking: Updated PostCSS from v5.x to v6.x, and reduce-css-calc from v1.x 154 | to v2.x (thanks to @andyjansson). 155 | 156 | # 5.3.1 - 2016-08-22 157 | 158 | - Fixed: avoid security issue related to ``reduce-css-calc@< 1.2.4``. 159 | 160 | # 5.3.0 - 2016-07-11 161 | 162 | - Added: support for selector transformation via `selectors` option. 163 | ([#29](https://github.com/postcss/postcss-calc/pull/29) - @uniquegestaltung) 164 | 165 | # 5.2.1 - 2016-04-10 166 | 167 | - Fixed: support for multiline value 168 | ([#27](https://github.com/postcss/postcss-calc/pull/27)) 169 | 170 | # 5.2.0 - 2016-01-08 171 | 172 | - Added: "mediaQueries" option for `@media` support 173 | ([#22](https://github.com/postcss/postcss-calc/pull/22)) 174 | 175 | # 5.1.0 - 2016-01-07 176 | 177 | - Added: "warnWhenCannotResolve" option to warn when calc() are not reduced to a single value 178 | ([#20](https://github.com/postcss/postcss-calc/pull/20)) 179 | 180 | # 5.0.0 - 2015-08-25 181 | 182 | - Removed: compatibility with postcss v4.x 183 | - Added: compatibility with postcss v5.x 184 | 185 | # 4.1.0 - 2015-04-09 186 | 187 | - Added: compatibility with postcss v4.1.x ([#12](https://github.com/postcss/postcss-calc/pull/12)) 188 | 189 | # 4.0.1 - 2015-04-09 190 | 191 | - Fixed: `preserve` option does not create duplicated values ([#7](https://github.com/postcss/postcss-calc/issues/7)) 192 | 193 | # 4.0.0 - 2015-01-26 194 | 195 | - Added: compatibility with postcss v4.x 196 | - Changed: partial compatiblity with postcss v3.x (stack traces have lost filename) 197 | 198 | # 3.0.0 - 2014-11-24 199 | 200 | - Added: GNU like exceptions ([#4](https://github.com/postcss/postcss-calc/issues/4)) 201 | - Added: `precision` option ([#5](https://github.com/postcss/postcss-calc/issues/5)) 202 | - Added: `preserve` option ([#6](https://github.com/postcss/postcss-calc/issues/6)) 203 | 204 | # 2.1.0 - 2014-10-15 205 | 206 | - Added: source of the error (gnu like message) (fix [#3](https://github.com/postcss/postcss-calc/issues/3)) 207 | 208 | # 2.0.1 - 2014-08-10 209 | 210 | - Fixed: correctly ignore unrecognized values (fix [#2](https://github.com/postcss/postcss-calc/issues/2)) 211 | 212 | # 2.0.0 - 2014-08-06 213 | 214 | - Changed: Plugin now return a function to have a consistent api. ([ref 1](https://github.com/ianstormtaylor/rework-color-function/issues/6), [ref 2](https://twitter.com/jongleberry/status/496552790416576513)) 215 | 216 | # 1.0.0 - 2014-08-04 217 | 218 | ✨ First release based on [rework-calc](https://github.com/reworkcss/rework-calc) v1.1.0 (code mainly exported to [`reduce-css-calc`](https://github.com/MoOx/reduce-css-calc)) 219 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | The following outlines a set of guidelines for contributing to this project. These are mostly guidelines, not rules. Use your best judgement, and feel free to propose changes to this document in a pull request. 4 | 5 | ## Asking questions 6 | 7 | Prefer asking questions in the [PostCSS chat](https://gitter.im/postcss/postcss) over opening issues. 8 | Leveraging the community would likely get you an answer faster, as well as leave us available to solve issues and make the product better. 9 | 10 | ## Reporting Bugs 11 | 12 | Before submitting a new issue, be sure to make a cursory search to see if the problem has already been reported. If it has and the issue is still open, leave a comment on the existing issue instead of opening a new one. 13 | 14 | If no prior issue exist, create a new one. Explain the problem and include additional details to help maintainers reproduce the problem: 15 | 16 | * Use a clear and descriptive title. 17 | * Summarize the problem you are having. 18 | * Include details about your configuration and environment. 19 | * Provide steps to reproduce the problem. 20 | * Describe what behavior you expected to see. 21 | 22 | ## Requesting Enhancements 23 | 24 | Before submitting a new issue, be sure to make a cursory search to see if the enhancement has already been requested. If no such issue exists, create a new one and detail it to the best of your ability: 25 | 26 | * Use a clear and descriptive title. 27 | * Provide a description of the proposed enhancement. 28 | * Exemplify what needs/uses this enhancement would address. 29 | 30 | ## Submitting Pull Requests 31 | 32 | Before contributing any code to the project, be sure to either open a new issue in the issue tracker detailing what you intend to contribute, or comment on an existing issue if one exists. 33 | This allows us to: 34 | 35 | * give feedback early on before significant effort has been put into the endevour. 36 | * align your contribution with ongoing efforts. 37 | * make sure that there's no ongoing effort into the issue already. 38 | 39 | When submitting your pull request, make sure that you: 40 | 41 | * use a clear and descriptive title. 42 | * summarize your contribution. 43 | * list the issues that this contribution addresses. 44 | * include tests for your contribution. 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Maxime Thirouin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PostCSS Calc [PostCSS][PostCSS] 2 | 3 | [![NPM Version][npm-img]][npm-url] 4 | [![Support Chat][git-img]][git-url] 5 | 6 | [PostCSS Calc] lets you reduce `calc()` references whenever it's possible. 7 | When multiple units are mixed together in the same expression, the `calc()` 8 | statement is left as is, to fallback to the [W3C calc() implementation]. 9 | 10 | ## Installation 11 | 12 | ```bash 13 | npm install postcss-calc 14 | ``` 15 | 16 | ## Usage 17 | 18 | ```js 19 | // dependencies 20 | var fs = require("fs") 21 | var postcss = require("postcss") 22 | var calc = require("postcss-calc") 23 | 24 | // css to be processed 25 | var css = fs.readFileSync("input.css", "utf8") 26 | 27 | // process css 28 | var output = postcss() 29 | .use(calc()) 30 | .process(css) 31 | .css 32 | ``` 33 | 34 | Using this `input.css`: 35 | 36 | ```css 37 | h1 { 38 | font-size: calc(16px * 2); 39 | height: calc(100px - 2em); 40 | width: calc(2*var(--base-width)); 41 | margin-bottom: calc(16px * 1.5); 42 | } 43 | ``` 44 | 45 | you will get: 46 | 47 | ```css 48 | h1 { 49 | font-size: 32px; 50 | height: calc(100px - 2em); 51 | width: calc(2*var(--base-width)); 52 | margin-bottom: 24px 53 | } 54 | ``` 55 | Checkout [tests] for more examples. 56 | 57 | ### Options 58 | 59 | #### `precision` (default: `5`) 60 | 61 | Allow you to define the precision for decimal numbers. 62 | 63 | ```js 64 | var out = postcss() 65 | .use(calc({precision: 10})) 66 | .process(css) 67 | .css 68 | ``` 69 | 70 | #### `preserve` (default: `false`) 71 | 72 | Allow you to preserve calc() usage in output so browsers will handle decimal 73 | precision themselves. 74 | 75 | ```js 76 | var out = postcss() 77 | .use(calc({preserve: true})) 78 | .process(css) 79 | .css 80 | ``` 81 | 82 | #### `warnWhenCannotResolve` (default: `false`) 83 | 84 | Adds warnings when calc() are not reduced to a single value. 85 | 86 | ```js 87 | var out = postcss() 88 | .use(calc({warnWhenCannotResolve: true})) 89 | .process(css) 90 | .css 91 | ``` 92 | 93 | #### `mediaQueries` (default: `false`) 94 | 95 | Allows calc() usage as part of media query declarations. 96 | 97 | ```js 98 | var out = postcss() 99 | .use(calc({mediaQueries: true})) 100 | .process(css) 101 | .css 102 | ``` 103 | 104 | #### `selectors` (default: `false`) 105 | 106 | Allows calc() usage as part of selectors. 107 | 108 | ```js 109 | var out = postcss() 110 | .use(calc({selectors: true})) 111 | .process(css) 112 | .css 113 | ``` 114 | 115 | Example: 116 | 117 | ```css 118 | div[data-size="calc(3*3)"] { 119 | width: 100px; 120 | } 121 | ``` 122 | 123 | --- 124 | 125 | ## Related PostCSS plugins 126 | To replace the value of CSS custom properties at build time, try [PostCSS Custom Properties]. 127 | 128 | ## Contributing 129 | 130 | Work on a branch, install dev-dependencies, respect coding style & run tests 131 | before submitting a bug fix or a feature. 132 | 133 | ```bash 134 | git clone git@github.com:postcss/postcss-calc.git 135 | git checkout -b patch-1 136 | npm install 137 | npm test 138 | ``` 139 | 140 | ## [Changelog](CHANGELOG.md) 141 | 142 | ## [License](LICENSE) 143 | 144 | [git-img]: https://img.shields.io/badge/support-chat-blue.svg 145 | [git-url]: https://gitter.im/postcss/postcss 146 | [npm-img]: https://img.shields.io/npm/v/postcss-calc.svg 147 | [npm-url]: https://www.npmjs.com/package/postcss-calc 148 | 149 | [PostCSS]: https://github.com/postcss 150 | [PostCSS Calc]: https://github.com/postcss/postcss-calc 151 | [PostCSS Custom Properties]: https://github.com/postcss/postcss-custom-properties 152 | [tests]: src/__tests__/index.js 153 | [W3C calc() implementation]: https://www.w3.org/TR/css3-values/#calc-notation 154 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | const js = require('@eslint/js'); 2 | const eslintConfigPrettier = require('eslint-config-prettier'); 3 | 4 | module.exports = [ 5 | { 6 | ignores: ['src/parser.js'], 7 | }, 8 | js.configs.recommended, 9 | eslintConfigPrettier, 10 | { 11 | languageOptions: { 12 | sourceType: 'commonjs', 13 | }, 14 | rules: { 15 | curly: 'error', 16 | }, 17 | }, 18 | ]; 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "postcss-calc", 3 | "version": "10.1.1", 4 | "description": "PostCSS plugin to reduce calc()", 5 | "keywords": [ 6 | "css", 7 | "postcss", 8 | "postcss-plugin", 9 | "calculation", 10 | "calc" 11 | ], 12 | "homepage": "https://github.com/postcss/postcss-calc", 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/postcss/postcss-calc.git" 16 | }, 17 | "main": "src/index.js", 18 | "types": "types/index.d.ts", 19 | "files": [ 20 | "src", 21 | "types", 22 | "LICENSE" 23 | ], 24 | "scripts": { 25 | "prepare": "pnpm run build && tsc", 26 | "build": "jison ./parser.jison -o src/parser.js", 27 | "lint": "eslint . && tsc", 28 | "test": "node --test" 29 | }, 30 | "author": "Andy Jansson", 31 | "license": "MIT", 32 | "engines": { 33 | "node": "^18.12 || ^20.9 || >=22.0" 34 | }, 35 | "devDependencies": { 36 | "@types/node": "^22.15.17", 37 | "eslint": "^9.25.1", 38 | "eslint-config-prettier": "^10.1.5", 39 | "jison-gho": "0.6.1-216", 40 | "postcss": "^8.5.3", 41 | "prettier": "^3.5.3", 42 | "typescript": "~5.8.3" 43 | }, 44 | "dependencies": { 45 | "postcss-selector-parser": "^7.1.0", 46 | "postcss-value-parser": "^4.2.0" 47 | }, 48 | "peerDependencies": { 49 | "postcss": "^8.4.38" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /parser.jison: -------------------------------------------------------------------------------- 1 | /* description: Parses expressions. */ 2 | 3 | /* lexical grammar */ 4 | %lex 5 | 6 | %options case-insensitive 7 | 8 | %% 9 | \s+ /* skip whitespace */ 10 | 11 | (\-(webkit|moz)\-)?calc\b return 'CALC'; 12 | 13 | [a-z][a-z0-9-]*\s*\((?:(?:\"(?:\\.|[^\"\\])*\"|\'(?:\\.|[^\'\\])*\')|\([^)]*\)|[^\(\)]*)*\) return 'FUNCTION'; 14 | 15 | "*" return 'MUL'; 16 | "/" return 'DIV'; 17 | "+" return 'ADD'; 18 | "-" return 'SUB'; 19 | 20 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)em\b return 'EMS'; 21 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)ex\b return 'EXS'; 22 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)ch\b return 'CHS'; 23 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)rem\b return 'REMS'; 24 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)vw\b return 'VWS'; 25 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)svw\b return 'SVWS'; 26 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)lvw\b return 'LVWS'; 27 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)dvw\b return 'DVWS'; 28 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)vh\b return 'VHS'; 29 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)svh\b return 'SVHS'; 30 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)lvh\b return 'LVHS'; 31 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)dvh\b return 'DVHS'; 32 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)vmin\b return 'VMINS'; 33 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)svmin\b return 'SVMINS'; 34 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)lvmin\b return 'LVMINS'; 35 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)dvmin\b return 'DVMINS'; 36 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)vmax\b return 'VMAXS'; 37 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)svmax\b return 'SVMAXS'; 38 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)lvmax\b return 'LVMAXS'; 39 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)dvmax\b return 'DVMAXS'; 40 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)vb\b return 'VBS'; 41 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)svb\b return 'SVBS'; 42 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)lvb\b return 'LVBS'; 43 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)dvb\b return 'DVBS'; 44 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)vi\b return 'VIS'; 45 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)svi\b return 'SVIS'; 46 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)lvi\b return 'LVIS'; 47 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)dvi\b return 'DVIS'; 48 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)cqw\b return 'CQWS'; 49 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)cqh\b return 'CQHS'; 50 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)cqi\b return 'CQIS'; 51 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)cqb\b return 'CQBS'; 52 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)cqmin\b return 'CQMINS'; 53 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)cqmax\b return 'CQMAXS'; 54 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)lh\b return 'LHS'; 55 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)rlh\b return 'RLHS'; 56 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)cm\b return 'LENGTH'; 57 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)mm\b return 'LENGTH'; 58 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)Q\b return 'LENGTH'; 59 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)in\b return 'LENGTH'; 60 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)pt\b return 'LENGTH'; 61 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)pc\b return 'LENGTH'; 62 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)px\b return 'LENGTH'; 63 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)deg\b return 'ANGLE'; 64 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)grad\b return 'ANGLE'; 65 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)rad\b return 'ANGLE'; 66 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)turn\b return 'ANGLE'; 67 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)s\b return 'TIME'; 68 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)ms\b return 'TIME'; 69 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)Hz\b return 'FREQ'; 70 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)kHz\b return 'FREQ'; 71 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)dpi\b return 'RES'; 72 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)dpcm\b return 'RES'; 73 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)dppx\b return 'RES'; 74 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)\% return 'PERCENTAGE'; 75 | (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)\b return 'NUMBER'; 76 | ("infinity"|"pi"|"e")\b return 'CALC_KEYWORD'; 77 | 78 | 79 | (([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'; 80 | 81 | "(" return 'LPAREN'; 82 | ")" return 'RPAREN'; 83 | 84 | <> return 'EOF'; 85 | 86 | /lex 87 | 88 | %left ADD SUB 89 | %left MUL DIV 90 | %left UPREC 91 | 92 | 93 | %start expression 94 | 95 | %% 96 | 97 | expression 98 | : math_expression EOF { return $1; } 99 | ; 100 | 101 | math_expression 102 | : CALC LPAREN math_expression RPAREN { $$ = $3; } 103 | | math_expression ADD math_expression { $$ = { type: 'MathExpression', operator: $2, left: $1, right: $3 }; } 104 | | math_expression SUB math_expression { $$ = { type: 'MathExpression', operator: $2, left: $1, right: $3 }; } 105 | | math_expression MUL math_expression { $$ = { type: 'MathExpression', operator: $2, left: $1, right: $3 }; } 106 | | math_expression DIV math_expression { $$ = { type: 'MathExpression', operator: $2, left: $1, right: $3 }; } 107 | | LPAREN math_expression RPAREN { $$ = { type: 'ParenthesizedExpression', content: $2 }; } 108 | | function { $$ = $1; } 109 | | dimension { $$ = $1; } 110 | | number { $$ = $1; } 111 | | calc_keyword { $$ = $1; } 112 | ; 113 | 114 | function 115 | : FUNCTION { $$ = { type: 'Function', value: $1 }; } 116 | ; 117 | 118 | dimension 119 | : LENGTH { $$ = { type: 'LengthValue', value: parseFloat($1), unit: /[a-z]+$/i.exec($1)[0] }; } 120 | | ANGLE { $$ = { type: 'AngleValue', value: parseFloat($1), unit: /[a-z]+$/i.exec($1)[0] }; } 121 | | TIME { $$ = { type: 'TimeValue', value: parseFloat($1), unit: /[a-z]+$/i.exec($1)[0] }; } 122 | | FREQ { $$ = { type: 'FrequencyValue', value: parseFloat($1), unit: /[a-z]+$/i.exec($1)[0] }; } 123 | | RES { $$ = { type: 'ResolutionValue', value: parseFloat($1), unit: /[a-z]+$/i.exec($1)[0] }; } 124 | | UNKNOWN_DIMENSION { $$ = { type: 'UnknownDimension', value: parseFloat($1), unit: /[a-z]+$/i.exec($1)[0] }; } 125 | | EMS { $$ = { type: 'EmValue', value: parseFloat($1), unit: 'em' }; } 126 | | EXS { $$ = { type: 'ExValue', value: parseFloat($1), unit: 'ex' }; } 127 | | CHS { $$ = { type: 'ChValue', value: parseFloat($1), unit: 'ch' }; } 128 | | REMS { $$ = { type: 'RemValue', value: parseFloat($1), unit: 'rem' }; } 129 | | VHS { $$ = { type: 'VhValue', value: parseFloat($1), unit: 'vh' }; } 130 | | SVHS { $$ = { type: 'SvhValue', value: parseFloat($1), unit: 'svh' }; } 131 | | LVHS { $$ = { type: 'LvhValue', value: parseFloat($1), unit: 'lvh' }; } 132 | | DVHS { $$ = { type: 'DvhValue', value: parseFloat($1), unit: 'dvh' }; } 133 | | VWS { $$ = { type: 'VwValue', value: parseFloat($1), unit: 'vw' }; } 134 | | SVWS { $$ = { type: 'SvwValue', value: parseFloat($1), unit: 'svw' }; } 135 | | LVWS { $$ = { type: 'LvwValue', value: parseFloat($1), unit: 'lvw' }; } 136 | | DVWS { $$ = { type: 'DvwValue', value: parseFloat($1), unit: 'dvw' }; } 137 | | VMINS { $$ = { type: 'VminValue', value: parseFloat($1), unit: 'vmin' }; } 138 | | SVMINS { $$ = { type: 'SvminValue', value: parseFloat($1), unit: 'svmin' }; } 139 | | LVMINS { $$ = { type: 'LvminValue', value: parseFloat($1), unit: 'lvmin' }; } 140 | | DVMINS { $$ = { type: 'DvminValue', value: parseFloat($1), unit: 'dvmin' }; } 141 | | VMAXS { $$ = { type: 'VmaxValue', value: parseFloat($1), unit: 'vmax' }; } 142 | | SVMAXS { $$ = { type: 'SvmaxValue', value: parseFloat($1), unit: 'svmax' }; } 143 | | LVMAXS { $$ = { type: 'LvmaxValue', value: parseFloat($1), unit: 'lvmax' }; } 144 | | DVMAXS { $$ = { type: 'DvmaxValue', value: parseFloat($1), unit: 'dvmax' }; } 145 | | VBS { $$ = { type: 'VbValue', value: parseFloat($1), unit: 'vb' }; } 146 | | SVBS { $$ = { type: 'SvbValue', value: parseFloat($1), unit: 'svb' }; } 147 | | LVBS { $$ = { type: 'LvbValue', value: parseFloat($1), unit: 'lvb' }; } 148 | | DVBS { $$ = { type: 'DvbValue', value: parseFloat($1), unit: 'dvb' }; } 149 | | VIS { $$ = { type: 'VhValue', value: parseFloat($1), unit: 'vi' }; } 150 | | SVIS { $$ = { type: 'SvhValue', value: parseFloat($1), unit: 'svi' }; } 151 | | LVIS { $$ = { type: 'LvhValue', value: parseFloat($1), unit: 'lvi' }; } 152 | | DVIS { $$ = { type: 'DvhValue', value: parseFloat($1), unit: 'dvi' }; } 153 | | CQWS { $$ = { type: 'CqwValue', value: parseFloat($1), unit: 'cqw' }; } 154 | | CQHS { $$ = { type: 'CqhValue', value: parseFloat($1), unit: 'cqh' }; } 155 | | CQIS { $$ = { type: 'CqiValue', value: parseFloat($1), unit: 'cqi' }; } 156 | | CQBS { $$ = { type: 'CqbValue', value: parseFloat($1), unit: 'cqb' }; } 157 | | CQMINS { $$ = { type: 'CqminValue', value: parseFloat($1), unit: 'cqmin' }; } 158 | | CQMAXS { $$ = { type: 'CqmaxValue', value: parseFloat($1), unit: 'cqmax' }; } 159 | | LHS { $$ = { type: 'LhValue', value: parseFloat($1), unit: 'lh' }; } 160 | | RLHS { $$ = { type: 'RlhValue', value: parseFloat($1), unit: 'rlh' }; } 161 | | PERCENTAGE { $$ = { type: 'PercentageValue', value: parseFloat($1), unit: '%' }; } 162 | | ADD dimension { var prev = $2; $$ = prev; } 163 | | SUB dimension { var prev = $2; prev.value *= -1; $$ = prev; } 164 | ; 165 | 166 | calc_keyword 167 | : CALC_KEYWORD { $$ = { type: 'CalcKeyword', value: $1 }; } 168 | ; 169 | 170 | number 171 | : NUMBER { $$ = { type: 'Number', value: parseFloat($1) }; } 172 | | ADD NUMBER { $$ = { type: 'Number', value: parseFloat($2) }; } 173 | | SUB NUMBER { $$ = { type: 'Number', value: parseFloat($2) * -1 }; } 174 | ; 175 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | dependencies: 11 | postcss-selector-parser: 12 | specifier: ^7.1.0 13 | version: 7.1.0 14 | postcss-value-parser: 15 | specifier: ^4.2.0 16 | version: 4.2.0 17 | devDependencies: 18 | '@types/node': 19 | specifier: ^22.15.17 20 | version: 22.15.17 21 | eslint: 22 | specifier: ^9.25.1 23 | version: 9.25.1 24 | eslint-config-prettier: 25 | specifier: ^10.1.5 26 | version: 10.1.5(eslint@9.25.1) 27 | jison-gho: 28 | specifier: 0.6.1-216 29 | version: 0.6.1-216 30 | postcss: 31 | specifier: ^8.5.3 32 | version: 8.5.3 33 | prettier: 34 | specifier: ^3.5.3 35 | version: 3.5.3 36 | typescript: 37 | specifier: ~5.8.3 38 | version: 5.8.3 39 | 40 | packages: 41 | 42 | '@eslint-community/eslint-utils@4.4.1': 43 | resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} 44 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 45 | peerDependencies: 46 | eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 47 | 48 | '@eslint-community/regexpp@4.12.1': 49 | resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} 50 | engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} 51 | 52 | '@eslint/config-array@0.20.0': 53 | resolution: {integrity: sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==} 54 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 55 | 56 | '@eslint/config-helpers@0.2.2': 57 | resolution: {integrity: sha512-+GPzk8PlG0sPpzdU5ZvIRMPidzAnZDl/s9L+y13iodqvb8leL53bTannOrQ/Im7UkpsmFU5Ily5U60LWixnmLg==} 58 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 59 | 60 | '@eslint/core@0.13.0': 61 | resolution: {integrity: sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==} 62 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 63 | 64 | '@eslint/eslintrc@3.3.1': 65 | resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} 66 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 67 | 68 | '@eslint/js@9.25.1': 69 | resolution: {integrity: sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==} 70 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 71 | 72 | '@eslint/object-schema@2.1.6': 73 | resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} 74 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 75 | 76 | '@eslint/plugin-kit@0.2.8': 77 | resolution: {integrity: sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==} 78 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 79 | 80 | '@gerhobbelt/ast-types@0.10.1-15': 81 | resolution: {integrity: sha512-CXoPKXH9xqCiWza0S/4TFjXa7aS8GAA8gYenBzhMN5+VwWDFBd2QVUGESq75nRe+yxgUkzSFQvq6rtAuQLRouA==} 82 | engines: {node: '>= 4.0'} 83 | 84 | '@gerhobbelt/ast-types@0.9.13-4': 85 | resolution: {integrity: sha512-V8UIj1XN6XOP014fPpecxEa7AlAB9kaTOB/wF9UbguuwIMWCHDmdA9i03JDK9zXyVDVaLWCYh42JK8F9f27AtA==} 86 | engines: {node: '>= 4.0'} 87 | 88 | '@gerhobbelt/ast-util@0.6.1-4': 89 | resolution: {integrity: sha512-NP7YZh7rR6CNiMLyKTF+qb2Epx0r5x/zKQ3Z14TgXl73YJurC8WkMkFM9nDj8cRXb6R+f+BEu4DqAvvYKMxbqg==} 90 | engines: {node: '>= 4.0'} 91 | 92 | '@gerhobbelt/esprima@4.0.1-15': 93 | resolution: {integrity: sha512-0VITWyCsgbRlNv0WjWfEszAHcgJL/iAQKSNfzU/uoJ6S7W/mgM8q4iWmzv7BDl4nmRpcYoSqW2B/BwXJNFzNMg==} 94 | engines: {node: '>=4'} 95 | hasBin: true 96 | 97 | '@gerhobbelt/json5@0.5.1-21': 98 | resolution: {integrity: sha512-BwqwZb2iv7Iu4nwJwj1D0LKvnvKxMVXB+VgTsrwb+s36KY/xYaTmKbFq0MAoEGiMBcB8jz3/L/J6lBBdx5XqAw==} 99 | hasBin: true 100 | 101 | '@gerhobbelt/linewrap@0.2.2-3': 102 | resolution: {integrity: sha512-u2eUbXgNtqckBI4gxds/uiUNoytT+qIqpePmVDI5isW8A18uB3Qz1P+UxAHgFafGOZWJNrpR0IKnZhl7QhaUng==} 103 | engines: {node: '>=4.0'} 104 | 105 | '@gerhobbelt/nomnom@1.8.4-24': 106 | resolution: {integrity: sha512-spzyz2vHd1BhYNSUMXjqJOwk4AjnOIzZz3cYCOryUCzMvlqz01/+SAPEy/pjT47CrOGdWd0JgemePjru1aLYgQ==} 107 | engines: {node: '>=4.0'} 108 | 109 | '@gerhobbelt/recast@0.13.0-24': 110 | resolution: {integrity: sha512-WqIAY+8RwgsgZHtJjeZJK3/w60uOMGOiW3Tcrm+gE31a3lcCjMnCgmYbauHLGCUYdRtepGS+jnr29ub3MFhKCg==} 111 | engines: {node: '>= 4.0'} 112 | 113 | '@gerhobbelt/xregexp@3.2.0-22': 114 | resolution: {integrity: sha512-TRu38Z67VxFSMrBP3z/ORiJVQqp56ulidZirbobtmJnVGBWLdo4GbHtihgIJFGieIZuk+LxmPkK45SY+SQsR3A==} 115 | 116 | '@humanfs/core@0.19.1': 117 | resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} 118 | engines: {node: '>=18.18.0'} 119 | 120 | '@humanfs/node@0.16.6': 121 | resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} 122 | engines: {node: '>=18.18.0'} 123 | 124 | '@humanwhocodes/module-importer@1.0.1': 125 | resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} 126 | engines: {node: '>=12.22'} 127 | 128 | '@humanwhocodes/retry@0.3.1': 129 | resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} 130 | engines: {node: '>=18.18'} 131 | 132 | '@humanwhocodes/retry@0.4.3': 133 | resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} 134 | engines: {node: '>=18.18'} 135 | 136 | '@types/estree@1.0.6': 137 | resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} 138 | 139 | '@types/json-schema@7.0.15': 140 | resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} 141 | 142 | '@types/node@22.15.17': 143 | resolution: {integrity: sha512-wIX2aSZL5FE+MR0JlvF87BNVrtFWf6AE6rxSE9X7OwnVvoyCQjpzSRJ+M87se/4QCkCiebQAqrJ0y6fwIyi7nw==} 144 | 145 | acorn-jsx@5.3.2: 146 | resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} 147 | peerDependencies: 148 | acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 149 | 150 | acorn@8.14.0: 151 | resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} 152 | engines: {node: '>=0.4.0'} 153 | hasBin: true 154 | 155 | ajv@6.12.6: 156 | resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} 157 | 158 | ansi-regex@2.1.1: 159 | resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==} 160 | engines: {node: '>=0.10.0'} 161 | 162 | ansi-regex@3.0.1: 163 | resolution: {integrity: sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==} 164 | engines: {node: '>=4'} 165 | 166 | ansi-styles@3.2.1: 167 | resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} 168 | engines: {node: '>=4'} 169 | 170 | ansi-styles@4.3.0: 171 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 172 | engines: {node: '>=8'} 173 | 174 | argparse@2.0.1: 175 | resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} 176 | 177 | balanced-match@1.0.2: 178 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 179 | 180 | brace-expansion@1.1.11: 181 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 182 | 183 | callsites@3.1.0: 184 | resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} 185 | engines: {node: '>=6'} 186 | 187 | camelcase@4.1.0: 188 | resolution: {integrity: sha512-FxAv7HpHrXbh3aPo4o2qxHay2lkLY3x5Mw3KeE4KQE8ysVfziWeRZDwcjauvwBSGEC/nXUPzZy8zeh4HokqOnw==} 189 | engines: {node: '>=4'} 190 | 191 | chalk@2.1.0: 192 | resolution: {integrity: sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==} 193 | engines: {node: '>=4'} 194 | 195 | chalk@4.1.2: 196 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 197 | engines: {node: '>=10'} 198 | 199 | cliui@3.2.0: 200 | resolution: {integrity: sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==} 201 | 202 | code-point-at@1.1.0: 203 | resolution: {integrity: sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==} 204 | engines: {node: '>=0.10.0'} 205 | 206 | color-convert@1.9.3: 207 | resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} 208 | 209 | color-convert@2.0.1: 210 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 211 | engines: {node: '>=7.0.0'} 212 | 213 | color-name@1.1.3: 214 | resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} 215 | 216 | color-name@1.1.4: 217 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 218 | 219 | concat-map@0.0.1: 220 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} 221 | 222 | core-js@2.5.3: 223 | resolution: {integrity: sha512-1fhTiNuC8YWzCl567b1K2mQqRyHvQtRlEuNY31t837BFNd57oMvElJTsM5IrIooczeG/KvssBbJi2ZZASwyMIQ==} 224 | deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js. 225 | 226 | cross-spawn@5.1.0: 227 | resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==} 228 | 229 | cross-spawn@7.0.6: 230 | resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} 231 | engines: {node: '>= 8'} 232 | 233 | cssesc@3.0.0: 234 | resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} 235 | engines: {node: '>=4'} 236 | hasBin: true 237 | 238 | debug@4.4.0: 239 | resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} 240 | engines: {node: '>=6.0'} 241 | peerDependencies: 242 | supports-color: '*' 243 | peerDependenciesMeta: 244 | supports-color: 245 | optional: true 246 | 247 | decamelize@1.2.0: 248 | resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} 249 | engines: {node: '>=0.10.0'} 250 | 251 | deep-is@0.1.4: 252 | resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} 253 | 254 | escape-string-regexp@1.0.5: 255 | resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} 256 | engines: {node: '>=0.8.0'} 257 | 258 | escape-string-regexp@4.0.0: 259 | resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} 260 | engines: {node: '>=10'} 261 | 262 | eslint-config-prettier@10.1.5: 263 | resolution: {integrity: sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==} 264 | hasBin: true 265 | peerDependencies: 266 | eslint: '>=7.0.0' 267 | 268 | eslint-scope@8.3.0: 269 | resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==} 270 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 271 | 272 | eslint-visitor-keys@3.4.3: 273 | resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} 274 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 275 | 276 | eslint-visitor-keys@4.2.0: 277 | resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} 278 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 279 | 280 | eslint@9.25.1: 281 | resolution: {integrity: sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==} 282 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 283 | hasBin: true 284 | peerDependencies: 285 | jiti: '*' 286 | peerDependenciesMeta: 287 | jiti: 288 | optional: true 289 | 290 | espree@10.3.0: 291 | resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} 292 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 293 | 294 | esquery@1.6.0: 295 | resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} 296 | engines: {node: '>=0.10'} 297 | 298 | esrecurse@4.3.0: 299 | resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} 300 | engines: {node: '>=4.0'} 301 | 302 | estraverse@5.3.0: 303 | resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} 304 | engines: {node: '>=4.0'} 305 | 306 | esutils@2.0.3: 307 | resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} 308 | engines: {node: '>=0.10.0'} 309 | 310 | execa@0.7.0: 311 | resolution: {integrity: sha512-RztN09XglpYI7aBBrJCPW95jEH7YF1UEPOoX9yDhUTPdp7mK+CQvnLTuD10BNXZ3byLTu2uehZ8EcKT/4CGiFw==} 312 | engines: {node: '>=4'} 313 | 314 | exit@0.1.2: 315 | resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} 316 | engines: {node: '>= 0.8.0'} 317 | 318 | fast-deep-equal@3.1.3: 319 | resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 320 | 321 | fast-json-stable-stringify@2.1.0: 322 | resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} 323 | 324 | fast-levenshtein@2.0.6: 325 | resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} 326 | 327 | file-entry-cache@8.0.0: 328 | resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} 329 | engines: {node: '>=16.0.0'} 330 | 331 | find-up@2.1.0: 332 | resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} 333 | engines: {node: '>=4'} 334 | 335 | find-up@5.0.0: 336 | resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} 337 | engines: {node: '>=10'} 338 | 339 | flat-cache@4.0.1: 340 | resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} 341 | engines: {node: '>=16'} 342 | 343 | flatted@3.3.2: 344 | resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==} 345 | 346 | get-caller-file@1.0.3: 347 | resolution: {integrity: sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==} 348 | 349 | get-stream@3.0.0: 350 | resolution: {integrity: sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==} 351 | engines: {node: '>=4'} 352 | 353 | glob-parent@6.0.2: 354 | resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} 355 | engines: {node: '>=10.13.0'} 356 | 357 | globals@14.0.0: 358 | resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} 359 | engines: {node: '>=18'} 360 | 361 | has-flag@2.0.0: 362 | resolution: {integrity: sha512-P+1n3MnwjR/Epg9BBo1KT8qbye2g2Ou4sFumihwt6I4tsUX7jnLcX4BTOSKg/B1ZrIYMN9FcEnG4x5a7NB8Eng==} 363 | engines: {node: '>=0.10.0'} 364 | 365 | has-flag@4.0.0: 366 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 367 | engines: {node: '>=8'} 368 | 369 | ignore@5.3.2: 370 | resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} 371 | engines: {node: '>= 4'} 372 | 373 | import-fresh@3.3.0: 374 | resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} 375 | engines: {node: '>=6'} 376 | 377 | imurmurhash@0.1.4: 378 | resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} 379 | engines: {node: '>=0.8.19'} 380 | 381 | invert-kv@1.0.0: 382 | resolution: {integrity: sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==} 383 | engines: {node: '>=0.10.0'} 384 | 385 | is-extglob@2.1.1: 386 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 387 | engines: {node: '>=0.10.0'} 388 | 389 | is-fullwidth-code-point@1.0.0: 390 | resolution: {integrity: sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==} 391 | engines: {node: '>=0.10.0'} 392 | 393 | is-fullwidth-code-point@2.0.0: 394 | resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==} 395 | engines: {node: '>=4'} 396 | 397 | is-glob@4.0.3: 398 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 399 | engines: {node: '>=0.10.0'} 400 | 401 | is-stream@1.1.0: 402 | resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==} 403 | engines: {node: '>=0.10.0'} 404 | 405 | isexe@2.0.0: 406 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 407 | 408 | jison-gho@0.6.1-216: 409 | resolution: {integrity: sha512-sBwC7puJgM1ECfBX0dbHpNo0v0+Dz4vXPoEpxUSVH8m3BiNRYLYtJeACC5vm8ACK5F4bQWrcHNacrqcVrYnWqA==} 410 | engines: {node: '>=4.0'} 411 | hasBin: true 412 | 413 | js-yaml@4.1.0: 414 | resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} 415 | hasBin: true 416 | 417 | json-buffer@3.0.1: 418 | resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} 419 | 420 | json-schema-traverse@0.4.1: 421 | resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} 422 | 423 | json-stable-stringify-without-jsonify@1.0.1: 424 | resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} 425 | 426 | keyv@4.5.4: 427 | resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} 428 | 429 | lcid@1.0.0: 430 | resolution: {integrity: sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==} 431 | engines: {node: '>=0.10.0'} 432 | 433 | levn@0.4.1: 434 | resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} 435 | engines: {node: '>= 0.8.0'} 436 | 437 | locate-path@2.0.0: 438 | resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} 439 | engines: {node: '>=4'} 440 | 441 | locate-path@6.0.0: 442 | resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} 443 | engines: {node: '>=10'} 444 | 445 | lodash.merge@4.6.2: 446 | resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} 447 | 448 | lru-cache@4.1.5: 449 | resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} 450 | 451 | mem@1.1.0: 452 | resolution: {integrity: sha512-nOBDrc/wgpkd3X/JOhMqYR+/eLqlfLP4oQfoBA6QExIxEl+GU01oyEkwWyueyO8110pUKijtiHGhEmYoOn88oQ==} 453 | engines: {node: '>=4'} 454 | 455 | mimic-fn@1.2.0: 456 | resolution: {integrity: sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==} 457 | engines: {node: '>=4'} 458 | 459 | minimatch@3.1.2: 460 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} 461 | 462 | ms@2.1.3: 463 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 464 | 465 | nanoid@3.3.8: 466 | resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} 467 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 468 | hasBin: true 469 | 470 | natural-compare@1.4.0: 471 | resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} 472 | 473 | npm-run-path@2.0.2: 474 | resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==} 475 | engines: {node: '>=4'} 476 | 477 | number-is-nan@1.0.1: 478 | resolution: {integrity: sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==} 479 | engines: {node: '>=0.10.0'} 480 | 481 | optionator@0.9.4: 482 | resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} 483 | engines: {node: '>= 0.8.0'} 484 | 485 | os-locale@2.1.0: 486 | resolution: {integrity: sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==} 487 | engines: {node: '>=4'} 488 | 489 | p-finally@1.0.0: 490 | resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} 491 | engines: {node: '>=4'} 492 | 493 | p-limit@1.3.0: 494 | resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} 495 | engines: {node: '>=4'} 496 | 497 | p-limit@3.1.0: 498 | resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} 499 | engines: {node: '>=10'} 500 | 501 | p-locate@2.0.0: 502 | resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} 503 | engines: {node: '>=4'} 504 | 505 | p-locate@5.0.0: 506 | resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} 507 | engines: {node: '>=10'} 508 | 509 | p-try@1.0.0: 510 | resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==} 511 | engines: {node: '>=4'} 512 | 513 | parent-module@1.0.1: 514 | resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} 515 | engines: {node: '>=6'} 516 | 517 | path-exists@3.0.0: 518 | resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} 519 | engines: {node: '>=4'} 520 | 521 | path-exists@4.0.0: 522 | resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} 523 | engines: {node: '>=8'} 524 | 525 | path-key@2.0.1: 526 | resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==} 527 | engines: {node: '>=4'} 528 | 529 | path-key@3.1.1: 530 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 531 | engines: {node: '>=8'} 532 | 533 | picocolors@1.1.1: 534 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 535 | 536 | postcss-selector-parser@7.1.0: 537 | resolution: {integrity: sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==} 538 | engines: {node: '>=4'} 539 | 540 | postcss-value-parser@4.2.0: 541 | resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} 542 | 543 | postcss@8.5.3: 544 | resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} 545 | engines: {node: ^10 || ^12 || >=14} 546 | 547 | prelude-ls@1.2.1: 548 | resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} 549 | engines: {node: '>= 0.8.0'} 550 | 551 | prettier@3.5.3: 552 | resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==} 553 | engines: {node: '>=14'} 554 | hasBin: true 555 | 556 | private@0.1.7: 557 | resolution: {integrity: sha512-YmFOCNzqPkis1UxGH6pr8zN4DLoFNcJPvrD+ZLr7aThaOpaHufbWy+UhCa6PM0XszYIWkcJZUg40eKHR5+w+8w==} 558 | engines: {node: '>= 0.6'} 559 | 560 | private@0.1.8: 561 | resolution: {integrity: sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==} 562 | engines: {node: '>= 0.6'} 563 | 564 | pseudomap@1.0.2: 565 | resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} 566 | 567 | punycode@2.3.1: 568 | resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} 569 | engines: {node: '>=6'} 570 | 571 | require-directory@2.1.1: 572 | resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} 573 | engines: {node: '>=0.10.0'} 574 | 575 | require-main-filename@1.0.1: 576 | resolution: {integrity: sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==} 577 | 578 | resolve-from@4.0.0: 579 | resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} 580 | engines: {node: '>=4'} 581 | 582 | set-blocking@2.0.0: 583 | resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} 584 | 585 | shebang-command@1.2.0: 586 | resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} 587 | engines: {node: '>=0.10.0'} 588 | 589 | shebang-command@2.0.0: 590 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 591 | engines: {node: '>=8'} 592 | 593 | shebang-regex@1.0.0: 594 | resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} 595 | engines: {node: '>=0.10.0'} 596 | 597 | shebang-regex@3.0.0: 598 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 599 | engines: {node: '>=8'} 600 | 601 | signal-exit@3.0.7: 602 | resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} 603 | 604 | source-map-js@1.2.1: 605 | resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 606 | engines: {node: '>=0.10.0'} 607 | 608 | source-map@0.6.1: 609 | resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} 610 | engines: {node: '>=0.10.0'} 611 | 612 | string-width@1.0.2: 613 | resolution: {integrity: sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==} 614 | engines: {node: '>=0.10.0'} 615 | 616 | string-width@2.1.1: 617 | resolution: {integrity: sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==} 618 | engines: {node: '>=4'} 619 | 620 | strip-ansi@3.0.1: 621 | resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} 622 | engines: {node: '>=0.10.0'} 623 | 624 | strip-ansi@4.0.0: 625 | resolution: {integrity: sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==} 626 | engines: {node: '>=4'} 627 | 628 | strip-eof@1.0.0: 629 | resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==} 630 | engines: {node: '>=0.10.0'} 631 | 632 | strip-json-comments@3.1.1: 633 | resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} 634 | engines: {node: '>=8'} 635 | 636 | supports-color@4.5.0: 637 | resolution: {integrity: sha512-ycQR/UbvI9xIlEdQT1TQqwoXtEldExbCEAJgRo5YXlmSKjv6ThHnP9/vwGa1gr19Gfw+LkFd7KqYMhzrRC5JYw==} 638 | engines: {node: '>=4'} 639 | 640 | supports-color@7.2.0: 641 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 642 | engines: {node: '>=8'} 643 | 644 | type-check@0.4.0: 645 | resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} 646 | engines: {node: '>= 0.8.0'} 647 | 648 | typescript@5.8.3: 649 | resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} 650 | engines: {node: '>=14.17'} 651 | hasBin: true 652 | 653 | undici-types@6.21.0: 654 | resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} 655 | 656 | uri-js@4.4.1: 657 | resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} 658 | 659 | util-deprecate@1.0.2: 660 | resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} 661 | 662 | which-module@2.0.1: 663 | resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} 664 | 665 | which@1.3.1: 666 | resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} 667 | hasBin: true 668 | 669 | which@2.0.2: 670 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 671 | engines: {node: '>= 8'} 672 | hasBin: true 673 | 674 | word-wrap@1.2.5: 675 | resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} 676 | engines: {node: '>=0.10.0'} 677 | 678 | wrap-ansi@2.1.0: 679 | resolution: {integrity: sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==} 680 | engines: {node: '>=0.10.0'} 681 | 682 | y18n@3.2.2: 683 | resolution: {integrity: sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==} 684 | 685 | yallist@2.1.2: 686 | resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==} 687 | 688 | yargs-parser@8.1.0: 689 | resolution: {integrity: sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==} 690 | 691 | yargs@10.0.3: 692 | resolution: {integrity: sha512-DqBpQ8NAUX4GyPP/ijDGHsJya4tYqLQrjPr95HNsr1YwL3+daCfvBwg7+gIC6IdJhR2kATh3hb61vjzMWEtjdw==} 693 | 694 | yocto-queue@0.1.0: 695 | resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} 696 | engines: {node: '>=10'} 697 | 698 | snapshots: 699 | 700 | '@eslint-community/eslint-utils@4.4.1(eslint@9.25.1)': 701 | dependencies: 702 | eslint: 9.25.1 703 | eslint-visitor-keys: 3.4.3 704 | 705 | '@eslint-community/regexpp@4.12.1': {} 706 | 707 | '@eslint/config-array@0.20.0': 708 | dependencies: 709 | '@eslint/object-schema': 2.1.6 710 | debug: 4.4.0 711 | minimatch: 3.1.2 712 | transitivePeerDependencies: 713 | - supports-color 714 | 715 | '@eslint/config-helpers@0.2.2': {} 716 | 717 | '@eslint/core@0.13.0': 718 | dependencies: 719 | '@types/json-schema': 7.0.15 720 | 721 | '@eslint/eslintrc@3.3.1': 722 | dependencies: 723 | ajv: 6.12.6 724 | debug: 4.4.0 725 | espree: 10.3.0 726 | globals: 14.0.0 727 | ignore: 5.3.2 728 | import-fresh: 3.3.0 729 | js-yaml: 4.1.0 730 | minimatch: 3.1.2 731 | strip-json-comments: 3.1.1 732 | transitivePeerDependencies: 733 | - supports-color 734 | 735 | '@eslint/js@9.25.1': {} 736 | 737 | '@eslint/object-schema@2.1.6': {} 738 | 739 | '@eslint/plugin-kit@0.2.8': 740 | dependencies: 741 | '@eslint/core': 0.13.0 742 | levn: 0.4.1 743 | 744 | '@gerhobbelt/ast-types@0.10.1-15': {} 745 | 746 | '@gerhobbelt/ast-types@0.9.13-4': {} 747 | 748 | '@gerhobbelt/ast-util@0.6.1-4': 749 | dependencies: 750 | '@gerhobbelt/ast-types': 0.9.13-4 751 | private: 0.1.7 752 | 753 | '@gerhobbelt/esprima@4.0.1-15': {} 754 | 755 | '@gerhobbelt/json5@0.5.1-21': 756 | dependencies: 757 | yargs: 10.0.3 758 | 759 | '@gerhobbelt/linewrap@0.2.2-3': {} 760 | 761 | '@gerhobbelt/nomnom@1.8.4-24': 762 | dependencies: 763 | '@gerhobbelt/linewrap': 0.2.2-3 764 | chalk: 2.1.0 765 | exit: 0.1.2 766 | 767 | '@gerhobbelt/recast@0.13.0-24': 768 | dependencies: 769 | '@gerhobbelt/ast-types': 0.10.1-15 770 | '@gerhobbelt/esprima': 4.0.1-15 771 | core-js: 2.5.3 772 | private: 0.1.8 773 | source-map: 0.6.1 774 | 775 | '@gerhobbelt/xregexp@3.2.0-22': {} 776 | 777 | '@humanfs/core@0.19.1': {} 778 | 779 | '@humanfs/node@0.16.6': 780 | dependencies: 781 | '@humanfs/core': 0.19.1 782 | '@humanwhocodes/retry': 0.3.1 783 | 784 | '@humanwhocodes/module-importer@1.0.1': {} 785 | 786 | '@humanwhocodes/retry@0.3.1': {} 787 | 788 | '@humanwhocodes/retry@0.4.3': {} 789 | 790 | '@types/estree@1.0.6': {} 791 | 792 | '@types/json-schema@7.0.15': {} 793 | 794 | '@types/node@22.15.17': 795 | dependencies: 796 | undici-types: 6.21.0 797 | 798 | acorn-jsx@5.3.2(acorn@8.14.0): 799 | dependencies: 800 | acorn: 8.14.0 801 | 802 | acorn@8.14.0: {} 803 | 804 | ajv@6.12.6: 805 | dependencies: 806 | fast-deep-equal: 3.1.3 807 | fast-json-stable-stringify: 2.1.0 808 | json-schema-traverse: 0.4.1 809 | uri-js: 4.4.1 810 | 811 | ansi-regex@2.1.1: {} 812 | 813 | ansi-regex@3.0.1: {} 814 | 815 | ansi-styles@3.2.1: 816 | dependencies: 817 | color-convert: 1.9.3 818 | 819 | ansi-styles@4.3.0: 820 | dependencies: 821 | color-convert: 2.0.1 822 | 823 | argparse@2.0.1: {} 824 | 825 | balanced-match@1.0.2: {} 826 | 827 | brace-expansion@1.1.11: 828 | dependencies: 829 | balanced-match: 1.0.2 830 | concat-map: 0.0.1 831 | 832 | callsites@3.1.0: {} 833 | 834 | camelcase@4.1.0: {} 835 | 836 | chalk@2.1.0: 837 | dependencies: 838 | ansi-styles: 3.2.1 839 | escape-string-regexp: 1.0.5 840 | supports-color: 4.5.0 841 | 842 | chalk@4.1.2: 843 | dependencies: 844 | ansi-styles: 4.3.0 845 | supports-color: 7.2.0 846 | 847 | cliui@3.2.0: 848 | dependencies: 849 | string-width: 1.0.2 850 | strip-ansi: 3.0.1 851 | wrap-ansi: 2.1.0 852 | 853 | code-point-at@1.1.0: {} 854 | 855 | color-convert@1.9.3: 856 | dependencies: 857 | color-name: 1.1.3 858 | 859 | color-convert@2.0.1: 860 | dependencies: 861 | color-name: 1.1.4 862 | 863 | color-name@1.1.3: {} 864 | 865 | color-name@1.1.4: {} 866 | 867 | concat-map@0.0.1: {} 868 | 869 | core-js@2.5.3: {} 870 | 871 | cross-spawn@5.1.0: 872 | dependencies: 873 | lru-cache: 4.1.5 874 | shebang-command: 1.2.0 875 | which: 1.3.1 876 | 877 | cross-spawn@7.0.6: 878 | dependencies: 879 | path-key: 3.1.1 880 | shebang-command: 2.0.0 881 | which: 2.0.2 882 | 883 | cssesc@3.0.0: {} 884 | 885 | debug@4.4.0: 886 | dependencies: 887 | ms: 2.1.3 888 | 889 | decamelize@1.2.0: {} 890 | 891 | deep-is@0.1.4: {} 892 | 893 | escape-string-regexp@1.0.5: {} 894 | 895 | escape-string-regexp@4.0.0: {} 896 | 897 | eslint-config-prettier@10.1.5(eslint@9.25.1): 898 | dependencies: 899 | eslint: 9.25.1 900 | 901 | eslint-scope@8.3.0: 902 | dependencies: 903 | esrecurse: 4.3.0 904 | estraverse: 5.3.0 905 | 906 | eslint-visitor-keys@3.4.3: {} 907 | 908 | eslint-visitor-keys@4.2.0: {} 909 | 910 | eslint@9.25.1: 911 | dependencies: 912 | '@eslint-community/eslint-utils': 4.4.1(eslint@9.25.1) 913 | '@eslint-community/regexpp': 4.12.1 914 | '@eslint/config-array': 0.20.0 915 | '@eslint/config-helpers': 0.2.2 916 | '@eslint/core': 0.13.0 917 | '@eslint/eslintrc': 3.3.1 918 | '@eslint/js': 9.25.1 919 | '@eslint/plugin-kit': 0.2.8 920 | '@humanfs/node': 0.16.6 921 | '@humanwhocodes/module-importer': 1.0.1 922 | '@humanwhocodes/retry': 0.4.3 923 | '@types/estree': 1.0.6 924 | '@types/json-schema': 7.0.15 925 | ajv: 6.12.6 926 | chalk: 4.1.2 927 | cross-spawn: 7.0.6 928 | debug: 4.4.0 929 | escape-string-regexp: 4.0.0 930 | eslint-scope: 8.3.0 931 | eslint-visitor-keys: 4.2.0 932 | espree: 10.3.0 933 | esquery: 1.6.0 934 | esutils: 2.0.3 935 | fast-deep-equal: 3.1.3 936 | file-entry-cache: 8.0.0 937 | find-up: 5.0.0 938 | glob-parent: 6.0.2 939 | ignore: 5.3.2 940 | imurmurhash: 0.1.4 941 | is-glob: 4.0.3 942 | json-stable-stringify-without-jsonify: 1.0.1 943 | lodash.merge: 4.6.2 944 | minimatch: 3.1.2 945 | natural-compare: 1.4.0 946 | optionator: 0.9.4 947 | transitivePeerDependencies: 948 | - supports-color 949 | 950 | espree@10.3.0: 951 | dependencies: 952 | acorn: 8.14.0 953 | acorn-jsx: 5.3.2(acorn@8.14.0) 954 | eslint-visitor-keys: 4.2.0 955 | 956 | esquery@1.6.0: 957 | dependencies: 958 | estraverse: 5.3.0 959 | 960 | esrecurse@4.3.0: 961 | dependencies: 962 | estraverse: 5.3.0 963 | 964 | estraverse@5.3.0: {} 965 | 966 | esutils@2.0.3: {} 967 | 968 | execa@0.7.0: 969 | dependencies: 970 | cross-spawn: 5.1.0 971 | get-stream: 3.0.0 972 | is-stream: 1.1.0 973 | npm-run-path: 2.0.2 974 | p-finally: 1.0.0 975 | signal-exit: 3.0.7 976 | strip-eof: 1.0.0 977 | 978 | exit@0.1.2: {} 979 | 980 | fast-deep-equal@3.1.3: {} 981 | 982 | fast-json-stable-stringify@2.1.0: {} 983 | 984 | fast-levenshtein@2.0.6: {} 985 | 986 | file-entry-cache@8.0.0: 987 | dependencies: 988 | flat-cache: 4.0.1 989 | 990 | find-up@2.1.0: 991 | dependencies: 992 | locate-path: 2.0.0 993 | 994 | find-up@5.0.0: 995 | dependencies: 996 | locate-path: 6.0.0 997 | path-exists: 4.0.0 998 | 999 | flat-cache@4.0.1: 1000 | dependencies: 1001 | flatted: 3.3.2 1002 | keyv: 4.5.4 1003 | 1004 | flatted@3.3.2: {} 1005 | 1006 | get-caller-file@1.0.3: {} 1007 | 1008 | get-stream@3.0.0: {} 1009 | 1010 | glob-parent@6.0.2: 1011 | dependencies: 1012 | is-glob: 4.0.3 1013 | 1014 | globals@14.0.0: {} 1015 | 1016 | has-flag@2.0.0: {} 1017 | 1018 | has-flag@4.0.0: {} 1019 | 1020 | ignore@5.3.2: {} 1021 | 1022 | import-fresh@3.3.0: 1023 | dependencies: 1024 | parent-module: 1.0.1 1025 | resolve-from: 4.0.0 1026 | 1027 | imurmurhash@0.1.4: {} 1028 | 1029 | invert-kv@1.0.0: {} 1030 | 1031 | is-extglob@2.1.1: {} 1032 | 1033 | is-fullwidth-code-point@1.0.0: 1034 | dependencies: 1035 | number-is-nan: 1.0.1 1036 | 1037 | is-fullwidth-code-point@2.0.0: {} 1038 | 1039 | is-glob@4.0.3: 1040 | dependencies: 1041 | is-extglob: 2.1.1 1042 | 1043 | is-stream@1.1.0: {} 1044 | 1045 | isexe@2.0.0: {} 1046 | 1047 | jison-gho@0.6.1-216: 1048 | dependencies: 1049 | '@gerhobbelt/ast-util': 0.6.1-4 1050 | '@gerhobbelt/json5': 0.5.1-21 1051 | '@gerhobbelt/nomnom': 1.8.4-24 1052 | '@gerhobbelt/recast': 0.13.0-24 1053 | '@gerhobbelt/xregexp': 3.2.0-22 1054 | 1055 | js-yaml@4.1.0: 1056 | dependencies: 1057 | argparse: 2.0.1 1058 | 1059 | json-buffer@3.0.1: {} 1060 | 1061 | json-schema-traverse@0.4.1: {} 1062 | 1063 | json-stable-stringify-without-jsonify@1.0.1: {} 1064 | 1065 | keyv@4.5.4: 1066 | dependencies: 1067 | json-buffer: 3.0.1 1068 | 1069 | lcid@1.0.0: 1070 | dependencies: 1071 | invert-kv: 1.0.0 1072 | 1073 | levn@0.4.1: 1074 | dependencies: 1075 | prelude-ls: 1.2.1 1076 | type-check: 0.4.0 1077 | 1078 | locate-path@2.0.0: 1079 | dependencies: 1080 | p-locate: 2.0.0 1081 | path-exists: 3.0.0 1082 | 1083 | locate-path@6.0.0: 1084 | dependencies: 1085 | p-locate: 5.0.0 1086 | 1087 | lodash.merge@4.6.2: {} 1088 | 1089 | lru-cache@4.1.5: 1090 | dependencies: 1091 | pseudomap: 1.0.2 1092 | yallist: 2.1.2 1093 | 1094 | mem@1.1.0: 1095 | dependencies: 1096 | mimic-fn: 1.2.0 1097 | 1098 | mimic-fn@1.2.0: {} 1099 | 1100 | minimatch@3.1.2: 1101 | dependencies: 1102 | brace-expansion: 1.1.11 1103 | 1104 | ms@2.1.3: {} 1105 | 1106 | nanoid@3.3.8: {} 1107 | 1108 | natural-compare@1.4.0: {} 1109 | 1110 | npm-run-path@2.0.2: 1111 | dependencies: 1112 | path-key: 2.0.1 1113 | 1114 | number-is-nan@1.0.1: {} 1115 | 1116 | optionator@0.9.4: 1117 | dependencies: 1118 | deep-is: 0.1.4 1119 | fast-levenshtein: 2.0.6 1120 | levn: 0.4.1 1121 | prelude-ls: 1.2.1 1122 | type-check: 0.4.0 1123 | word-wrap: 1.2.5 1124 | 1125 | os-locale@2.1.0: 1126 | dependencies: 1127 | execa: 0.7.0 1128 | lcid: 1.0.0 1129 | mem: 1.1.0 1130 | 1131 | p-finally@1.0.0: {} 1132 | 1133 | p-limit@1.3.0: 1134 | dependencies: 1135 | p-try: 1.0.0 1136 | 1137 | p-limit@3.1.0: 1138 | dependencies: 1139 | yocto-queue: 0.1.0 1140 | 1141 | p-locate@2.0.0: 1142 | dependencies: 1143 | p-limit: 1.3.0 1144 | 1145 | p-locate@5.0.0: 1146 | dependencies: 1147 | p-limit: 3.1.0 1148 | 1149 | p-try@1.0.0: {} 1150 | 1151 | parent-module@1.0.1: 1152 | dependencies: 1153 | callsites: 3.1.0 1154 | 1155 | path-exists@3.0.0: {} 1156 | 1157 | path-exists@4.0.0: {} 1158 | 1159 | path-key@2.0.1: {} 1160 | 1161 | path-key@3.1.1: {} 1162 | 1163 | picocolors@1.1.1: {} 1164 | 1165 | postcss-selector-parser@7.1.0: 1166 | dependencies: 1167 | cssesc: 3.0.0 1168 | util-deprecate: 1.0.2 1169 | 1170 | postcss-value-parser@4.2.0: {} 1171 | 1172 | postcss@8.5.3: 1173 | dependencies: 1174 | nanoid: 3.3.8 1175 | picocolors: 1.1.1 1176 | source-map-js: 1.2.1 1177 | 1178 | prelude-ls@1.2.1: {} 1179 | 1180 | prettier@3.5.3: {} 1181 | 1182 | private@0.1.7: {} 1183 | 1184 | private@0.1.8: {} 1185 | 1186 | pseudomap@1.0.2: {} 1187 | 1188 | punycode@2.3.1: {} 1189 | 1190 | require-directory@2.1.1: {} 1191 | 1192 | require-main-filename@1.0.1: {} 1193 | 1194 | resolve-from@4.0.0: {} 1195 | 1196 | set-blocking@2.0.0: {} 1197 | 1198 | shebang-command@1.2.0: 1199 | dependencies: 1200 | shebang-regex: 1.0.0 1201 | 1202 | shebang-command@2.0.0: 1203 | dependencies: 1204 | shebang-regex: 3.0.0 1205 | 1206 | shebang-regex@1.0.0: {} 1207 | 1208 | shebang-regex@3.0.0: {} 1209 | 1210 | signal-exit@3.0.7: {} 1211 | 1212 | source-map-js@1.2.1: {} 1213 | 1214 | source-map@0.6.1: {} 1215 | 1216 | string-width@1.0.2: 1217 | dependencies: 1218 | code-point-at: 1.1.0 1219 | is-fullwidth-code-point: 1.0.0 1220 | strip-ansi: 3.0.1 1221 | 1222 | string-width@2.1.1: 1223 | dependencies: 1224 | is-fullwidth-code-point: 2.0.0 1225 | strip-ansi: 4.0.0 1226 | 1227 | strip-ansi@3.0.1: 1228 | dependencies: 1229 | ansi-regex: 2.1.1 1230 | 1231 | strip-ansi@4.0.0: 1232 | dependencies: 1233 | ansi-regex: 3.0.1 1234 | 1235 | strip-eof@1.0.0: {} 1236 | 1237 | strip-json-comments@3.1.1: {} 1238 | 1239 | supports-color@4.5.0: 1240 | dependencies: 1241 | has-flag: 2.0.0 1242 | 1243 | supports-color@7.2.0: 1244 | dependencies: 1245 | has-flag: 4.0.0 1246 | 1247 | type-check@0.4.0: 1248 | dependencies: 1249 | prelude-ls: 1.2.1 1250 | 1251 | typescript@5.8.3: {} 1252 | 1253 | undici-types@6.21.0: {} 1254 | 1255 | uri-js@4.4.1: 1256 | dependencies: 1257 | punycode: 2.3.1 1258 | 1259 | util-deprecate@1.0.2: {} 1260 | 1261 | which-module@2.0.1: {} 1262 | 1263 | which@1.3.1: 1264 | dependencies: 1265 | isexe: 2.0.0 1266 | 1267 | which@2.0.2: 1268 | dependencies: 1269 | isexe: 2.0.0 1270 | 1271 | word-wrap@1.2.5: {} 1272 | 1273 | wrap-ansi@2.1.0: 1274 | dependencies: 1275 | string-width: 1.0.2 1276 | strip-ansi: 3.0.1 1277 | 1278 | y18n@3.2.2: {} 1279 | 1280 | yallist@2.1.2: {} 1281 | 1282 | yargs-parser@8.1.0: 1283 | dependencies: 1284 | camelcase: 4.1.0 1285 | 1286 | yargs@10.0.3: 1287 | dependencies: 1288 | cliui: 3.2.0 1289 | decamelize: 1.2.0 1290 | find-up: 2.1.0 1291 | get-caller-file: 1.0.3 1292 | os-locale: 2.1.0 1293 | require-directory: 2.1.1 1294 | require-main-filename: 1.0.1 1295 | set-blocking: 2.0.0 1296 | string-width: 2.1.1 1297 | which-module: 2.0.1 1298 | y18n: 3.2.2 1299 | yargs-parser: 8.1.0 1300 | 1301 | yocto-queue@0.1.0: {} 1302 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const transform = require('./lib/transform.js'); 3 | 4 | /** 5 | * @typedef {{precision?: number | false, 6 | * preserve?: boolean, 7 | * warnWhenCannotResolve?: boolean, 8 | * mediaQueries?: boolean, 9 | * selectors?: boolean}} PostCssCalcOptions 10 | */ 11 | /** 12 | * @type {import('postcss').PluginCreator} 13 | * @param {PostCssCalcOptions} opts 14 | * @return {import('postcss').Plugin} 15 | */ 16 | function pluginCreator(opts) { 17 | const options = Object.assign( 18 | { 19 | precision: 5, 20 | preserve: false, 21 | warnWhenCannotResolve: false, 22 | mediaQueries: false, 23 | selectors: false, 24 | }, 25 | opts 26 | ); 27 | 28 | return { 29 | postcssPlugin: 'postcss-calc', 30 | OnceExit(css, { result }) { 31 | css.walk((node) => { 32 | const { type } = node; 33 | if (type === 'decl') { 34 | transform(node, 'value', options, result); 35 | } 36 | 37 | if (type === 'atrule' && options.mediaQueries) { 38 | transform(node, 'params', options, result); 39 | } 40 | 41 | if (type === 'rule' && options.selectors) { 42 | transform(node, 'selector', options, result); 43 | } 44 | }); 45 | }, 46 | }; 47 | } 48 | 49 | pluginCreator.postcss = true; 50 | 51 | module.exports = pluginCreator; 52 | -------------------------------------------------------------------------------- /src/lib/convertUnit.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * @type {{[key:string]: {[key:string]: number}}} 4 | */ 5 | const conversions = { 6 | // Absolute length units 7 | px: { 8 | px: 1, 9 | cm: 96 / 2.54, 10 | mm: 96 / 25.4, 11 | q: 96 / 101.6, 12 | in: 96, 13 | pt: 96 / 72, 14 | pc: 16, 15 | }, 16 | cm: { 17 | px: 2.54 / 96, 18 | cm: 1, 19 | mm: 0.1, 20 | q: 0.025, 21 | in: 2.54, 22 | pt: 2.54 / 72, 23 | pc: 2.54 / 6, 24 | }, 25 | mm: { 26 | px: 25.4 / 96, 27 | cm: 10, 28 | mm: 1, 29 | q: 0.25, 30 | in: 25.4, 31 | pt: 25.4 / 72, 32 | pc: 25.4 / 6, 33 | }, 34 | q: { 35 | px: 101.6 / 96, 36 | cm: 40, 37 | mm: 4, 38 | q: 1, 39 | in: 101.6, 40 | pt: 101.6 / 72, 41 | pc: 101.6 / 6, 42 | }, 43 | in: { 44 | px: 1 / 96, 45 | cm: 1 / 2.54, 46 | mm: 1 / 25.4, 47 | q: 1 / 101.6, 48 | in: 1, 49 | pt: 1 / 72, 50 | pc: 1 / 6, 51 | }, 52 | pt: { 53 | px: 0.75, 54 | cm: 72 / 2.54, 55 | mm: 72 / 25.4, 56 | q: 72 / 101.6, 57 | in: 72, 58 | pt: 1, 59 | pc: 12, 60 | }, 61 | pc: { 62 | px: 0.0625, 63 | cm: 6 / 2.54, 64 | mm: 6 / 25.4, 65 | q: 6 / 101.6, 66 | in: 6, 67 | pt: 6 / 72, 68 | pc: 1, 69 | }, 70 | // Angle units 71 | deg: { 72 | deg: 1, 73 | grad: 0.9, 74 | rad: 180 / Math.PI, 75 | turn: 360, 76 | }, 77 | grad: { 78 | deg: 400 / 360, 79 | grad: 1, 80 | rad: 200 / Math.PI, 81 | turn: 400, 82 | }, 83 | rad: { 84 | deg: Math.PI / 180, 85 | grad: Math.PI / 200, 86 | rad: 1, 87 | turn: Math.PI * 2, 88 | }, 89 | turn: { 90 | deg: 1 / 360, 91 | grad: 0.0025, 92 | rad: 0.5 / Math.PI, 93 | turn: 1, 94 | }, 95 | // Duration units 96 | s: { 97 | s: 1, 98 | ms: 0.001, 99 | }, 100 | ms: { 101 | s: 1000, 102 | ms: 1, 103 | }, 104 | // Frequency units 105 | hz: { 106 | hz: 1, 107 | khz: 1000, 108 | }, 109 | khz: { 110 | hz: 0.001, 111 | khz: 1, 112 | }, 113 | // Resolution units 114 | dpi: { 115 | dpi: 1, 116 | dpcm: 1 / 2.54, 117 | dppx: 1 / 96, 118 | }, 119 | dpcm: { 120 | dpi: 2.54, 121 | dpcm: 1, 122 | dppx: 2.54 / 96, 123 | }, 124 | dppx: { 125 | dpi: 96, 126 | dpcm: 96 / 2.54, 127 | dppx: 1, 128 | }, 129 | }; 130 | /** 131 | * @param {number} value 132 | * @param {string} sourceUnit 133 | * @param {string} targetUnit 134 | * @param {number|false} precision 135 | */ 136 | function convertUnit(value, sourceUnit, targetUnit, precision) { 137 | const sourceUnitNormalized = sourceUnit.toLowerCase(); 138 | const targetUnitNormalized = targetUnit.toLowerCase(); 139 | 140 | if (!conversions[targetUnitNormalized]) { 141 | throw new Error('Cannot convert to ' + targetUnit); 142 | } 143 | 144 | if (!conversions[targetUnitNormalized][sourceUnitNormalized]) { 145 | throw new Error('Cannot convert from ' + sourceUnit + ' to ' + targetUnit); 146 | } 147 | 148 | const converted = 149 | conversions[targetUnitNormalized][sourceUnitNormalized] * value; 150 | 151 | if (precision !== false) { 152 | precision = Math.pow(10, Math.ceil(precision) || 5); 153 | 154 | return Math.round(converted * precision) / precision; 155 | } 156 | 157 | return converted; 158 | } 159 | 160 | module.exports = convertUnit; 161 | -------------------------------------------------------------------------------- /src/lib/reducer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const convertUnit = require('./convertUnit.js'); 3 | 4 | /** 5 | * @param {import('../parser').CalcNode} node 6 | * @return {node is import('../parser').ValueExpression} 7 | */ 8 | function isValueType(node) { 9 | switch (node.type) { 10 | case 'LengthValue': 11 | case 'AngleValue': 12 | case 'TimeValue': 13 | case 'FrequencyValue': 14 | case 'ResolutionValue': 15 | case 'EmValue': 16 | case 'ExValue': 17 | case 'ChValue': 18 | case 'RemValue': 19 | case 'VhValue': 20 | case 'SvhValue': 21 | case 'LvhValue': 22 | case 'DvhValue': 23 | case 'VwValue': 24 | case 'SvwValue': 25 | case 'LvwValue': 26 | case 'DvwValue': 27 | case 'VminValue': 28 | case 'SvminValue': 29 | case 'LvminValue': 30 | case 'DvminValue': 31 | case 'VmaxValue': 32 | case 'SvmaxValue': 33 | case 'LvmaxValue': 34 | case 'DvmaxValue': 35 | case 'VbValue': 36 | case 'SvbValue': 37 | case 'LvbValue': 38 | case 'DvbValue': 39 | case 'ViValue': 40 | case 'SviValue': 41 | case 'LviValue': 42 | case 'DviValue': 43 | case 'CqwValue': 44 | case 'CqhValue': 45 | case 'CqiValue': 46 | case 'CqbValue': 47 | case 'CqminValue': 48 | case 'CqmaxValue': 49 | case 'PercentageValue': 50 | case 'LhValue': 51 | case 'RlhValue': 52 | case 'Number': 53 | return true; 54 | } 55 | return false; 56 | } 57 | 58 | /** @param {'-'|'+'} operator */ 59 | function flip(operator) { 60 | return operator === '+' ? '-' : '+'; 61 | } 62 | 63 | /** 64 | * @param {string} operator 65 | * @returns {operator is '+'|'-'} 66 | */ 67 | function isAddSubOperator(operator) { 68 | return operator === '+' || operator === '-'; 69 | } 70 | 71 | /** 72 | * @typedef {{preOperator: '+'|'-', node: import('../parser').CalcNode}} Collectible 73 | */ 74 | 75 | /** 76 | * @param {'+'|'-'} preOperator 77 | * @param {import('../parser').CalcNode} node 78 | * @param {Collectible[]} collected 79 | * @param {number} precision 80 | */ 81 | function collectAddSubItems(preOperator, node, collected, precision) { 82 | if (!isAddSubOperator(preOperator)) { 83 | throw new Error(`invalid operator ${preOperator}`); 84 | } 85 | if (isValueType(node)) { 86 | const itemIndex = collected.findIndex((x) => x.node.type === node.type); 87 | if (itemIndex >= 0) { 88 | if (node.value === 0) { 89 | return; 90 | } 91 | // can cast because of the criterion used to find itemIndex 92 | const otherValueNode = /** @type import('../parser').ValueExpression*/ ( 93 | collected[itemIndex].node 94 | ); 95 | const { left: reducedNode, right: current } = convertNodesUnits( 96 | otherValueNode, 97 | node, 98 | precision 99 | ); 100 | 101 | if (collected[itemIndex].preOperator === '-') { 102 | collected[itemIndex].preOperator = '+'; 103 | reducedNode.value *= -1; 104 | } 105 | if (preOperator === '+') { 106 | reducedNode.value += current.value; 107 | } else { 108 | reducedNode.value -= current.value; 109 | } 110 | // make sure reducedNode.value >= 0 111 | if (reducedNode.value >= 0) { 112 | collected[itemIndex] = { node: reducedNode, preOperator: '+' }; 113 | } else { 114 | reducedNode.value *= -1; 115 | collected[itemIndex] = { node: reducedNode, preOperator: '-' }; 116 | } 117 | } else { 118 | // make sure node.value >= 0 119 | if (node.value >= 0) { 120 | collected.push({ node, preOperator }); 121 | } else { 122 | node.value *= -1; 123 | collected.push({ node, preOperator: flip(preOperator) }); 124 | } 125 | } 126 | } else if (node.type === 'MathExpression') { 127 | if (isAddSubOperator(node.operator)) { 128 | collectAddSubItems(preOperator, node.left, collected, precision); 129 | const collectRightOperator = 130 | preOperator === '-' ? flip(node.operator) : node.operator; 131 | collectAddSubItems( 132 | collectRightOperator, 133 | node.right, 134 | collected, 135 | precision 136 | ); 137 | } else { 138 | // * or / 139 | const reducedNode = reduce(node, precision); 140 | // prevent infinite recursive call 141 | if ( 142 | reducedNode.type !== 'MathExpression' || 143 | isAddSubOperator(reducedNode.operator) 144 | ) { 145 | collectAddSubItems(preOperator, reducedNode, collected, precision); 146 | } else { 147 | collected.push({ node: reducedNode, preOperator }); 148 | } 149 | } 150 | } else if (node.type === 'ParenthesizedExpression') { 151 | collectAddSubItems(preOperator, node.content, collected, precision); 152 | } else { 153 | collected.push({ node, preOperator }); 154 | } 155 | } 156 | 157 | /** 158 | * @param {import('../parser').CalcNode} node 159 | * @param {number} precision 160 | */ 161 | function reduceAddSubExpression(node, precision) { 162 | /** @type Collectible[] */ 163 | const collected = []; 164 | collectAddSubItems('+', node, collected, precision); 165 | 166 | const withoutZeroItem = collected.filter( 167 | (item) => !(isValueType(item.node) && item.node.value === 0) 168 | ); 169 | const firstNonZeroItem = withoutZeroItem[0]; // could be undefined 170 | 171 | // prevent producing "calc(-var(--a))" or "calc()" 172 | // which is invalid css 173 | if ( 174 | !firstNonZeroItem || 175 | (firstNonZeroItem.preOperator === '-' && 176 | !isValueType(firstNonZeroItem.node)) 177 | ) { 178 | const firstZeroItem = collected.find( 179 | (item) => isValueType(item.node) && item.node.value === 0 180 | ); 181 | if (firstZeroItem) { 182 | withoutZeroItem.unshift(firstZeroItem); 183 | } 184 | } 185 | 186 | // make sure the preOperator of the first item is + 187 | if ( 188 | withoutZeroItem[0].preOperator === '-' && 189 | isValueType(withoutZeroItem[0].node) 190 | ) { 191 | withoutZeroItem[0].node.value *= -1; 192 | withoutZeroItem[0].preOperator = '+'; 193 | } 194 | 195 | let root = withoutZeroItem[0].node; 196 | for (let i = 1; i < withoutZeroItem.length; i++) { 197 | root = { 198 | type: 'MathExpression', 199 | operator: withoutZeroItem[i].preOperator, 200 | left: root, 201 | right: withoutZeroItem[i].node, 202 | }; 203 | } 204 | 205 | return root; 206 | } 207 | /** 208 | * @param {import('../parser').MathExpression} node 209 | */ 210 | function reduceDivisionExpression(node) { 211 | if (!isValueType(node.right)) { 212 | return node; 213 | } 214 | 215 | if (node.right.type !== 'Number') { 216 | throw new Error(`Cannot divide by "${node.right.unit}", number expected`); 217 | } 218 | 219 | return applyNumberDivision(node.left, node.right.value); 220 | } 221 | 222 | /** 223 | * apply (expr) / number 224 | * 225 | * @param {import('../parser').CalcNode} node 226 | * @param {number} divisor 227 | * @return {import('../parser').CalcNode} 228 | */ 229 | function applyNumberDivision(node, divisor) { 230 | if (divisor === 0) { 231 | throw new Error('Cannot divide by zero'); 232 | } 233 | if (isValueType(node)) { 234 | node.value /= divisor; 235 | return node; 236 | } 237 | if (node.type === 'MathExpression' && isAddSubOperator(node.operator)) { 238 | // turn (a + b) / num into a/num + b/num 239 | // is good for further reduction 240 | // checkout the test case 241 | // "should reduce division before reducing additions" 242 | return { 243 | type: 'MathExpression', 244 | operator: node.operator, 245 | left: applyNumberDivision(node.left, divisor), 246 | right: applyNumberDivision(node.right, divisor), 247 | }; 248 | } 249 | // it is impossible to reduce it into a single value 250 | // .e.g the node contains css variable 251 | // so we just preserve the division and let browser do it 252 | return { 253 | type: 'MathExpression', 254 | operator: '/', 255 | left: node, 256 | right: { 257 | type: 'Number', 258 | value: divisor, 259 | }, 260 | }; 261 | } 262 | /** 263 | * @param {import('../parser').MathExpression} node 264 | */ 265 | function reduceMultiplicationExpression(node) { 266 | // (expr) * number 267 | if (node.right.type === 'Number') { 268 | return applyNumberMultiplication(node.left, node.right.value); 269 | } 270 | // number * (expr) 271 | if (node.left.type === 'Number') { 272 | return applyNumberMultiplication(node.right, node.left.value); 273 | } 274 | return node; 275 | } 276 | 277 | /** 278 | * apply (expr) * number 279 | * @param {number} multiplier 280 | * @param {import('../parser').CalcNode} node 281 | * @return {import('../parser').CalcNode} 282 | */ 283 | function applyNumberMultiplication(node, multiplier) { 284 | if (isValueType(node)) { 285 | node.value *= multiplier; 286 | return node; 287 | } 288 | if (node.type === 'MathExpression' && isAddSubOperator(node.operator)) { 289 | // turn (a + b) * num into a*num + b*num 290 | // is good for further reduction 291 | // checkout the test case 292 | // "should reduce multiplication before reducing additions" 293 | return { 294 | type: 'MathExpression', 295 | operator: node.operator, 296 | left: applyNumberMultiplication(node.left, multiplier), 297 | right: applyNumberMultiplication(node.right, multiplier), 298 | }; 299 | } 300 | // it is impossible to reduce it into a single value 301 | // .e.g the node contains css variable 302 | // so we just preserve the division and let browser do it 303 | return { 304 | type: 'MathExpression', 305 | operator: '*', 306 | left: node, 307 | right: { 308 | type: 'Number', 309 | value: multiplier, 310 | }, 311 | }; 312 | } 313 | 314 | /** 315 | * @param {import('../parser').ValueExpression} left 316 | * @param {import('../parser').ValueExpression} right 317 | * @param {number} precision 318 | */ 319 | function convertNodesUnits(left, right, precision) { 320 | switch (left.type) { 321 | case 'LengthValue': 322 | case 'AngleValue': 323 | case 'TimeValue': 324 | case 'FrequencyValue': 325 | case 'ResolutionValue': 326 | if (right.type === left.type && right.unit && left.unit) { 327 | const converted = convertUnit( 328 | right.value, 329 | right.unit, 330 | left.unit, 331 | precision 332 | ); 333 | 334 | right = { 335 | type: left.type, 336 | value: converted, 337 | unit: left.unit, 338 | }; 339 | } 340 | 341 | return { left, right }; 342 | default: 343 | return { left, right }; 344 | } 345 | } 346 | 347 | /** 348 | * @param {import('../parser').ParenthesizedExpression} node 349 | */ 350 | function includesNoCssProperties(node) { 351 | return ( 352 | node.content.type !== 'Function' && 353 | (node.content.type !== 'MathExpression' || 354 | (node.content.right.type !== 'Function' && 355 | node.content.left.type !== 'Function')) 356 | ); 357 | } 358 | /** 359 | * @param {import('../parser').CalcNode} node 360 | * @param {number} precision 361 | * @return {import('../parser').CalcNode} 362 | */ 363 | function reduce(node, precision) { 364 | if ( 365 | node.type === 'MathExpression' && 366 | (node.left.type === 'CalcKeyword' || node.right.type === 'CalcKeyword') 367 | ) { 368 | return node; 369 | } 370 | if (node.type === 'MathExpression') { 371 | if (isAddSubOperator(node.operator)) { 372 | // reduceAddSubExpression will call reduce recursively 373 | return reduceAddSubExpression(node, precision); 374 | } 375 | node.left = reduce(node.left, precision); 376 | node.right = reduce(node.right, precision); 377 | switch (node.operator) { 378 | case '/': 379 | return reduceDivisionExpression(node); 380 | case '*': 381 | return reduceMultiplicationExpression(node); 382 | } 383 | 384 | return node; 385 | } 386 | 387 | if (node.type === 'ParenthesizedExpression') { 388 | if (includesNoCssProperties(node)) { 389 | return reduce(node.content, precision); 390 | } 391 | } 392 | 393 | return node; 394 | } 395 | 396 | module.exports = reduce; 397 | -------------------------------------------------------------------------------- /src/lib/stringifier.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const order = { 3 | '*': 0, 4 | '/': 0, 5 | '+': 1, 6 | '-': 1, 7 | }; 8 | 9 | /** 10 | * @param {number} value 11 | * @param {number | false} prec 12 | */ 13 | function round(value, prec) { 14 | if (prec !== false) { 15 | const precision = Math.pow(10, prec); 16 | return Math.round(value * precision) / precision; 17 | } 18 | return value; 19 | } 20 | 21 | /** 22 | * @param {number | false} prec 23 | * @param {import('../parser').CalcNode} node 24 | * 25 | * @return {string} 26 | */ 27 | function stringify(node, prec) { 28 | switch (node.type) { 29 | case 'MathExpression': { 30 | const { left, right, operator: op } = node; 31 | let str = ''; 32 | if (left.type === 'MathExpression' && order[op] < order[left.operator]) { 33 | str += `(${stringify(left, prec)})`; 34 | } else if (left.type === 'CalcKeyword') { 35 | str += left.value; 36 | } else { 37 | str += stringify(left, prec); 38 | } 39 | 40 | str += order[op] ? ` ${node.operator} ` : node.operator; 41 | 42 | if ( 43 | right.type === 'MathExpression' && 44 | order[op] < order[right.operator] 45 | ) { 46 | str += `(${stringify(right, prec)})`; 47 | } else if (right.type === 'CalcKeyword') { 48 | str += right.value; 49 | } else { 50 | str += stringify(right, prec); 51 | } 52 | 53 | return str; 54 | } 55 | case 'Number': 56 | return round(node.value, prec).toString(); 57 | case 'Function': 58 | return node.value.toString(); 59 | case 'ParenthesizedExpression': 60 | return `(${stringify(node.content, prec)})`; 61 | case 'CalcKeyword': 62 | return node.value; 63 | default: 64 | return round(node.value, prec) + node.unit; 65 | } 66 | } 67 | 68 | /** 69 | * @param {string} calc 70 | * @param {import('../parser').CalcNode} node 71 | * @param {string} originalValue 72 | * @param {{precision: number | false, warnWhenCannotResolve: boolean}} options 73 | * @param {import("postcss").Result} result 74 | * @param {import("postcss").ChildNode} item 75 | * 76 | * @returns {string} 77 | */ 78 | module.exports = function (calc, node, originalValue, options, result, item) { 79 | let str = stringify(node, options.precision); 80 | 81 | const shouldPrintCalc = 82 | node.type === 'MathExpression' || 83 | node.type === 'Function' || 84 | node.type === 'ParenthesizedExpression' || 85 | node.type === 'CalcKeyword'; 86 | 87 | if (shouldPrintCalc) { 88 | // if calc expression couldn't be resolved to a single value, re-wrap it as 89 | // a calc() 90 | if (node.type === 'ParenthesizedExpression') { 91 | str = `${calc}${str}`; 92 | } else { 93 | str = `${calc}(${str})`; 94 | } 95 | 96 | // if the warnWhenCannotResolve option is on, inform the user that the calc 97 | // expression could not be resolved to a single value 98 | if (options.warnWhenCannotResolve) { 99 | result.warn('Could not reduce expression: ' + originalValue, { 100 | plugin: 'postcss-calc', 101 | node: item, 102 | }); 103 | } 104 | } 105 | return str; 106 | }; 107 | -------------------------------------------------------------------------------- /src/lib/transform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const selectorParser = require('postcss-selector-parser'); 3 | const valueParser = require('postcss-value-parser'); 4 | 5 | const { parser } = require('../parser.js'); 6 | 7 | const reducer = require('./reducer.js'); 8 | const stringifier = require('./stringifier.js'); 9 | 10 | const MATCH_CALC = /((?:-(moz|webkit)-)?calc(?!-))/i; 11 | 12 | /** 13 | * @param {string} value 14 | * @param {{precision: number, warnWhenCannotResolve: boolean}} options 15 | * @param {import("postcss").Result} result 16 | * @param {import("postcss").ChildNode} item 17 | */ 18 | function transformValue(value, options, result, item) { 19 | return valueParser(value) 20 | .walk((node) => { 21 | // skip anything which isn't a calc() function 22 | if (node.type !== 'function' || !MATCH_CALC.test(node.value)) { 23 | return; 24 | } 25 | 26 | // stringify calc expression and produce an AST 27 | const contents = valueParser.stringify(node.nodes); 28 | const ast = parser.parse(contents); 29 | 30 | // reduce AST to its simplest form, that is, either to a single value 31 | // or a simplified calc expression 32 | const reducedAst = reducer(ast, options.precision); 33 | 34 | // stringify AST and write it back 35 | /** @type {valueParser.Node} */ (node).type = 'word'; 36 | node.value = stringifier( 37 | node.value, 38 | reducedAst, 39 | value, 40 | options, 41 | result, 42 | item 43 | ); 44 | 45 | return false; 46 | }) 47 | .toString(); 48 | } 49 | /** 50 | * @param {import("postcss-selector-parser").Selectors} value 51 | * @param {{precision: number, warnWhenCannotResolve: boolean}} options 52 | * @param {import("postcss").Result} result 53 | * @param {import("postcss").ChildNode} item 54 | */ 55 | function transformSelector(value, options, result, item) { 56 | return selectorParser((selectors) => { 57 | selectors.walk((node) => { 58 | // attribute value 59 | // e.g. the "calc(3*3)" part of "div[data-size="calc(3*3)"]" 60 | if (node.type === 'attribute' && node.value) { 61 | node.setValue(transformValue(node.value, options, result, item)); 62 | } 63 | 64 | // tag value 65 | // e.g. the "calc(3*3)" part of "div:nth-child(2n + calc(3*3))" 66 | if (node.type === 'tag') { 67 | node.value = transformValue(node.value, options, result, item); 68 | } 69 | 70 | return; 71 | }); 72 | }).processSync(value); 73 | } 74 | 75 | /** 76 | * @param {any} node 77 | * @param {{precision: number, preserve: boolean, warnWhenCannotResolve: boolean}} options 78 | * @param {'value'|'params'|'selector'} property 79 | * @param {import("postcss").Result} result 80 | */ 81 | module.exports = (node, property, options, result) => { 82 | let value = node[property]; 83 | 84 | try { 85 | value = 86 | property === 'selector' 87 | ? transformSelector(node[property], options, result, node) 88 | : transformValue(node[property], options, result, node); 89 | } catch (error) { 90 | if (error instanceof Error) { 91 | result.warn(error.message, { node }); 92 | } else { 93 | result.warn('Error', { node }); 94 | } 95 | return; 96 | } 97 | 98 | // if the preserve option is enabled and the value has changed, write the 99 | // transformed value into a cloned node which is inserted before the current 100 | // node, preserving the original value. Otherwise, overwrite the original 101 | // value. 102 | if (options.preserve && node[property] !== value) { 103 | const clone = node.clone(); 104 | clone[property] = value; 105 | node.parent.insertBefore(node, clone); 106 | } else { 107 | node[property] = value; 108 | } 109 | }; 110 | -------------------------------------------------------------------------------- /src/parser.d.ts: -------------------------------------------------------------------------------- 1 | export interface MathExpression { 2 | type: 'MathExpression'; 3 | right: CalcNode; 4 | left: CalcNode; 5 | operator: '*' | '+' | '-' | '/'; 6 | } 7 | 8 | export interface ParenthesizedExpression { 9 | type: 'ParenthesizedExpression'; 10 | content: CalcNode; 11 | } 12 | 13 | export interface DimensionExpression { 14 | type: 15 | | 'LengthValue' 16 | | 'AngleValue' 17 | | 'TimeValue' 18 | | 'FrequencyValue' 19 | | 'PercentageValue' 20 | | 'ResolutionValue' 21 | | 'EmValue' 22 | | 'ExValue' 23 | | 'ChValue' 24 | | 'RemValue' 25 | | 'VhValue' 26 | | 'SvhValue' 27 | | 'LvhValue' 28 | | 'DvhValue' 29 | | 'VwValue' 30 | | 'SvwValue' 31 | | 'LvwValue' 32 | | 'DvwValue' 33 | | 'VminValue' 34 | | 'SvminValue' 35 | | 'LvminValue' 36 | | 'DvminValue' 37 | | 'VmaxValue' 38 | | 'SvmaxValue' 39 | | 'LvmaxValue' 40 | | 'DvmaxValue' 41 | | 'VbValue' 42 | | 'SvbValue' 43 | | 'LvbValue' 44 | | 'DvbValue' 45 | | 'ViValue' 46 | | 'SviValue' 47 | | 'LviValue' 48 | | 'DviValue' 49 | | 'CqwValue' 50 | | 'CqhValue' 51 | | 'CqbValue' 52 | | 'CqiValue' 53 | | 'CqminValue' 54 | | 'CqmaxValue' 55 | | 'LhValue' 56 | | 'RlhValue'; 57 | value: number; 58 | unit: string; 59 | } 60 | 61 | export interface NumberExpression { 62 | type: 'Number'; 63 | value: number; 64 | } 65 | 66 | export interface FunctionExpression { 67 | type: 'Function'; 68 | value: string; 69 | } 70 | 71 | export interface CalcKeywordExpression { 72 | type: 'CalcKeyword'; 73 | value: string; 74 | } 75 | 76 | export type ValueExpression = DimensionExpression | NumberExpression; 77 | 78 | export type CalcNode = 79 | | MathExpression 80 | | ValueExpression 81 | | FunctionExpression 82 | | ParenthesizedExpression 83 | | CalcKeywordExpression; 84 | 85 | export interface Parser { 86 | parse: (arg: string) => CalcNode; 87 | } 88 | 89 | export const parser: Parser; 90 | -------------------------------------------------------------------------------- /test/convertUnit.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const { test } = require('node:test'); 3 | const assert = require('node:assert/strict'); 4 | 5 | const convertUnit = require('../src/lib/convertUnit.js'); 6 | 7 | test('valid conversions', () => { 8 | const conversions = [ 9 | // source value, source unit, expected value, target unit 10 | [10, 'px', 10, 'px'], 11 | [10, 'px', 0.26458, 'cm'], 12 | [10, 'px', 2.64583, 'mm'], 13 | [10, 'px', 10.58333, 'q'], 14 | [10, 'px', 0.10417, 'in'], 15 | [10, 'px', 7.5, 'pt'], 16 | [10, 'px', 0.625, 'pc'], 17 | [10, 'cm', 377.95276, 'px'], 18 | [10, 'cm', 10, 'cm'], 19 | [10, 'cm', 100, 'mm'], 20 | [10, 'cm', 400, 'q'], 21 | [10, 'cm', 3.93701, 'in'], 22 | [10, 'cm', 283.46457, 'pt'], 23 | [10, 'cm', 23.62205, 'pc'], 24 | [10, 'mm', 37.79528, 'px'], 25 | [10, 'mm', 1, 'cm'], 26 | [10, 'mm', 10, 'mm'], 27 | [10, 'mm', 40, 'q'], 28 | [10, 'mm', 0.3937, 'in'], 29 | [10, 'mm', 28.34646, 'pt'], 30 | [10, 'mm', 2.3622, 'pc'], 31 | [10, 'q', 9.44882, 'px'], 32 | [10, 'q', 0.25, 'cm'], 33 | [10, 'q', 2.5, 'mm'], 34 | [10, 'q', 0.09843, 'in'], 35 | [10, 'q', 7.08661, 'pt'], 36 | [10, 'q', 0.59055, 'pc'], 37 | [10, 'in', 960, 'px'], 38 | [10, 'in', 25.4, 'cm'], 39 | [10, 'in', 254, 'mm'], 40 | [10, 'in', 1016, 'q'], 41 | [10, 'in', 10, 'in'], 42 | [10, 'in', 720, 'pt'], 43 | [10, 'in', 60, 'pc'], 44 | [10, 'pt', 13.33333, 'px'], 45 | [10, 'pt', 0.35278, 'cm'], 46 | [10, 'pt', 3.52778, 'mm'], 47 | [10, 'pt', 14.11111, 'q'], 48 | [10, 'pt', 0.13889, 'in'], 49 | [10, 'pt', 10, 'pt'], 50 | [10, 'pt', 0.83333, 'pc'], 51 | [10, 'pc', 160, 'px'], 52 | [10, 'pc', 4.23333, 'cm'], 53 | [10, 'pc', 42.33333, 'mm'], 54 | [10, 'pc', 169.33333, 'q'], 55 | [10, 'pc', 1.66667, 'in'], 56 | [10, 'pc', 120, 'pt'], 57 | [10, 'pc', 10, 'pc'], 58 | [10, 'deg', 10, 'deg'], 59 | [10, 'deg', 11.11111, 'grad'], 60 | [10, 'deg', 0.17453, 'rad'], 61 | [10, 'deg', 0.02778, 'turn'], 62 | [10, 'grad', 9, 'deg'], 63 | [10, 'grad', 10, 'grad'], 64 | [10, 'grad', 0.15708, 'rad'], 65 | [10, 'grad', 0.025, 'turn'], 66 | [10, 'rad', 572.9578, 'deg'], 67 | [10, 'rad', 636.61977, 'grad'], 68 | [10, 'rad', 10, 'rad'], 69 | [10, 'rad', 1.59155, 'turn'], 70 | [10, 'turn', 3600, 'deg'], 71 | [10, 'turn', 4000, 'grad'], 72 | [10, 'turn', 62.83185, 'rad'], 73 | [10, 'turn', 10, 'turn'], 74 | [10, 's', 10, 's'], 75 | [10, 's', 10000, 'ms'], 76 | [10, 'ms', 0.01, 's'], 77 | [10, 'ms', 10, 'ms'], 78 | [10, 'Hz', 10, 'Hz'], 79 | [10, 'Hz', 0.01, 'kHz'], 80 | [10, 'kHz', 10000, 'Hz'], 81 | [10, 'kHz', 10, 'kHz'], 82 | [10, 'dpi', 10, 'dpi'], 83 | [10, 'dpi', 25.4, 'dpcm'], 84 | [10, 'dpi', 960, 'dppx'], 85 | [10, 'dpcm', 3.93701, 'dpi'], 86 | [10, 'dpcm', 10, 'dpcm'], 87 | [10, 'dpcm', 377.95276, 'dppx'], 88 | [10, 'dppx', 0.10417, 'dpi'], 89 | [10, 'dppx', 0.26458, 'dpcm'], 90 | [10, 'dppx', 10, 'dppx'], 91 | ]; 92 | 93 | conversions.forEach(function (e) { 94 | const value = e[0]; 95 | const unit = e[1]; 96 | const expected = e[2]; 97 | const targetUnit = e[3]; 98 | 99 | assert.strictEqual( 100 | convertUnit(value, unit, targetUnit), 101 | expected, 102 | unit + ' -> ' + targetUnit 103 | ); 104 | }); 105 | }); 106 | 107 | test('invalid conversions', () => { 108 | const invalid_units = { 109 | px: [ 110 | 'deg', 111 | 'grad', 112 | 'rad', 113 | 'turn', 114 | 's', 115 | 'ms', 116 | 'Hz', 117 | 'kHz', 118 | 'dpi', 119 | 'dpcm', 120 | 'dppx', 121 | ], 122 | cm: [ 123 | 'deg', 124 | 'grad', 125 | 'rad', 126 | 'turn', 127 | 's', 128 | 'ms', 129 | 'Hz', 130 | 'kHz', 131 | 'dpi', 132 | 'dpcm', 133 | 'dppx', 134 | ], 135 | mm: [ 136 | 'deg', 137 | 'grad', 138 | 'rad', 139 | 'turn', 140 | 's', 141 | 'ms', 142 | 'Hz', 143 | 'kHz', 144 | 'dpi', 145 | 'dpcm', 146 | 'dppx', 147 | ], 148 | q: [ 149 | 'deg', 150 | 'grad', 151 | 'rad', 152 | 'turn', 153 | 's', 154 | 'ms', 155 | 'Hz', 156 | 'kHz', 157 | 'dpi', 158 | 'dpcm', 159 | 'dppx', 160 | ], 161 | in: [ 162 | 'deg', 163 | 'grad', 164 | 'rad', 165 | 'turn', 166 | 's', 167 | 'ms', 168 | 'Hz', 169 | 'kHz', 170 | 'dpi', 171 | 'dpcm', 172 | 'dppx', 173 | ], 174 | pt: [ 175 | 'deg', 176 | 'grad', 177 | 'rad', 178 | 'turn', 179 | 's', 180 | 'ms', 181 | 'Hz', 182 | 'kHz', 183 | 'dpi', 184 | 'dpcm', 185 | 'dppx', 186 | ], 187 | pc: [ 188 | 'deg', 189 | 'grad', 190 | 'rad', 191 | 'turn', 192 | 's', 193 | 'ms', 194 | 'Hz', 195 | 'kHz', 196 | 'dpi', 197 | 'dpcm', 198 | 'dppx', 199 | ], 200 | deg: [ 201 | 'px', 202 | 'cm', 203 | 'mm', 204 | 'in', 205 | 'pt', 206 | 'pc', 207 | 's', 208 | 'ms', 209 | 'Hz', 210 | 'kHz', 211 | 'dpi', 212 | 'dpcm', 213 | 'dppx', 214 | ], 215 | grad: [ 216 | 'px', 217 | 'cm', 218 | 'mm', 219 | 'in', 220 | 'pt', 221 | 'pc', 222 | 's', 223 | 'ms', 224 | 'Hz', 225 | 'kHz', 226 | 'dpi', 227 | 'dpcm', 228 | 'dppx', 229 | ], 230 | rad: [ 231 | 'px', 232 | 'cm', 233 | 'mm', 234 | 'in', 235 | 'pt', 236 | 'pc', 237 | 's', 238 | 'ms', 239 | 'Hz', 240 | 'kHz', 241 | 'dpi', 242 | 'dpcm', 243 | 'dppx', 244 | ], 245 | turn: [ 246 | 'px', 247 | 'cm', 248 | 'mm', 249 | 'in', 250 | 'pt', 251 | 'pc', 252 | 's', 253 | 'ms', 254 | 'Hz', 255 | 'kHz', 256 | 'dpi', 257 | 'dpcm', 258 | 'dppx', 259 | ], 260 | s: [ 261 | 'px', 262 | 'cm', 263 | 'mm', 264 | 'in', 265 | 'pt', 266 | 'pc', 267 | 'deg', 268 | 'grad', 269 | 'rad', 270 | 'turn', 271 | 'Hz', 272 | 'kHz', 273 | 'dpi', 274 | 'dpcm', 275 | 'dppx', 276 | ], 277 | ms: [ 278 | 'px', 279 | 'cm', 280 | 'mm', 281 | 'in', 282 | 'pt', 283 | 'pc', 284 | 'deg', 285 | 'grad', 286 | 'rad', 287 | 'turn', 288 | 'Hz', 289 | 'kHz', 290 | 'dpi', 291 | 'dpcm', 292 | 'dppx', 293 | ], 294 | Hz: [ 295 | 'px', 296 | 'cm', 297 | 'mm', 298 | 'in', 299 | 'pt', 300 | 'pc', 301 | 'deg', 302 | 'grad', 303 | 'rad', 304 | 'turn', 305 | 's', 306 | 'ms', 307 | 'dpi', 308 | 'dpcm', 309 | 'dppx', 310 | ], 311 | kHz: [ 312 | 'px', 313 | 'cm', 314 | 'mm', 315 | 'in', 316 | 'pt', 317 | 'pc', 318 | 'deg', 319 | 'grad', 320 | 'rad', 321 | 'turn', 322 | 's', 323 | 'ms', 324 | 'dpi', 325 | 'dpcm', 326 | 'dppx', 327 | ], 328 | dpi: [ 329 | 'px', 330 | 'cm', 331 | 'mm', 332 | 'in', 333 | 'pt', 334 | 'pc', 335 | 'deg', 336 | 'grad', 337 | 'rad', 338 | 'turn', 339 | 's', 340 | 'ms', 341 | 'Hz', 342 | 'kHz', 343 | ], 344 | dpcm: [ 345 | 'px', 346 | 'cm', 347 | 'mm', 348 | 'in', 349 | 'pt', 350 | 'pc', 351 | 'deg', 352 | 'grad', 353 | 'rad', 354 | 'turn', 355 | 's', 356 | 'ms', 357 | 'Hz', 358 | 'kHz', 359 | ], 360 | dppx: [ 361 | 'px', 362 | 'cm', 363 | 'mm', 364 | 'in', 365 | 'pt', 366 | 'pc', 367 | 'deg', 368 | 'grad', 369 | 'rad', 370 | 'turn', 371 | 's', 372 | 'ms', 373 | 'Hz', 374 | 'kHz', 375 | ], 376 | }; 377 | 378 | for (const unit in invalid_units) { 379 | invalid_units[unit].forEach((targetUnit) => { 380 | let failed = false; 381 | 382 | try { 383 | convertUnit(10, unit, targetUnit); 384 | } catch { 385 | failed = true; 386 | } 387 | 388 | assert.ok(failed, unit + ' -> ' + targetUnit); 389 | }); 390 | } 391 | }); 392 | 393 | test('precision', () => { 394 | const precision = 10; 395 | const conversions = [ 396 | // source value, source unit, expected value, target unit 397 | [10, 'px', 0.2645833333, 'cm'], 398 | [10, 'px', 2.6458333333, 'mm'], 399 | [10, 'px', 0.1041666667, 'in'], 400 | [10, 'cm', 377.9527559055, 'px'], 401 | ]; 402 | 403 | conversions.forEach((e) => { 404 | const value = e[0]; 405 | const unit = e[1]; 406 | const expected = e[2]; 407 | const targetUnit = e[3]; 408 | 409 | assert.strictEqual( 410 | convertUnit(value, unit, targetUnit, precision), 411 | expected, 412 | unit + ' -> ' + targetUnit 413 | ); 414 | }); 415 | }); 416 | 417 | test('falsey precision', () => { 418 | assert.strictEqual(convertUnit(10, 'px', 'cm', false), 0.26458333333333334); 419 | }); 420 | 421 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const { test } = require('node:test'); 3 | const assert = require('node:assert/strict'); 4 | const postcss = require('postcss'); 5 | 6 | const reduceCalc = require('../src/index.js'); 7 | 8 | const postcssOpts = { from: undefined }; 9 | 10 | function testValue(fixture, expected, opts = {}) { 11 | fixture = `foo{bar:${fixture}}`; 12 | expected = `foo{bar:${expected}}`; 13 | 14 | return async () => { 15 | const result = await postcss(reduceCalc(opts)).process( 16 | fixture, 17 | postcssOpts 18 | ); 19 | assert.strictEqual(result.css, expected); 20 | }; 21 | } 22 | 23 | function testCss(fixture, expected, opts = {}) { 24 | return async () => { 25 | const result = await postcss(reduceCalc(opts)).process( 26 | fixture, 27 | postcssOpts 28 | ); 29 | assert.strictEqual(result.css, expected); 30 | }; 31 | } 32 | 33 | function testCssDoesNotThrow(fixture, expected, opts = {}) { 34 | return async () => { 35 | const result = await postcss(reduceCalc(opts)).process( 36 | fixture, 37 | postcssOpts 38 | ); 39 | assert.strictEqual(result.css, expected); 40 | const warnings = result.warnings(); 41 | assert.strictEqual(warnings.length, 0); 42 | }; 43 | } 44 | 45 | function testThrows(fixture, expected, warning, opts = {}) { 46 | fixture = `foo{bar:${fixture}}`; 47 | expected = `foo{bar:${expected}}`; 48 | 49 | return async () => { 50 | const result = await postcss(reduceCalc(opts)).process( 51 | fixture, 52 | postcssOpts 53 | ); 54 | const warnings = result.warnings(); 55 | assert.strictEqual(result.css, expected); 56 | assert.strictEqual(warnings[0].text, warning); 57 | }; 58 | } 59 | 60 | test('should reduce simple calc (1)', testValue('calc(1px + 1px)', '2px')); 61 | 62 | test( 63 | 'should reduce simple calc (2)', 64 | testValue('calc(1px + 1px);baz:calc(2px+3px)', '2px;baz:5px') 65 | ); 66 | 67 | test('should reduce simple calc (3)', testValue('calc(1rem * 1.5)', '1.5rem')); 68 | 69 | test('should reduce simple calc (4)', testValue('calc(3em - 1em)', '2em')); 70 | 71 | test('should reduce simple calc (5', testValue('calc(2ex / 2)', '1ex')); 72 | 73 | test( 74 | 'should reduce simple calc (6)', 75 | testValue('calc(50px - (20px - 30px))', '60px') 76 | ); 77 | 78 | test( 79 | 'should reduce simple calc (7)', 80 | testValue('calc(100px - (100px - 100%))', '100%') 81 | ); 82 | 83 | test( 84 | 'should reduce simple calc (8)', 85 | testValue('calc(100px + (100px - 100%))', 'calc(200px - 100%)') 86 | ); 87 | 88 | test( 89 | 'should reduce additions and subtractions (1)', 90 | testValue('calc(100% - 10px + 20px)', 'calc(100% + 10px)') 91 | ); 92 | 93 | test( 94 | 'should reduce additions and subtractions (2)', 95 | testValue('calc(100% + 10px - 20px)', 'calc(100% - 10px)') 96 | ); 97 | 98 | test( 99 | 'should reduce additions and subtractions (3)', 100 | testValue('calc(1px - (2em + 3%))', 'calc(1px - 2em - 3%)') 101 | ); 102 | 103 | test( 104 | 'should reduce additions and subtractions (4)', 105 | testValue('calc((100vw - 50em) / 2)', 'calc(50vw - 25em)') 106 | ); 107 | 108 | test( 109 | 'should reduce additions and subtractions (5)', 110 | testValue('calc(10px - (100vw - 50em) / 2)', 'calc(10px - 50vw + 25em)') 111 | ); 112 | 113 | test( 114 | 'should reduce additions and subtractions (6)', 115 | testValue('calc(1px - (2em + 4vh + 3%))', 'calc(1px - 2em - 4vh - 3%)') 116 | ); 117 | 118 | test( 119 | 'should reduce additions and subtractions (7)', 120 | testValue( 121 | 'calc(0px - (24px - (var(--a) - var(--b)) / 2 + var(--c)))', 122 | 'calc(-24px + (var(--a) - var(--b))/2 - var(--c))' 123 | ) 124 | ); 125 | 126 | test( 127 | 'should reduce additions and subtractions (8)', 128 | testValue('calc(1px + (2em + (3vh + 4px)))', 'calc(5px + 2em + 3vh)') 129 | ); 130 | 131 | test( 132 | 'should reduce additions and subtractions (9)', 133 | testValue('calc(1px - (2em + 4px - 6vh) / 2)', 'calc(-1px - 1em + 3vh)') 134 | ); 135 | 136 | test( 137 | 'should reduce multiplication', 138 | testValue('calc(((var(--a) + 4px) * 2) * 2)', 'calc((var(--a) + 4px)*2*2)') 139 | ); 140 | 141 | test( 142 | 'should reduce multiplication before reducing additions', 143 | testValue( 144 | 'calc(((var(--a) + 4px) * 2) * 2 + 4px)', 145 | 'calc((var(--a) + 4px)*2*2 + 4px)' 146 | ) 147 | ); 148 | 149 | test( 150 | 'should reduce division', 151 | testValue('calc(((var(--a) + 4px) / 2) / 2)', 'calc((var(--a) + 4px)/2/2)') 152 | ); 153 | 154 | test( 155 | 'should reduce division before reducing additions', 156 | testValue( 157 | 'calc(((var(--a) + 4px) / 2) / 2 + 4px)', 158 | 'calc((var(--a) + 4px)/2/2 + 4px)' 159 | ) 160 | ); 161 | 162 | test( 163 | 'should ignore value surrounding calc function (1)', 164 | testValue('a calc(1px + 1px)', 'a 2px') 165 | ); 166 | 167 | test( 168 | 'should ignore value surrounding calc function (2)', 169 | testValue('calc(1px + 1px) a', '2px a') 170 | ); 171 | 172 | test( 173 | 'should ignore value surrounding calc function (3)', 174 | testValue('a calc(1px + 1px) b', 'a 2px b') 175 | ); 176 | 177 | test( 178 | 'should ignore value surrounding calc function (4)', 179 | testValue('a calc(1px + 1px) b calc(1em + 2em) c', 'a 2px b 3em c') 180 | ); 181 | 182 | test( 183 | 'should reduce nested calc', 184 | testValue('calc(100% - calc(50% + 25px))', 'calc(50% - 25px)') 185 | ); 186 | 187 | test( 188 | 'should reduce vendor-prefixed nested calc', 189 | testValue( 190 | '-webkit-calc(100% - -webkit-calc(50% + 25px))', 191 | '-webkit-calc(50% - 25px)' 192 | ) 193 | ); 194 | 195 | test('should reduce uppercase calc (1)', testValue('CALC(1px + 1px)', '2px')); 196 | 197 | test( 198 | 'should reduce uppercase calc (2)', 199 | testValue('CALC(1px + CALC(2px / 2))', '2px') 200 | ); 201 | 202 | test( 203 | 'should reduce uppercase calc (3)', 204 | testValue('-WEBKIT-CALC(1px + 1px)', '2px') 205 | ); 206 | 207 | test( 208 | 'should reduce uppercase calc (4)', 209 | testValue('-WEBKIT-CALC(1px + -WEBKIT-CALC(2px / 2))', '2px') 210 | ); 211 | 212 | test( 213 | 'should ignore calc with css variables (1)', 214 | testValue('calc(var(--mouseX) * 1px)', 'calc(var(--mouseX)*1px)') 215 | ); 216 | 217 | test( 218 | 'should ignore calc with css variables (2)', 219 | testValue( 220 | 'calc(10px - (100px * var(--mouseX)))', 221 | 'calc(10px - 100px*var(--mouseX))' 222 | ) 223 | ); 224 | 225 | test( 226 | 'should ignore calc with css variables (3)', 227 | testValue( 228 | 'calc(10px - (100px + var(--mouseX)))', 229 | 'calc(-90px - var(--mouseX))' 230 | ) 231 | ); 232 | 233 | test( 234 | 'should ignore calc with css variables (4)', 235 | testValue( 236 | 'calc(10px - (100px / var(--mouseX)))', 237 | 'calc(10px - 100px/var(--mouseX))' 238 | ) 239 | ); 240 | 241 | test( 242 | 'should ignore calc with css variables (5)', 243 | testValue( 244 | 'calc(10px - (100px - var(--mouseX)))', 245 | 'calc(-90px + var(--mouseX))' 246 | ) 247 | ); 248 | 249 | test( 250 | 'should ignore calc with css variables (6)', 251 | testValue('calc(var(--popupHeight) / 2)', 'calc(var(--popupHeight)/2)') 252 | ); 253 | 254 | test( 255 | 'should ignore calc with css variables (7)', 256 | testValue( 257 | 'calc(var(--popupHeight) / 2 + var(--popupWidth) / 2)', 258 | 'calc(var(--popupHeight)/2 + var(--popupWidth)/2)' 259 | ) 260 | ); 261 | 262 | 263 | test( 264 | 'should ignore multiplication with infinity', 265 | testValue('calc(infinity * 1px)', 'calc(infinity*1px)') 266 | ); 267 | 268 | test( 269 | 'should ignore addition with infinity', 270 | testValue('calc(infinity + 1px)', 'calc(infinity + 1px)') 271 | ); 272 | 273 | test( 274 | 'should ignore multiplication with pi', 275 | testValue('calc(1px * pi)', 'calc(1px*pi)') 276 | ); 277 | 278 | test( 279 | 'should ignore addition with pi', 280 | testValue('calc(43 + pi)', 'calc(43 + pi)') 281 | ); 282 | 283 | test( 284 | 'should preserve e', 285 | testValue('calc(e)', 'calc(e)') 286 | ); 287 | 288 | 289 | test( 290 | 'should reduce calc with newline characters', 291 | testValue('calc(\n1rem \n* 2 \n* 1.5)', '3rem') 292 | ); 293 | 294 | test( 295 | 'should preserve calc with incompatible units', 296 | testValue('calc(100% + 1px)', 'calc(100% + 1px)') 297 | ); 298 | 299 | test( 300 | 'should preserve calc with cqw units', 301 | testValue('calc(12.72727px + 8.523cqw)', 'calc(12.72727px + 8.523cqw)') 302 | ); 303 | 304 | test( 305 | 'should add numbers with cqw units', 306 | testValue('calc(1cqw + 8cqw)', '9cqw') 307 | ); 308 | 309 | test( 310 | 'should add numbers with cqh units', 311 | testValue('calc(1cqh + 3cqh)', '4cqh') 312 | ); 313 | 314 | test( 315 | 'should add numbers with cqi units', 316 | testValue('calc(1cqi + 3cqi)', '4cqi') 317 | ); 318 | 319 | test( 320 | 'should add numbers with cqb units', 321 | testValue('calc(1cqb + 3cqb)', '4cqb') 322 | ); 323 | 324 | test( 325 | 'should add numbers with cqmin units', 326 | testValue('calc(1cqmin + 3cqmin)', '4cqmin') 327 | ); 328 | 329 | test( 330 | 'should add numbers with cqmax units', 331 | testValue('calc(1cqmax + 3cqmax)', '4cqmax') 332 | ); 333 | 334 | test( 335 | 'should add expressions with svh units', 336 | testValue( 337 | 'calc(98% - 1.5rem - (85svh/8.2 + 1.9rem + 1.65svh))', 338 | 'calc(98% - 3.4rem - 12.01585svh)' 339 | ) 340 | ); 341 | 342 | test( 343 | 'should not combine different viewport units', 344 | testValue('calc(100svmax - 44.5svh)', 'calc(100svmax - 44.5svh)') 345 | ); 346 | 347 | test( 348 | 'should add numbers with lh units', 349 | testValue('calc(1lh + 4lh)', '5lh') 350 | ); 351 | 352 | test( 353 | 'should add numbers with rlh units', 354 | testValue('calc(1rlh + 4rlh)', '5rlh') 355 | ); 356 | 357 | test( 358 | 'should not combine different lh units', 359 | testValue('calc(1lh + 4rlh)', 'calc(1lh + 4rlh)') 360 | ); 361 | 362 | test( 363 | 'should not combine different lh units', 364 | testValue('calc(1lh + 20px)', 'calc(1lh + 20px)') 365 | ); 366 | 367 | test( 368 | 'should parse fractions without leading zero', 369 | testValue('calc(2rem - .14285em)', 'calc(2rem - 0.14285em)') 370 | ); 371 | 372 | test('should handle precision correctly (1)', testValue('calc(1/100)', '0.01')); 373 | 374 | test( 375 | 'should handle precision correctly (2)', 376 | testValue('calc(5/1000000)', '0.00001') 377 | ); 378 | 379 | test( 380 | 'should handle precision correctly (3)', 381 | testValue('calc(5/1000000)', '0.000005', { precision: 6 }) 382 | ); 383 | 384 | test( 385 | 'should reduce browser-prefixed calc (1)', 386 | testValue('-webkit-calc(1px + 1px)', '2px') 387 | ); 388 | 389 | test( 390 | 'should reduce browser-prefixed calc (2)', 391 | testValue('-moz-calc(1px + 1px)', '2px') 392 | ); 393 | 394 | test( 395 | 'should discard zero values (#2) (1)', 396 | testValue('calc(100vw / 2 - 6px + 0px)', 'calc(50vw - 6px)') 397 | ); 398 | 399 | test( 400 | 'should discard zero values (#2) (2)', 401 | testValue('calc(500px - 0px)', '500px') 402 | ); 403 | 404 | test( 405 | 'should not perform addition on unitless values (#3)', 406 | testValue('calc(1px + 1)', 'calc(1px + 1)') 407 | ); 408 | 409 | test( 410 | 'should reduce consecutive substractions (#24) (1)', 411 | testValue('calc(100% - 120px - 60px)', 'calc(100% - 180px)') 412 | ); 413 | 414 | test( 415 | 'should reduce consecutive substractions (#24) (2)', 416 | testValue('calc(100% - 10px - 20px)', 'calc(100% - 30px)') 417 | ); 418 | 419 | test( 420 | 'should reduce mixed units of time (postcss-calc#33)', 421 | testValue('calc(1s - 50ms)', '0.95s') 422 | ); 423 | 424 | test( 425 | 'should correctly reduce calc with mixed units (cssnano#211)', 426 | testValue('calc(99.99% * 1/1 - 0rem)', '99.99%') 427 | ); 428 | 429 | test( 430 | 'should apply optimization (cssnano#320)', 431 | testValue('calc(50% + (5em + 5%))', 'calc(55% + 5em)') 432 | ); 433 | 434 | test( 435 | 'should reduce substraction from zero', 436 | testValue('calc( 0 - 10px)', '-10px') 437 | ); 438 | 439 | test( 440 | 'should reduce subtracted expression from zero', 441 | testValue('calc( 0 - calc(1px + 1em) )', 'calc(-1px - 1em)') 442 | ); 443 | 444 | test( 445 | 'should reduce substracted expression from zero (1)', 446 | testValue('calc( 0 - (100vw - 10px) / 2 )', 'calc(-50vw + 5px)') 447 | ); 448 | 449 | test( 450 | 'should reduce substracted expression from zero (2)', 451 | testValue('calc( 0px - (100vw - 10px))', 'calc(10px - 100vw)') 452 | ); 453 | 454 | test( 455 | 'should reduce substracted expression from zero (3)', 456 | testValue('calc( 0px - (100vw - 10px) * 2 )', 'calc(20px - 200vw)') 457 | ); 458 | 459 | test( 460 | 'should reduce substracted expression from zero (4)', 461 | testValue('calc( 0px - (100vw + 10px))', 'calc(-10px - 100vw)') 462 | ); 463 | 464 | test( 465 | 'should reduce substracted expression from zero (css-variable)', 466 | testValue( 467 | 'calc( 0px - (var(--foo, 4px) / 2))', 468 | 'calc(0px - var(--foo, 4px)/2)' 469 | ) 470 | ); 471 | 472 | test( 473 | 'should reduce nested expression', 474 | testValue('calc( (1em - calc( 10px + 1em)) / 2)', '-5px') 475 | ); 476 | 477 | test( 478 | 'should skip constant function', 479 | testValue( 480 | 'calc(constant(safe-area-inset-left))', 481 | 'calc(constant(safe-area-inset-left))' 482 | ) 483 | ); 484 | 485 | test( 486 | 'should skip env function', 487 | testValue( 488 | 'calc(env(safe-area-inset-left))', 489 | 'calc(env(safe-area-inset-left))' 490 | ) 491 | ); 492 | 493 | test( 494 | 'should skip env function (#1)', 495 | testValue( 496 | 'calc(env(safe-area-inset-left, 50px 20px))', 497 | 'calc(env(safe-area-inset-left, 50px 20px))' 498 | ) 499 | ); 500 | 501 | test( 502 | 'should skip unknown function', 503 | testValue( 504 | 'calc(unknown(safe-area-inset-left))', 505 | 'calc(unknown(safe-area-inset-left))' 506 | ) 507 | ); 508 | 509 | test( 510 | 'should preserve the original declaration when `preserve` option is set to true', 511 | testCss('foo{bar:calc(1rem * 1.5)}', 'foo{bar:1.5rem;bar:calc(1rem * 1.5)}', { 512 | preserve: true, 513 | }) 514 | ); 515 | 516 | test( 517 | 'should not yield warnings when nothing is wrong', 518 | testValue('calc(500px - 0px)', '500px', { warnWhenCannotResolve: true }) 519 | ); 520 | 521 | test( 522 | 'should warn when calc expression cannot be reduced to a single value', 523 | testValue('calc(100% + 1px)', 'calc(100% + 1px)', { 524 | warnWhenCannotResolve: true, 525 | }) 526 | ); 527 | 528 | test( 529 | 'should reduce mixed units of time (#33)', 530 | testValue('calc(1s - 50ms)', '0.95s') 531 | ); 532 | 533 | test( 534 | 'should not parse variables as calc expressions (#35)', 535 | testCss( 536 | 'foo:nth-child(2n + $var-calc){}', 537 | 'foo:nth-child(2n + $var-calc){}', 538 | { selectors: true } 539 | ) 540 | ); 541 | 542 | test( 543 | 'should apply algebraic reduction (cssnano#319)', 544 | testValue('calc((100px - 1em) + (-50px + 1em))', '50px') 545 | ); 546 | 547 | test( 548 | 'should discard zero values (reduce-css-calc#2) (1)', 549 | testValue('calc(100vw / 2 - 6px + 0px)', 'calc(50vw - 6px)') 550 | ); 551 | 552 | test( 553 | 'should discard zero values (reduce-css-calc#2) (2)', 554 | testValue('calc(500px - 0px)', '500px') 555 | ); 556 | 557 | test( 558 | 'should not perform addition on unitless values (reduce-css-calc#3)', 559 | testValue('calc(1px + 1)', 'calc(1px + 1)') 560 | ); 561 | 562 | test( 563 | 'should return the same and not thrown an exception for attribute selectors without a value', 564 | testCss('button[disabled]{}', 'button[disabled]{}', { selectors: true }) 565 | ); 566 | 567 | test( 568 | 'should ignore reducing custom property', 569 | testCss( 570 | ':root { --foo: calc(var(--bar) / 8); }', 571 | ':root { --foo: calc(var(--bar)/8); }' 572 | ) 573 | ); 574 | 575 | test( 576 | 'should ignore media queries', 577 | testCss( 578 | '@media (min-width:calc(10px+10px)){}', 579 | '@media (min-width:calc(10px+10px)){}' 580 | ) 581 | ); 582 | 583 | test( 584 | 'should reduce calc in media queries when `mediaQueries` option is set to true', 585 | testCss('@media (min-width:calc(10px+10px)){}', '@media (min-width:20px){}', { 586 | mediaQueries: true, 587 | }) 588 | ); 589 | 590 | test( 591 | 'should ignore selectors (1)', 592 | testCss('div[data-size="calc(3*3)"]{}', 'div[data-size="calc(3*3)"]{}') 593 | ); 594 | 595 | test( 596 | 'should ignore selectors (2)', 597 | testCss('div:nth-child(2n + calc(3*3)){}', 'div:nth-child(2n + calc(3*3)){}') 598 | ); 599 | 600 | test( 601 | 'should reduce calc in selectors when `selectors` option is set to true (1)', 602 | testCss('div[data-size="calc(3*3)"]{}', 'div[data-size="9"]{}', { 603 | selectors: true, 604 | }) 605 | ); 606 | 607 | test( 608 | 'should reduce calc in selectors when `selectors` option is set to true (2)', 609 | testCss('div:nth-child(2n + calc(3*3)){}', 'div:nth-child(2n + 9){}', { 610 | selectors: true, 611 | }) 612 | ); 613 | 614 | test( 615 | 'should not reduce 100% to 1 (reduce-css-calc#44)', 616 | testCss( 617 | '.@supports (width:calc(100% - constant(safe-area-inset-left))){.a{width:calc(100% - constant(safe-area-inset-left))}}', 618 | '.@supports (width:calc(100% - constant(safe-area-inset-left))){.a{width:calc(100% - constant(safe-area-inset-left))}}' 619 | ) 620 | ); 621 | 622 | test( 623 | 'should not break css variables that have "calc" in their names', 624 | testCss( 625 | 'a{transform: translateY(calc(-100% - var(--tooltip-calculated-offset)))}', 626 | 'a{transform: translateY(calc(-100% - var(--tooltip-calculated-offset)))}' 627 | ) 628 | ); 629 | 630 | test( 631 | 'should handle complex calculations (reduce-css-calc#45) (1)', 632 | testValue( 633 | 'calc(100% + (2 * 100px) - ((75.37% - 63.5px) - 900px))', 634 | 'calc(24.63% + 1163.5px)' 635 | ) 636 | ); 637 | 638 | test( 639 | 'should handle complex calculations (reduce-css-calc#45) (2)', 640 | testValue( 641 | 'calc(((((100% + (2 * 30px) + 63.5px) / 0.7537) - (100vw - 60px)) / 2) + 30px)', 642 | 'calc(66.33939% + 141.92915px - 50vw)' 643 | ) 644 | ); 645 | 646 | test( 647 | 'should handle advanced arithmetic (1)', 648 | testValue( 649 | 'calc(((75.37% - 63.5px) - 900px) + (2 * 100px))', 650 | 'calc(75.37% - 763.5px)' 651 | ) 652 | ); 653 | 654 | test( 655 | 'should handle advanced arithmetic (2)', 656 | testValue( 657 | 'calc((900px - (10% - 63.5px)) + (2 * 100px))', 658 | 'calc(1163.5px - 10%)' 659 | ) 660 | ); 661 | 662 | test( 663 | 'should handle nested calc statements (reduce-css-calc#49)', 664 | testValue('calc(calc(2.25rem + 2px) - 1px * 2)', '2.25rem') 665 | ); 666 | 667 | test( 668 | 'should throw an exception when attempting to divide by zero', 669 | testThrows('calc(500px/0)', 'calc(500px/0)', 'Cannot divide by zero') 670 | ); 671 | 672 | test( 673 | 'should throw an exception when attempting to divide by unit (#1)', 674 | testThrows( 675 | 'calc(500px/2px)', 676 | 'calc(500px/2px)', 677 | 'Cannot divide by "px", number expected' 678 | ) 679 | ); 680 | 681 | test( 682 | 'nested var (reduce-css-calc#50)', 683 | testValue( 684 | 'calc(var(--xxx, var(--yyy)) / 2)', 685 | 'calc(var(--xxx, var(--yyy))/2)' 686 | ) 687 | ); 688 | 689 | test( 690 | 'should not throw an exception when unknow function exist in calc', 691 | testValue( 692 | 'calc(unknown(#fff) - other-unknown(200px))', 693 | 'calc(unknown(#fff) - other-unknown(200px))' 694 | ) 695 | ); 696 | 697 | test( 698 | 'should not throw an exception when unknow function exist in calc (#1)', 699 | testValue( 700 | 'calc(unknown(#fff) * other-unknown(200px))', 701 | 'calc(unknown(#fff)*other-unknown(200px))' 702 | ) 703 | ); 704 | 705 | test( 706 | 'should not strip calc with single CSS custom variable', 707 | testValue('calc(var(--foo))', 'calc(var(--foo))') 708 | ); 709 | 710 | test( 711 | 'should strip unnecessary calc with single CSS custom variable', 712 | testValue('calc(calc(var(--foo)))', 'calc(var(--foo))') 713 | ); 714 | 715 | test( 716 | 'should not strip calc with single CSS custom variables and value', 717 | testValue('calc(var(--foo) + 10px)', 'calc(var(--foo) + 10px)') 718 | ); 719 | 720 | test('should reduce calc (uppercase)', testValue('CALC(1PX + 1PX)', '2PX')); 721 | 722 | test( 723 | 'should reduce calc (uppercase) (#1)', 724 | testValue('CALC(VAR(--foo) + VAR(--bar))', 'CALC(VAR(--foo) + VAR(--bar))') 725 | ); 726 | 727 | test( 728 | 'should reduce calc (uppercase) (#2)', 729 | testValue('CALC( (1EM - CALC( 10PX + 1EM)) / 2)', '-5PX') 730 | ); 731 | 732 | test( 733 | 'should handle nested calc function (#1)', 734 | testValue( 735 | 'calc(calc(var(--foo) + var(--bar)) + var(--baz))', 736 | 'calc(var(--foo) + var(--bar) + var(--baz))' 737 | ) 738 | ); 739 | 740 | test( 741 | 'should handle nested calc function (#2)', 742 | testValue( 743 | 'calc(var(--foo) + calc(var(--bar) + var(--baz)))', 744 | 'calc(var(--foo) + var(--bar) + var(--baz))' 745 | ) 746 | ); 747 | 748 | test( 749 | 'should handle nested calc function (#3)', 750 | testValue( 751 | 'calc(calc(var(--foo) - var(--bar)) - var(--baz))', 752 | 'calc(var(--foo) - var(--bar) - var(--baz))' 753 | ) 754 | ); 755 | 756 | test( 757 | 'should handle nested calc function (#4)', 758 | testValue( 759 | 'calc(var(--foo) - calc(var(--bar) - var(--baz)))', 760 | 'calc(var(--foo) - var(--bar) + var(--baz))' 761 | ) 762 | ); 763 | 764 | test( 765 | 'should handle nested calc function (#5)', 766 | testValue( 767 | 'calc(calc(var(--foo) + var(--bar)) - var(--baz))', 768 | 'calc(var(--foo) + var(--bar) - var(--baz))' 769 | ) 770 | ); 771 | 772 | test( 773 | 'should handle nested calc function (#6)', 774 | testValue( 775 | 'calc(var(--foo) + calc(var(--bar) - var(--baz)))', 776 | 'calc(var(--foo) + var(--bar) - var(--baz))' 777 | ) 778 | ); 779 | 780 | test( 781 | 'should handle nested calc function (#7)', 782 | testValue( 783 | 'calc(calc(var(--foo) - var(--bar)) + var(--baz))', 784 | 'calc(var(--foo) - var(--bar) + var(--baz))' 785 | ) 786 | ); 787 | 788 | test( 789 | 'should handle nested calc function (#8)', 790 | testValue( 791 | 'calc(var(--foo) - calc(var(--bar) + var(--baz)))', 792 | 'calc(var(--foo) - var(--bar) - var(--baz))' 793 | ) 794 | ); 795 | 796 | test( 797 | 'should handle nested calc function (#9)', 798 | testValue( 799 | 'calc(calc(var(--foo) + var(--bar)) * var(--baz))', 800 | 'calc((var(--foo) + var(--bar))*var(--baz))' 801 | ) 802 | ); 803 | 804 | test( 805 | 'should handle nested calc function (#10)', 806 | testValue( 807 | 'calc(var(--foo) * calc(var(--bar) + var(--baz)))', 808 | 'calc(var(--foo)*(var(--bar) + var(--baz)))' 809 | ) 810 | ); 811 | 812 | test( 813 | 'should handle nested calc function (#11)', 814 | testValue( 815 | 'calc(calc(var(--foo) + var(--bar)) / var(--baz))', 816 | 'calc((var(--foo) + var(--bar))/var(--baz))' 817 | ) 818 | ); 819 | 820 | test( 821 | 'should handle nested calc function (#12)', 822 | testValue( 823 | 'calc(var(--foo) / calc(var(--bar) + var(--baz)))', 824 | 'calc(var(--foo)/(var(--bar) + var(--baz)))' 825 | ) 826 | ); 827 | 828 | test( 829 | 'should handle nested calc function (#13)', 830 | testValue( 831 | 'calc(100vh - 5rem - calc(10rem + 100px))', 832 | 'calc(100vh - 15rem - 100px)' 833 | ) 834 | ); 835 | 836 | test( 837 | 'should handle nested calc function (#14)', 838 | testValue('calc(100% - calc(10px + 2vw))', 'calc(100% - 10px - 2vw)') 839 | ); 840 | 841 | test( 842 | 'should handle nested calc function (#15)', 843 | testValue('calc(100% - calc(10px - 2vw))', 'calc(100% - 10px + 2vw)') 844 | ); 845 | 846 | test( 847 | 'should preserve division precedence', 848 | testValue( 849 | 'calc(100%/(var(--aspect-ratio)))', 850 | 'calc(100%/(var(--aspect-ratio)))' 851 | ) 852 | ); 853 | 854 | test( 855 | 'should preserve division precedence (2)', 856 | testValue( 857 | `calc( 858 | (var(--fluid-screen) - ((var(--fluid-min-width) / 16) * 1rem)) / 859 | ((var(--fluid-max-width) / 16) - (var(--fluid-min-width) / 16)) 860 | )`, 861 | 'calc((var(--fluid-screen) - ((var(--fluid-min-width)/16)*1rem))/(var(--fluid-max-width)/16 - var(--fluid-min-width)/16))' 862 | ) 863 | ); 864 | 865 | test( 866 | 'should preserve division precedence (3)', 867 | testValue('calc(1/(10/var(--dot-size)))', 'calc(1/(10/var(--dot-size)))') 868 | ); 869 | 870 | test( 871 | 'should correctly preserve parentheses', 872 | testValue( 873 | 'calc(1/((var(--a) - var(--b))/16))', 874 | 'calc(1/(var(--a) - var(--b))/16)' 875 | ) 876 | ); 877 | 878 | test( 879 | 'should preserve calc when extra parentheses are used', 880 | testValue( 881 | 'calc((var(--circumference) / var(--number-of-segments)))', 882 | 'calc(var(--circumference)/var(--number-of-segments))' 883 | ) 884 | ); 885 | 886 | test('precision for calc', testValue('calc(100% / 3 * 3)', '100%')); 887 | 888 | test( 889 | 'precision for nested calc', 890 | testValue('calc(calc(100% / 3) * 3)', '100%') 891 | ); 892 | 893 | test('plus sign', testValue('calc(+100px + +100px)', '200px')); 894 | 895 | test('plus sign (#1)', testValue('calc(+100px - +100px)', '0px')); 896 | 897 | test('plus sign (#2)', testValue('calc(200px * +1)', '200px')); 898 | 899 | test('plus sign (#3)', testValue('calc(200px / +1)', '200px')); 900 | 901 | test('minus sign', testValue('calc(-100px + -100px)', '-200px')); 902 | 903 | test('minus sign (#2)', testValue('calc(-100px - -100px)', '0px')); 904 | 905 | test('minus sign (#3)', testValue('calc(200px * -1)', '-200px')); 906 | 907 | test('minus sign (#4)', testValue('calc(200px / -1)', '-200px')); 908 | 909 | test('whitespace', testValue('calc( 100px + 100px )', '200px')); 910 | 911 | test('whitespace (#1)', testValue('calc(\t100px\t+\t100px\t)', '200px')); 912 | 913 | test('whitespace (#2)', testValue('calc(\n100px\n+\n100px\n)', '200px')); 914 | 915 | test( 916 | 'whitespace (#4)', 917 | testValue('calc(\r\n100px\r\n+\r\n100px\r\n)', '200px') 918 | ); 919 | 920 | /* Skip removal of comments because it was PostCSS that used to take care of that, 921 | but now does not anymore, but we need to upgrade PostCSS because older versions 922 | have a vulnerability */ 923 | test.skip( 924 | 'comments', 925 | testValue('calc(/*test*/100px/*test*/ + /*test*/100px/*test*/)', '200px') 926 | ); 927 | 928 | test.skip( 929 | 'comments (#1)', 930 | testValue('calc(/*test*/100px/*test*/*/*test*/2/*test*/)', '200px') 931 | ); 932 | 933 | test.skip( 934 | 'comments nested', 935 | testValue( 936 | 'calc(/*test*/100px + calc(/*test*/100px/*test*/ + /*test*/100px/*test*/))', 937 | '300px' 938 | ) 939 | ); 940 | 941 | test('exponent composed', testValue('calc(1.1e+1px + 1.1e+1px)', '22px')); 942 | 943 | test('exponent composed (#1)', testValue('calc(10e+1px + 10e+1px)', '200px')); 944 | 945 | test( 946 | 'exponent composed (#2)', 947 | testValue('calc(1.1e+10px + 1.1e+10px)', '22000000000px') 948 | ); 949 | 950 | test('exponent composed (#3)', testValue('calc(9e+1 * 1px)', '90px')); 951 | 952 | test('exponent composed (#4)', testValue('calc(9e+1% + 10%)', '100%')); 953 | 954 | test( 955 | 'exponent composed (uppercase)', 956 | testValue('calc(1.1E+1px + 1.1E+1px)', '22px') 957 | ); 958 | 959 | test('convert units', testValue('calc(1cm + 1px)', '1.02646cm')); 960 | 961 | test('convert units (#1)', testValue('calc(1px + 1cm)', '38.79528px')); 962 | 963 | test('convert units (#2)', testValue('calc(10Q + 10Q)', '20Q')); 964 | 965 | test('convert units (#3)', testValue('calc(100.9q + 10px)', '111.48333q')); 966 | 967 | test('convert units (#4)', testValue('calc(10px + 100.9q)', '105.33858px')); 968 | 969 | test('convert units (#5)', testValue('calc(10cm + 1px)', '10.02646cm')); 970 | 971 | test('convert units (#6)', testValue('calc(10mm + 1px)', '10.26458mm')); 972 | 973 | test('convert units (#7)', testValue('calc(10px + 1q)', '10.94488px')); 974 | 975 | test('convert units (#8)', testValue('calc(10cm + 1q)', '10.025cm')); 976 | 977 | test('convert units (#9)', testValue('calc(10mm + 1q)', '10.25mm')); 978 | 979 | test('convert units (#10)', testValue('calc(10in + 1q)', '10.00984in')); 980 | 981 | test('convert units (#11)', testValue('calc(10pt + 1q)', '10.70866pt')); 982 | 983 | test('convert units (#12)', testValue('calc(10pc + 1q)', '10.05906pc')); 984 | 985 | test('convert units (#13)', testValue('calc(1q + 10px)', '11.58333q')); 986 | 987 | test('convert units (#14)', testValue('calc(1q + 10cm)', '401q')); 988 | 989 | test('convert units (#15)', testValue('calc(1q + 10mm)', '41q')); 990 | 991 | test('convert units (#16)', testValue('calc(1q + 10in)', '1017q')); 992 | 993 | test('convert units (#17)', testValue('calc(1q + 10pt)', '15.11111q')); 994 | 995 | test('convert units (#18)', testValue('calc(1q + 10pc)', '170.33333q')); 996 | 997 | test( 998 | 'unknown units', 999 | testValue('calc(1unknown + 2unknown)', 'calc(1unknown + 2unknown)') 1000 | ); 1001 | 1002 | test( 1003 | 'unknown units with known', 1004 | testValue('calc(1unknown + 2px)', 'calc(1unknown + 2px)') 1005 | ); 1006 | 1007 | test( 1008 | 'unknown units with known (#1)', 1009 | testValue('calc(1px + 2unknown)', 'calc(1px + 2unknown)') 1010 | ); 1011 | 1012 | test( 1013 | 'calc-size should be ignored', 1014 | testCssDoesNotThrow('.foo{block-size: calc-size(auto, size)}', '.foo{block-size: calc-size(auto, size)}') 1015 | ); 1016 | 1017 | test( 1018 | 'error with parsing', 1019 | testThrows( 1020 | 'calc(10pc + unknown)', 1021 | 'calc(10pc + unknown)', 1022 | 'Lexical error on line 1: Unrecognized text.\n\n Erroneous area:\n1: 10pc + unknown\n^.........^' 1023 | ) 1024 | ); 1025 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2021", 4 | "lib": ["es2021"], 5 | "module": "commonjs", 6 | "allowJs": true, 7 | "checkJs": true, 8 | "declaration": true, 9 | "emitDeclarationOnly": true, 10 | "noEmitOnError": true, 11 | "newLine": "lf", 12 | "outDir": "types", 13 | "allowSyntheticDefaultImports": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "strict": true, 16 | }, 17 | "include": ["src/*"], 18 | "exclude": ["src/parser.js"] 19 | } 20 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | export = pluginCreator; 2 | /** 3 | * @typedef {{precision?: number | false, 4 | * preserve?: boolean, 5 | * warnWhenCannotResolve?: boolean, 6 | * mediaQueries?: boolean, 7 | * selectors?: boolean}} PostCssCalcOptions 8 | */ 9 | /** 10 | * @type {import('postcss').PluginCreator} 11 | * @param {PostCssCalcOptions} opts 12 | * @return {import('postcss').Plugin} 13 | */ 14 | declare function pluginCreator(opts: PostCssCalcOptions): import("postcss").Plugin; 15 | declare namespace pluginCreator { 16 | export { postcss, PostCssCalcOptions }; 17 | } 18 | declare var postcss: true; 19 | type PostCssCalcOptions = { 20 | precision?: number | false; 21 | preserve?: boolean; 22 | warnWhenCannotResolve?: boolean; 23 | mediaQueries?: boolean; 24 | selectors?: boolean; 25 | }; 26 | -------------------------------------------------------------------------------- /types/lib/convertUnit.d.ts: -------------------------------------------------------------------------------- 1 | export = convertUnit; 2 | /** 3 | * @param {number} value 4 | * @param {string} sourceUnit 5 | * @param {string} targetUnit 6 | * @param {number|false} precision 7 | */ 8 | declare function convertUnit(value: number, sourceUnit: string, targetUnit: string, precision: number | false): number; 9 | -------------------------------------------------------------------------------- /types/lib/reducer.d.ts: -------------------------------------------------------------------------------- 1 | export = reduce; 2 | /** 3 | * @param {import('../parser').CalcNode} node 4 | * @param {number} precision 5 | * @return {import('../parser').CalcNode} 6 | */ 7 | declare function reduce(node: import("../parser").CalcNode, precision: number): import("../parser").CalcNode; 8 | declare namespace reduce { 9 | export { Collectible }; 10 | } 11 | type Collectible = { 12 | preOperator: "+" | "-"; 13 | node: import("../parser").CalcNode; 14 | }; 15 | -------------------------------------------------------------------------------- /types/lib/stringifier.d.ts: -------------------------------------------------------------------------------- 1 | declare function _exports(calc: string, node: import("../parser").CalcNode, originalValue: string, options: { 2 | precision: number | false; 3 | warnWhenCannotResolve: boolean; 4 | }, result: import("postcss").Result, item: import("postcss").ChildNode): string; 5 | export = _exports; 6 | -------------------------------------------------------------------------------- /types/lib/transform.d.ts: -------------------------------------------------------------------------------- 1 | declare function _exports(node: any, property: "value" | "params" | "selector", options: { 2 | precision: number; 3 | preserve: boolean; 4 | warnWhenCannotResolve: boolean; 5 | }, result: import("postcss").Result): void; 6 | export = _exports; 7 | --------------------------------------------------------------------------------