diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 6eec078d6..0aaa2efe2 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -3,7 +3,6 @@ If you want to contribute to PostCSS, there are a few things that you should be familiar with. - ## Adding Your Plugin to the List If you created or found a plugin and want to add it to the PostCSS plugins list @@ -14,55 +13,53 @@ moderated by the PostCSS author. Plugins submitted by the community are located in [`docs/plugins`]. -* **Keep plugins ordered** +- **Keep plugins ordered** - Be sure that a plugin is not already present and find a suitable position - for it in alphabetical order. - However plugins with `postcss-` prefix should come first. + Be sure that a plugin is not already present and find a suitable position + for it in alphabetical order. + However plugins with `postcss-` prefix should come first. -* **Check spelling** +- **Check spelling** - Before submitting a PR make sure the spelling check is passing. - To run the check use `npm test`. - If it fails with an unknown word error, add it as a word - to `.yaspellerrc` dictionary. + Before submitting a PR make sure the spelling check is passing. + To run the check use `npm test`. + If it fails with an unknown word error, add it as a word + to `.yaspellerrc` dictionary. -* **Check PostCSS plugin guidelines** +- **Check PostCSS plugin guidelines** - The suggested plugin should match plugin [guidelines]. + The suggested plugin should match plugin [guidelines]. -- **Provide link to suggested plugin** +* **Provide link to suggested plugin** - Make sure your pull request description contains a link to the plugin - you want to add. + Make sure your pull request description contains a link to the plugin + you want to add. [`docs/plugins`]: https://github.com/postcss/postcss/blob/main/docs/plugins.md -[guidelines]: https://github.com/postcss/postcss/blob/main/docs/guidelines/plugin.md - +[guidelines]: https://github.com/postcss/postcss/blob/main/docs/guidelines/plugin.md ## TypeScript Declaration Improvements If you found a bug or want to add certain improvements to types declaration file: -* **Check current TypeScript styling** +- **Check current TypeScript styling** - Be sure that your changes match TypeScript styling rules defined in typings file. - * We use classes for existing JS classes like `Stringifier`. - * Namespaces used for separating functions related to the same subject. - * Interfaces used for defining custom types. + Be sure that your changes match TypeScript styling rules defined in typings file. + - We use classes for existing JS classes like `Stringifier`. + - Namespaces used for separating functions related to the same subject. + - Interfaces used for defining custom types. - Make sure you read through declaration file writing [best practices] - by the TypeScript team. + Make sure you read through declaration file writing [best practices] + by the TypeScript team. [best practices]: https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html - ## Core Development If you want to add new features or fix existing issues - **Become familiar with PostCSS architecture** - For a gentle intro to PostCSS architecture look through our [guide]. + For a gentle intro to PostCSS architecture look through our [guide]. [guide]: https://github.com/postcss/postcss/blob/main/docs/architecture.md diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..04fb6b3a8 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,44 @@ +name: Release +on: + push: + tags: + - '*' +permissions: + contents: write +jobs: + release: + name: Release On Tag + if: startsWith(github.ref, 'refs/tags/') + runs-on: ubuntu-latest + steps: + - name: Checkout the repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Extract the changelog + id: changelog + run: | + TAG_NAME=${GITHUB_REF/refs\/tags\//} + READ_SECTION=false + CHANGELOG="" + while IFS= read -r line; do + if [[ "$line" =~ ^#+\ +(.*) ]]; then + if [[ "${BASH_REMATCH[1]}" == "$TAG_NAME" ]]; then + READ_SECTION=true + elif [[ "$READ_SECTION" == true ]]; then + break + fi + elif [[ "$READ_SECTION" == true ]]; then + CHANGELOG+="$line"$'\n' + fi + done < "CHANGELOG.md" + CHANGELOG=$(echo "$CHANGELOG" | awk '/./ {$1=$1;print}') + echo "changelog_content<> $GITHUB_OUTPUT + echo "$CHANGELOG" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + - name: Create the release + if: steps.changelog.outputs.changelog_content != '' + uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0 + with: + name: ${{ github.ref_name }} + body: '${{ steps.changelog.outputs.changelog_content }}' + draft: false + prerelease: false diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b379d876d..2771ece37 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,18 +12,18 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install pnpm - uses: pnpm/action-setup@v2 + uses: pnpm/action-setup@8912a9102ac27614460f54aedde9e1e7f9aec20d # v6.0.5 with: - version: 8 + version: 11 - name: Install Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: - node-version: 20 + node-version: 25 cache: pnpm - name: Install dependencies - run: pnpm install --frozen-lockfile --ignore-scripts + run: pnpm ci --ignore-scripts - name: Run tests run: pnpm test short: @@ -31,23 +31,23 @@ jobs: strategy: matrix: node-version: - - 18 - - 16 + - 24 + - 22 name: Node.js ${{ matrix.node-version }} Quick steps: - name: Checkout the repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install pnpm - uses: pnpm/action-setup@v2 + uses: pnpm/action-setup@8912a9102ac27614460f54aedde9e1e7f9aec20d # v6.0.5 with: - version: 8 + version: 11 - name: Install Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: ${{ matrix.node-version }} cache: pnpm - name: Install dependencies - run: pnpm install --frozen-lockfile --ignore-scripts + run: pnpm ci --ignore-scripts - name: Run unit tests run: pnpm run unit old: @@ -55,27 +55,30 @@ jobs: strategy: matrix: node-version: + - 20 + - 18 + - 16 - 14 - 12 - 10 name: Node.js ${{ matrix.node-version }} Quick steps: - name: Checkout the repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install pnpm - uses: pnpm/action-setup@v1 + uses: pnpm/action-setup@8912a9102ac27614460f54aedde9e1e7f9aec20d # v6.0.5 with: version: 3 env: ACTIONS_ALLOW_UNSECURE_COMMANDS: true - name: Install Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: ${{ matrix.node-version }} - name: Install dependencies run: pnpm install --ignore-scripts - name: Downgrade TypeScript - run: pnpm install typescript@4 + run: pnpm install typescript@4 --ignore-scripts - name: Run unit tests run: pnpm run old windows: @@ -83,17 +86,17 @@ jobs: name: Windows Quick steps: - name: Checkout the repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install pnpm - uses: pnpm/action-setup@v2 + uses: pnpm/action-setup@8912a9102ac27614460f54aedde9e1e7f9aec20d # v6.0.5 with: - version: latest + version: 10 - name: Install Node.js LTS - uses: actions/setup-node@v3 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: - node-version: 20 + node-version: 24 cache: pnpm - name: Install dependencies - run: pnpm install --frozen-lockfile --ignore-scripts + run: pnpm install --ignore-scripts - name: Run unit tests run: pnpm run unit diff --git a/.npmignore b/.npmignore index de9010b49..9439f8b9d 100644 --- a/.npmignore +++ b/.npmignore @@ -3,3 +3,5 @@ test/ docs/ tsconfig.json +eslint.config.mjs +pnpm-workspace.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index 05c9da70e..aa7eb91a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,999 +1,1383 @@ # Change Log + This project adheres to [Semantic Versioning](https://semver.org/). +## 8.5.14 + +- Fixed custom syntax regression (by @43081j). + +## 8.5.13 + +- Fixed `postcss-scss` commend regression. + +## 8.5.12 + +- Fixed reading any file via user-generated CSS. +- Added `opts.unsafeMap` to disable checks. + +## 8.5.11 + +- Fixed nested brackets parsing performance (by @offset). + +## 8.5.10 + +- Fixed XSS via unescaped `` in non-bundler cases (by @TharVid). + +## 8.5.9 + +- Speed up source map encoding paring in case of the error. + +## 8.5.8 + +- Fixed `Processor#version`. + +## 8.5.7 + +- Improved source map annotation cleaning performance (by CodeAnt AI). + +## 8.5.6 + +- Fixed `ContainerWithChildren` type discriminating (by @Goodwine). + +## 8.5.5 + +- Fixed `package.json`→`exports` compatibility with some tools (by @JounQin). + +## 8.5.4 + +- Fixed Parcel compatibility issue (by @git-sumitchaudhary). + +## 8.5.3 + +- Added more details to `Unknown word` error (by @hiepxanh). +- Fixed types (by @romainmenke). +- Fixed docs (by @catnipan). + +## 8.5.2 + +- Fixed end position of rules with semicolon (by @romainmenke). + +## 8.5.1 + +- Fixed backwards compatibility for complex cases (by @romainmenke). + +## 8.5 “Duke Alloces” + +- Added `Input#document` for sources like CSS-in-JS or HTML (by @romainmenke). + +## 8.4.49 + +- Fixed custom syntax without `source.offset` (by @romainmenke). + +## 8.4.48 + +- Fixed position calculation in error/warnings methods (by @romainmenke). + +## 8.4.47 + +- Removed debug code. + +## 8.4.46 + +- Fixed `Cannot read properties of undefined (reading 'before')`. + +## 8.4.45 + +- Removed unnecessary fix which could lead to infinite loop. + +## 8.4.44 + +- Another way to fix `markClean is not a function` error. + +## 8.4.43 + +- Fixed `markClean is not a function` error. + +## 8.4.42 + +- Fixed CSS syntax error on long minified files (by @varpstar). + +## 8.4.41 + +- Fixed types (by @nex3 and @querkmachine). +- Cleaned up RegExps (by @bluwy). + +## 8.4.40 + +- Moved to getter/setter in nodes types to help Sass team (by @nex3). + +## 8.4.39 + +- Fixed `CssSyntaxError` types (by @romainmenke). + +## 8.4.38 + +- Fixed `endIndex: 0` in errors and warnings (by @romainmenke). + +## 8.4.37 + +- Fixed `original.column are not numbers` error in another case. + +## 8.4.36 + +- Fixed `original.column are not numbers` error on broken previous source map. + +## 8.4.35 + +- Avoid `!` in `node.parent.nodes` type. +- Allow to pass `undefined` to node adding method to simplify types. + +## 8.4.34 + +- Fixed `AtRule#nodes` type (by Tim Weißenfels). +- Cleaned up code (by Dmitry Kirillov). + +## 8.4.33 + +- Fixed `NoWorkResult` behavior difference with normal mode (by Romain Menke). +- Fixed `NoWorkResult` usage conditions (by @ahmdammarr). + +## 8.4.32 + +- Fixed `postcss().process()` types (by Andrew Ferreira). + ## 8.4.31 -* Fixed `\r` parsing to fix CVE-2023-44270. + +- Fixed `\r` parsing to fix CVE-2023-44270. ## 8.4.30 -* Improved source map performance (by Romain Menke). + +- Improved source map performance (by Romain Menke). ## 8.4.29 -* Fixed `Node#source.offset` (by Ido Rosenthal). -* Fixed docs (by Christian Oliff). + +- Fixed `Node#source.offset` (by Ido Rosenthal). +- Fixed docs (by Christian Oliff). ## 8.4.28 -* Fixed `Root.source.end` for better source map (by Romain Menke). -* Fixed `Result.root` types when `process()` has no parser. + +- Fixed `Root.source.end` for better source map (by Romain Menke). +- Fixed `Result.root` types when `process()` has no parser. ## 8.4.27 -* Fixed `Container` clone methods types. + +- Fixed `Container` clone methods types. ## 8.4.26 -* Fixed clone methods types. + +- Fixed clone methods types. ## 8.4.25 -* Improve stringify performance (by Romain Menke). -* Fixed docs (by @vikaskaliramna07). + +- Improve stringify performance (by Romain Menke). +- Fixed docs (by @vikaskaliramna07). ## 8.4.24 -* Fixed `Plugin` types. + +- Fixed `Plugin` types. ## 8.4.23 -* Fixed warnings in TypeDoc. + +- Fixed warnings in TypeDoc. ## 8.4.22 -* Fixed TypeScript support with `node16` (by Remco Haszing). + +- Fixed TypeScript support with `node16` (by Remco Haszing). ## 8.4.21 -* Fixed `Input#error` types (by Aleks Hudochenkov). + +- Fixed `Input#error` types (by Aleks Hudochenkov). ## 8.4.20 -* Fixed source map generation for childless at-rules like `@layer`. + +- Fixed source map generation for childless at-rules like `@layer`. ## 8.4.19 -* Fixed whitespace preserving after AST transformations (by Romain Menke). + +- Fixed whitespace preserving after AST transformations (by Romain Menke). ## 8.4.18 -* Fixed an error on `absolute: true` with empty `sourceContent` (by Rene Haas). + +- Fixed an error on `absolute: true` with empty `sourceContent` (by Rene Haas). ## 8.4.17 -* Fixed `Node.before()` unexpected behavior (by Romain Menke). -* Added TOC to docs (by Mikhail Dedov). + +- Fixed `Node.before()` unexpected behavior (by Romain Menke). +- Added TOC to docs (by Mikhail Dedov). ## 8.4.16 -* Fixed `Root` AST migration. + +- Fixed `Root` AST migration. ## 8.4.15 -* Fixed AST normalization after using custom parser with old PostCSS AST. + +- Fixed AST normalization after using custom parser with old PostCSS AST. ## 8.4.14 -* Print “old plugin API” warning only if plugin was used (by @zardoy). + +- Print “old plugin API” warning only if plugin was used (by @zardoy). ## 8.4.13 -* Fixed `append()` error after using `.parent` (by Jordan Pittman). + +- Fixed `append()` error after using `.parent` (by Jordan Pittman). ## 8.4.12 -* Fixed `package.funding` to have same value between all PostCSS packages. + +- Fixed `package.funding` to have same value between all PostCSS packages. ## 8.4.11 -* Fixed `Declaration#raws.value` type. + +- Fixed `Declaration#raws.value` type. ## 8.4.10 -* Fixed `package.funding` URL format. + +- Fixed `package.funding` URL format. ## 8.4.9 -* Fixed `package.funding` (by Álvaro Mondéjar). + +- Fixed `package.funding` (by Álvaro Mondéjar). ## 8.4.8 -* Fixed end position in empty Custom Properties. + +- Fixed end position in empty Custom Properties. ## 8.4.7 -* Fixed `Node#warn()` type (by Masafumi Koba). -* Fixed comment removal in values after `,`. + +- Fixed `Node#warn()` type (by Masafumi Koba). +- Fixed comment removal in values after `,`. ## 8.4.6 -* Prevented comment removing when it change meaning of CSS. -* Fixed parsing space in last semicolon-less CSS Custom Properties. -* Fixed comment cleaning in CSS Custom Properties with space. -* Fixed throwing an error on `.root` access for plugin-less case. + +- Prevented comment removing when it change meaning of CSS. +- Fixed parsing space in last semicolon-less CSS Custom Properties. +- Fixed comment cleaning in CSS Custom Properties with space. +- Fixed throwing an error on `.root` access for plugin-less case. ## 8.4.5 -* Fixed `raws` types to make object extendable (by James Garbutt). -* Moved from Yarn 1 to pnpm. + +- Fixed `raws` types to make object extendable (by James Garbutt). +- Moved from Yarn 1 to pnpm. ## 8.4.4 -* Fixed absolute path in source map on zero plugins mode. + +- Fixed absolute path in source map on zero plugins mode. ## 8.4.3 -* Fixed `this.css.replace is not a function` error. + +- Fixed `this.css.replace is not a function` error. ## 8.4.2 -* Fixed previous source map support in zero plugins mode. + +- Fixed previous source map support in zero plugins mode. ## 8.4.1 -* Fixed `Stringifier` types (by James Garbutt). + +- Fixed `Stringifier` types (by James Garbutt). ## 8.4 “President Camio” -* Added ranges for errors and warnings (by Adaline Valentina Simonian). -* Added `Stringifier` types (by James Garbutt). -* Added `Processor` types. -* Removed `PostCSS does nothing` warning by lazy parser (Bogdan Dolin). -* Fixed `Node#walkRules()` types (by Aleks Hudochenkov). -* Fixed types `Root` and `Document` in result values (by James Garbutt). -* Reduced npm install size by 0.5 MB. -* Moved tests from Jest to `uvu` (by Andrey Kim). -* Fixed docs (by Paul Shryock). + +- Added ranges for errors and warnings (by Adaline Valentina Simonian). +- Added `Stringifier` types (by James Garbutt). +- Added `Processor` types. +- Removed `PostCSS does nothing` warning by lazy parser (Bogdan Dolin). +- Fixed `Node#walkRules()` types (by Aleks Hudochenkov). +- Fixed types `Root` and `Document` in result values (by James Garbutt). +- Reduced npm install size by 0.5 MB. +- Moved tests from Jest to `uvu` (by Andrey Kim). +- Fixed docs (by Paul Shryock). ## 8.3.11 -* Remove debugging code. + +- Remove debugging code. ## 8.3.10 -* Fixed `Maximum call stack` issue of some source maps (by Yeting Li). + +- Fixed `Maximum call stack` issue of some source maps (by Yeting Li). ## 8.3.9 -* Replaced `nanocolors` to `picocolors`. -* Reduced package size. + +- Replaced `nanocolors` to `picocolors`. +- Reduced package size. ## 8.3.8 -* Update `nanocolors`. + +- Update `nanocolors`. ## 8.3.7 -* Replaced `colorette` to `nanocolors`. -* Added bug field to `package.json` (by Christian Oliff). -* Improved docs (by Andrew Bruce and Paul Shryock). + +- Replaced `colorette` to `nanocolors`. +- Added bug field to `package.json` (by Christian Oliff). +- Improved docs (by Andrew Bruce and Paul Shryock). ## 8.3.6 -* Fixed column in `missed semicolon` error (by @Gusted). + +- Fixed column in `missed semicolon` error (by @Gusted). ## 8.3.5 -* Fixed broken AST detection. + +- Fixed broken AST detection. ## 8.3.4 -* Fixed broken AST detection. + +- Fixed broken AST detection. ## 8.3.3 -* Fixed broken AST on `postcss` dependency duplication in custom parsers. + +- Fixed broken AST on `postcss` dependency duplication in custom parsers. ## 8.3.2 -* Update changelog. + +- Update changelog. ## 8.3.1 -* Fixed false positives `PostCSS does nothing` warning on `syntax` option. + +- Fixed false positives `PostCSS does nothing` warning on `syntax` option. ## 8.3 “Duke Murmur” -* Added `Node#assign()` shortcut (by Jonathan Neal). -* Added experimental `Document` node to AST (by Aleks Hudochenkov). -* Moved to faster fork of `source-map` (by Valentin Semirulnik). + +- Added `Node#assign()` shortcut (by Jonathan Neal). +- Added experimental `Document` node to AST (by Aleks Hudochenkov). +- Moved to faster fork of `source-map` (by Valentin Semirulnik). ## 8.2.15 -* Fixed `list` type definitions (by @n19htz). + +- Fixed `list` type definitions (by @n19htz). ## 8.2.14 -* Removed `source-map` from client-side bundle (by Barak Igal). + +- Removed `source-map` from client-side bundle (by Barak Igal). ## 8.2.13 -* Fixed ReDoS vulnerabilities in source map parsing (by Yeting Li). + +- Fixed ReDoS vulnerabilities in source map parsing (by Yeting Li). ## 8.2.12 -* Fixed `package.json` exports. + +- Fixed `package.json` exports. ## 8.2.11 -* Fixed `DEP0148` warning in Node.js 16. -* Fixed docs (by @semiromid). + +- Fixed `DEP0148` warning in Node.js 16. +- Fixed docs (by @semiromid). ## 8.2.10 -* Fixed ReDoS vulnerabilities in source map parsing. -* Fixed webpack 5 support (by Barak Igal). -* Fixed docs (by Roeland Moors). + +- Fixed ReDoS vulnerabilities in source map parsing. +- Fixed webpack 5 support (by Barak Igal). +- Fixed docs (by Roeland Moors). ## 8.2.9 -* Exported `NodeErrorOptions` type (by Rouven Weßling). + +- Exported `NodeErrorOptions` type (by Rouven Weßling). ## 8.2.8 -* Fixed browser builds in webpack 4 (by Matt Jones). + +- Fixed browser builds in webpack 4 (by Matt Jones). ## 8.2.7 -* Fixed browser builds in webpack 5 (by Matt Jones). + +- Fixed browser builds in webpack 5 (by Matt Jones). ## 8.2.6 -* Fixed `Maximum call stack size exceeded` in `Node#toJSON`. -* Fixed docs (by inokawa). + +- Fixed `Maximum call stack size exceeded` in `Node#toJSON`. +- Fixed docs (by inokawa). ## 8.2.5 -* Fixed escaped characters handling in `list.split` (by Natalie Weizenbaum). + +- Fixed escaped characters handling in `list.split` (by Natalie Weizenbaum). ## 8.2.4 -* Added plugin name to `postcss.plugin()` warning (by Tom Williams). -* Fixed docs (by Bill Columbia). + +- Added plugin name to `postcss.plugin()` warning (by Tom Williams). +- Fixed docs (by Bill Columbia). ## 8.2.3 -* Fixed `JSON.stringify(Node[])` support (by Niklas Mischkulnig). + +- Fixed `JSON.stringify(Node[])` support (by Niklas Mischkulnig). ## 8.2.2 -* Fixed CSS-in-JS support (by James Garbutt). -* Fixed plugin types (by Ludovico Fischer). -* Fixed `Result#warn()` types. + +- Fixed CSS-in-JS support (by James Garbutt). +- Fixed plugin types (by Ludovico Fischer). +- Fixed `Result#warn()` types. ## 8.2.1 -* Fixed `Node#toJSON()` and `postcss.fromJSON()` (by Niklas Mischkulnig). + +- Fixed `Node#toJSON()` and `postcss.fromJSON()` (by Niklas Mischkulnig). ## 8.2 “Prince Orobas” -* Added `Node#toJSON()` and `postcss.fromJSON()` (by Niklas Mischkulnig). + +- Added `Node#toJSON()` and `postcss.fromJSON()` (by Niklas Mischkulnig). ## 8.1.14 -* Fixed parser performance regression. + +- Fixed parser performance regression. ## 8.1.13 -* Fixed broken AST after moving nodes in visitor API. + +- Fixed broken AST after moving nodes in visitor API. ## 8.1.12 -* Fixed Autoprefixer regression. + +- Fixed Autoprefixer regression. ## 8.1.11 -* Added PostCSS update suggestion on unknown event in plugin. + +- Added PostCSS update suggestion on unknown event in plugin. ## 8.1.10 -* Fixed `LazyResult` type export (by Evan You). -* Fixed `LazyResult` type compatibility with `Promise` (by Anton Kastritskiy). + +- Fixed `LazyResult` type export (by Evan You). +- Fixed `LazyResult` type compatibility with `Promise` (by Anton Kastritskiy). ## 8.1.9 -* Reduced dependencies number (by Bogdan Chadkin). + +- Reduced dependencies number (by Bogdan Chadkin). ## 8.1.8 -* Fixed `LazyResult` type compatibility with `Promise` (by Ludovico Fischer). -* Fixed HTTPS links in documentation. + +- Fixed `LazyResult` type compatibility with `Promise` (by Ludovico Fischer). +- Fixed HTTPS links in documentation. ## 8.1.7 -* Fixed `import` support in TypeScript (by Remco Haszing). + +- Fixed `import` support in TypeScript (by Remco Haszing). ## 8.1.6 -* Reverted `package.exports` Node.js 15 fix. + +- Reverted `package.exports` Node.js 15 fix. ## 8.1.5 -* Fixed Node.js 15 warning (by 沈鸿飞). + +- Fixed Node.js 15 warning (by 沈鸿飞). ## 8.1.4 -* Fixed TypeScript definition (by Arthur Petrie). + +- Fixed TypeScript definition (by Arthur Petrie). ## 8.1.3 -* Added `package.types`. + +- Added `package.types`. ## 8.1.2 -* Fixed API docs (by Arthur Petrie). -* Improved plugin guide (by Yunus Gaziev). -* Prepared code base for Deno support (by Oscar Otero). + +- Fixed API docs (by Arthur Petrie). +- Improved plugin guide (by Yunus Gaziev). +- Prepared code base for Deno support (by Oscar Otero). ## 8.1.1 -* Updated funding link. + +- Updated funding link. ## 8.1 “Duke Gemory” -* Added `Once` and `OnceExit` events. -* Fixed `Root` and `RootExit` events re-visiting. -* Fixed node re-visiting on deep children changes. -* Added docs for visitor API events. + +- Added `Once` and `OnceExit` events. +- Fixed `Root` and `RootExit` events re-visiting. +- Fixed node re-visiting on deep children changes. +- Added docs for visitor API events. ## 8.0.9 -* Replace prototype in PostCSS 7 nodes instead of recreating them. -* Added missed `Transformer` to exported types (by Pierre-Marie Dartus). + +- Replace prototype in PostCSS 7 nodes instead of recreating them. +- Added missed `Transformer` to exported types (by Pierre-Marie Dartus). ## 8.0.8 -* Fix `8.0.7` regression on PostCSS 7 nodes converting (by Adam Wathan). + +- Fix `8.0.7` regression on PostCSS 7 nodes converting (by Adam Wathan). ## 8.0.7 -* Fixed compatibility issue with mixin AST with PostCSS 7 and 8 nodes. -* Added migration guide translation to Chinese to the warning. + +- Fixed compatibility issue with mixin AST with PostCSS 7 and 8 nodes. +- Added migration guide translation to Chinese to the warning. ## 8.0.6 -* Fixed child adding methods in `Container`. + +- Fixed child adding methods in `Container`. ## 8.0.5 -* Update changelog. + +- Update changelog. ## 8.0.4 -* Fixed `Cannot read property 'line' of null` error. -* Fixed source map support for declarations. + +- Fixed `Cannot read property 'line' of null` error. +- Fixed source map support for declarations. ## 8.0.3 -* Fixed client-side bundling support. + +- Fixed client-side bundling support. ## 8.0.2 -* Fixed plugin packs support. + +- Fixed plugin packs support. ## 8.0.1 -* Updated `Processor#version`. + +- Updated `Processor#version`. ## 8.0 “President Ose” -* Removed support for Node.js 6.x, 8.x, 11.x, and 13.x versions. -* Removed `postcss.vendor` helpers. -* Deprecated `postcss.plugin()` API. -* Treats `sourceMap.sources` as URL instead of file path. -* Plugins and runners must have `postcss` in `peerDependencies`. -* Prohibited to extend PostCSS AST classes. -* Moved from JSDoc to TypeDoc. -* Moved unknown source from counter to random IDs. -* Added visitor API for plugins (by Alexey Bondarenko). -* Added ES modules support. -* Added named exports for public classes `const { Rule } = require('postcss)`. -* Added `position.url` to `Node#origin()` result. -* Added `opts.maps.absolute = true` option. -* Added `opts.maps.annotation = (file, root) => url` option support. -* Added `Node#source.offset` (by Ayaz Zaynutdinov). -* Added `Declaration#variable`. -* Added JSON source map support. -* Added index source map support. -* Added `Declaration#value` auto-converting to string. -* Fixed parsing `{}` in at-rule parameters. -* Fixed parsing empty Custom Properties. `--foo: ;` will have ` ` value. -* Fixed building PostCSS with Rollup (by MapGrid). -* Fixed TypeScript types. -* Fixed source map relative paths. -* Fixed calling `replaceWith` with input replaced node (by Joseph Kaptur). -* Improved “Writing a PostCSS Plugin” docs (by Alexey Bondarenko). -* Removed Babel from the project’s release process. -* Removed docs from npm package. -* Replaced `chalk` to `colorette`. + +- Removed support for Node.js 6.x, 8.x, 11.x, and 13.x versions. +- Removed `postcss.vendor` helpers. +- Deprecated `postcss.plugin()` API. +- Treats `sourceMap.sources` as URL instead of file path. +- Plugins and runners must have `postcss` in `peerDependencies`. +- Prohibited to extend PostCSS AST classes. +- Moved from JSDoc to TypeDoc. +- Moved unknown source from counter to random IDs. +- Added visitor API for plugins (by Alexey Bondarenko). +- Added ES modules support. +- Added named exports for public classes `const { Rule } = require('postcss)`. +- Added `position.url` to `Node#origin()` result. +- Added `opts.maps.absolute = true` option. +- Added `opts.maps.annotation = (file, root) => url` option support. +- Added `Node#source.offset` (by Ayaz Zaynutdinov). +- Added `Declaration#variable`. +- Added JSON source map support. +- Added index source map support. +- Added `Declaration#value` auto-converting to string. +- Fixed parsing `{}` in at-rule parameters. +- Fixed parsing empty Custom Properties. `--foo: ;` will have ` ` value. +- Fixed building PostCSS with Rollup (by MapGrid). +- Fixed TypeScript types. +- Fixed source map relative paths. +- Fixed calling `replaceWith` with input replaced node (by Joseph Kaptur). +- Improved “Writing a PostCSS Plugin” docs (by Alexey Bondarenko). +- Removed Babel from the project’s release process. +- Removed docs from npm package. +- Replaced `chalk` to `colorette`. ## 7.0.38 -* Update `Processor#version`. + +- Update `Processor#version`. ## 7.0.37 -* Backport `chalk` to `nanocolors` migration. + +- Backport `chalk` to `nanocolors` migration. ## 7.0.36 -* Backport ReDoS vulnerabilities from PostCSS 8. + +- Backport ReDoS vulnerabilities from PostCSS 8. ## 7.0.35 -* Add migration guide link to PostCSS 8 error text. + +- Add migration guide link to PostCSS 8 error text. ## 7.0.34 -* Fix compatibility with `postcss-scss` 2. + +- Fix compatibility with `postcss-scss` 2. ## 7.0.33 -* Add error message for PostCSS 8 plugins. + +- Add error message for PostCSS 8 plugins. ## 7.0.32 -* Fix error message (by @admosity). + +- Fix error message (by @admosity). ## 7.0.31 -* Use only the latest source map annotation (by Emmanouil Zoumpoulakis). + +- Use only the latest source map annotation (by Emmanouil Zoumpoulakis). ## 7.0.30 -* Fix TypeScript definition (by Natalie Weizenbaum). + +- Fix TypeScript definition (by Natalie Weizenbaum). ## 7.0.29 -* Update `Processor#version`. + +- Update `Processor#version`. ## 7.0.28 -* Fix TypeScript definition (by Natalie Weizenbaum). + +- Fix TypeScript definition (by Natalie Weizenbaum). ## 7.0.27 -* Fix TypeScript definition (by Natalie Weizenbaum). + +- Fix TypeScript definition (by Natalie Weizenbaum). ## 7.0.26 -* Fix TypeScript definition (by Natalie Weizenbaum). + +- Fix TypeScript definition (by Natalie Weizenbaum). ## 7.0.25 -* Fix absolute path support for Windows (by Tom Raviv). + +- Fix absolute path support for Windows (by Tom Raviv). ## 7.0.24 -* Fix TypeScript definition (by Keith Cirkel). + +- Fix TypeScript definition (by Keith Cirkel). ## 7.0.23 -* Update `Processor#version`. + +- Update `Processor#version`. ## 7.0.22 -* Add funding link for `npm fund`. + +- Add funding link for `npm fund`. ## 7.0.21 -* Revert passing `nodes` property to node constructor. + +- Revert passing `nodes` property to node constructor. ## 7.0.20 -* Allow to pass PostCSS’s nodes in `nodes` property to node constructor. + +- Allow to pass PostCSS’s nodes in `nodes` property to node constructor. ## 7.0.19 -* Fix passing `nodes` property to node constructor. + +- Fix passing `nodes` property to node constructor. ## 7.0.18 -* Fix TypeScript type definitions (by Jan Buschtöns). + +- Fix TypeScript type definitions (by Jan Buschtöns). ## 7.0.17 -* Fix TypeScript type definitions (by Bob Matcuk and Jan Buschtöns). + +- Fix TypeScript type definitions (by Bob Matcuk and Jan Buschtöns). ## 7.0.16 -* Revert Custom Properties fix until PostCSS 8.0. + +- Revert Custom Properties fix until PostCSS 8.0. ## 7.0.15 -* Fix Custom Properties support (by Ivan Solovev). + +- Fix Custom Properties support (by Ivan Solovev). ## 7.0.14 -* Fix tokenizer for `postcss-less` (by Matt Lyons). + +- Fix tokenizer for `postcss-less` (by Matt Lyons). ## 7.0.13 -* Fix parsing regression in 7.0.12 for comments between property and value. + +- Fix parsing regression in 7.0.12 for comments between property and value. ## 7.0.12 -* Fix parsing broken CSS with two words in declaration property. + +- Fix parsing broken CSS with two words in declaration property. ## 7.0.11 -* Fix source maps on declaration semicolon (by Niklas Mischkulnig). + +- Fix source maps on declaration semicolon (by Niklas Mischkulnig). ## 7.0.10 -* Fix source maps (by Niklas Mischkulnig). + +- Fix source maps (by Niklas Mischkulnig). ## 7.0.9 -* Increase stringifing performance for non-raws AST. + +- Increase stringifing performance for non-raws AST. ## 7.0.8 -* Fix TypeScript definitions (by Ankur Oberoi). -* Use `support-colors` 6.0. + +- Fix TypeScript definitions (by Ankur Oberoi). +- Use `support-colors` 6.0. ## 7.0.7 -* Extend `Error` in `CssSyntaxError`. + +- Extend `Error` in `CssSyntaxError`. ## 7.0.6 -* Fix parsing files with BOM (by Veniamin Krol). + +- Fix parsing files with BOM (by Veniamin Krol). ## 7.0.5 -* Reduce npm package size (by Gilad Peleg). + +- Reduce npm package size (by Gilad Peleg). ## 7.0.4 -* Fix safe parser regression. + +- Fix safe parser regression. ## 7.0.3 -* Fix tokenizer extendability (by Andrew Powell). -* Reduce npm package size. + +- Fix tokenizer extendability (by Andrew Powell). +- Reduce npm package size. ## 7.0.2 -* Fix warning text (by Rui Pedro M Lima). + +- Fix warning text (by Rui Pedro M Lima). ## 7.0.1 -* Fix JSDoc (by Steven Lambert). + +- Fix JSDoc (by Steven Lambert). ## 7.0 “President Amy” -* Remove Node.js 9 and Node.js 4 support. -* Remove IE and “dead” browsers support for client-side Babel transpiling. -* Add CSS position on error happened inside `walk()` (by Nikhil Gaba). -* Add `LazyResult#finally` (by Igor Kamyshev). -* Add warning on calling PostCSS without plugins and syntax options. -* Reduce client-side size. + +- Remove Node.js 9 and Node.js 4 support. +- Remove IE and “dead” browsers support for client-side Babel transpiling. +- Add CSS position on error happened inside `walk()` (by Nikhil Gaba). +- Add `LazyResult#finally` (by Igor Kamyshev). +- Add warning on calling PostCSS without plugins and syntax options. +- Reduce client-side size. ## 6.0.23 -* Fix parsing nested at-rules without semicolon, params, and spaces. -* Fix docs (by Kevin Schiffer and Pat Cavit). + +- Fix parsing nested at-rules without semicolon, params, and spaces. +- Fix docs (by Kevin Schiffer and Pat Cavit). ## 6.0.22 -* Fix `Node#prev` and `Node#next` on missed parent. + +- Fix `Node#prev` and `Node#next` on missed parent. ## 6.0.21 -* Rename Chinese docs to fix `yarnpkg.com` issue. + +- Rename Chinese docs to fix `yarnpkg.com` issue. ## 6.0.20 -* Better error message on `null` as input CSS. + +- Better error message on `null` as input CSS. ## 6.0.19 -* Fix TypeScript definitions for source maps (by Oleh Kuchuk). -* Fix `source` field in TypeScript definitions (by Sylvain Pollet-Villard). + +- Fix TypeScript definitions for source maps (by Oleh Kuchuk). +- Fix `source` field in TypeScript definitions (by Sylvain Pollet-Villard). ## 6.0.18 -* Use primitive object in TypeScript definitions (by Sylvain Pollet-Villard). + +- Use primitive object in TypeScript definitions (by Sylvain Pollet-Villard). ## 6.0.17 -* Fix parsing comment in selector between word tokens (by Oleh Kuchuk). + +- Fix parsing comment in selector between word tokens (by Oleh Kuchuk). ## 6.0.16 -* Fix warning text (by Michael Keller). + +- Fix warning text (by Michael Keller). ## 6.0.15 -* Add warning about missed `from` option on `process().then()` call. -* Add IE 10 support. + +- Add warning about missed `from` option on `process().then()` call. +- Add IE 10 support. ## 6.0.14 -* Fix TypeScript definitions (by Jed Mao). + +- Fix TypeScript definitions (by Jed Mao). ## 6.0.13 -* Fix TypeScript definitions for case of multiple PostCSS versions + +- Fix TypeScript definitions for case of multiple PostCSS versions in `node_modules` (by Chris Eppstein). -* Use `source-map` 0.6. +- Use `source-map` 0.6. ## 6.0.12 -* Don’t copy `*` hack to declaration indent. + +- Don’t copy `*` hack to declaration indent. ## 6.0.11 -* Add upper case `!IMPORTANT` support. + +- Add upper case `!IMPORTANT` support. ## 6.0.10 -* Reduce PostCSS size in webpack bundle. + +- Reduce PostCSS size in webpack bundle. ## 6.0.9 -* Improve error message for plugin with old PostCSS (by Igor Adamenko). + +- Improve error message for plugin with old PostCSS (by Igor Adamenko). ## 6.0.8 -* Fix Node.js 4.2.2 support. + +- Fix Node.js 4.2.2 support. ## 6.0.7 -* Fix base64 decoding for old Node.js and browser. + +- Fix base64 decoding for old Node.js and browser. ## 6.0.6 -* Fix `end` position in at-rule without semicolon (by Oleh Kuchuk). + +- Fix `end` position in at-rule without semicolon (by Oleh Kuchuk). ## 6.0.5 -* Move Babel config from `package.json` for `node_modules` compiling cases. + +- Move Babel config from `package.json` for `node_modules` compiling cases. ## 6.0.4 -* Fix parsing `;;` after rules. -* Use Chalk 2.0. + +- Fix parsing `;;` after rules. +- Use Chalk 2.0. ## 6.0.3 -* Fix escape sequences parsing (by Oleh Kuchuk). -* Added ability to force disable colors with an environment variable. -* Improved color detection of some terminal apps. + +- Fix escape sequences parsing (by Oleh Kuchuk). +- Added ability to force disable colors with an environment variable. +- Improved color detection of some terminal apps. ## 6.0.2 -* Keep `raws.before` on moving `Root` children to new `Root`. + +- Keep `raws.before` on moving `Root` children to new `Root`. ## 6.0.1 -* Fix parser extensibility to use it in Safe Parser. + +- Fix parser extensibility to use it in Safe Parser. ## 6.0 “Marquis Orias” -* Remove node.js 0.12 support. -* Remove deprecated method from PostCSS 4. -* Insert methods remove child from previous parent, instead of closing. -* Insert methods and cloning doesn’t clean `raws` anymore. -* Methods `moveTo`, `moveAfter`, `moveBefore` were deprecated. -* Options was changed in `Plugin#process(css, processOptions, pluginOptions)`. -* Add stream parser to reduce memory usage (by Oleh Kuchuk). -* Add `before()`/`after()` shortcuts for `node.parent.insertBefore(node, x)`. -* Add `Rule#raws.ownSemicolon` for semicolon after templates for `@apply`. -* Use `babel-preset-env` to compile npm package. -* Remove `js-base64` from dependencies (by Roman Dvornov). -* Fix error message on single `:` in CSS. -* Move tests to Jest. -* Clean up test (by Gabriel Kalani). + +- Remove node.js 0.12 support. +- Remove deprecated method from PostCSS 4. +- Insert methods remove child from previous parent, instead of closing. +- Insert methods and cloning doesn’t clean `raws` anymore. +- Methods `moveTo`, `moveAfter`, `moveBefore` were deprecated. +- Options was changed in `Plugin#process(css, processOptions, pluginOptions)`. +- Add stream parser to reduce memory usage (by Oleh Kuchuk). +- Add `before()`/`after()` shortcuts for `node.parent.insertBefore(node, x)`. +- Add `Rule#raws.ownSemicolon` for semicolon after templates for `@apply`. +- Use `babel-preset-env` to compile npm package. +- Remove `js-base64` from dependencies (by Roman Dvornov). +- Fix error message on single `:` in CSS. +- Move tests to Jest. +- Clean up test (by Gabriel Kalani). ## 5.2.18 -* Fix TypeScript definitions for case of multiple PostCSS versions + +- Fix TypeScript definitions for case of multiple PostCSS versions in `node_modules` (by Chris Eppstein). ## 5.2.17 -* Add `postcss-sass` suggestion to syntax error on `.sass` input. + +- Add `postcss-sass` suggestion to syntax error on `.sass` input. ## 5.2.16 -* Better error on wrong argument in node constructor. + +- Better error on wrong argument in node constructor. ## 5.2.15 -* Fix TypeScript definitions (by bumbleblym). + +- Fix TypeScript definitions (by bumbleblym). ## 5.2.14 -* Fix browser bundle building in webpack (by janschoenherr). + +- Fix browser bundle building in webpack (by janschoenherr). ## 5.2.13 -* Do not add comment to important raws. -* Fix JSDoc (by Dmitry Semigradsky). + +- Do not add comment to important raws. +- Fix JSDoc (by Dmitry Semigradsky). ## 5.2.12 -* Fix typo in deprecation message (by Garet McKinley). + +- Fix typo in deprecation message (by Garet McKinley). ## 5.2.11 -* Fix TypeScript definitions (by Jed Mao). + +- Fix TypeScript definitions (by Jed Mao). ## 5.2.10 -* Fix TypeScript definitions (by Jed Mao). + +- Fix TypeScript definitions (by Jed Mao). ## 5.2.9 -* Update TypeScript definitions (by Jed Mao). + +- Update TypeScript definitions (by Jed Mao). ## 5.2.8 -* Fix error message (by Ben Briggs). + +- Fix error message (by Ben Briggs). ## 5.2.7 -* Better error message on syntax object in plugins list. + +- Better error message on syntax object in plugins list. ## 5.2.6 -* Fix `postcss.vendor` for values with spaces (by 刘祺). + +- Fix `postcss.vendor` for values with spaces (by 刘祺). ## 5.2.5 -* Better error message on unclosed string (by Ben Briggs). + +- Better error message on unclosed string (by Ben Briggs). ## 5.2.4 -* Improve terminal CSS syntax highlight (by Simon Lydell). + +- Improve terminal CSS syntax highlight (by Simon Lydell). ## 5.2.3 -* Better color highlight in syntax error code frame. -* Fix color highlight support in old systems. + +- Better color highlight in syntax error code frame. +- Fix color highlight support in old systems. ## 5.2.2 -* Update `Processor#version`. + +- Update `Processor#version`. ## 5.2.1 -* Fix source map path for CSS without `from` option (by Michele Locati). + +- Fix source map path for CSS without `from` option (by Michele Locati). ## 5.2 “Duke Vapula” -* Add syntax highlight to code frame in syntax error (by Andrey Popp). -* Use Babel code frame style and size in syntax error. -* Add `[` and `]` tokens to parse `[attr=;] {}` correctly. -* Add `ignoreErrors` options to tokenizer (by Andrey Popp). -* Fix error position on tab indent (by Simon Lydell). + +- Add syntax highlight to code frame in syntax error (by Andrey Popp). +- Use Babel code frame style and size in syntax error. +- Add `[` and `]` tokens to parse `[attr=;] {}` correctly. +- Add `ignoreErrors` options to tokenizer (by Andrey Popp). +- Fix error position on tab indent (by Simon Lydell). ## 5.1.2 -* Suggests SCSS/Less parsers on parse errors depends on file extension. + +- Suggests SCSS/Less parsers on parse errors depends on file extension. ## 5.1.1 -* Fix TypeScript definitions (by Efremov Alexey). + +- Fix TypeScript definitions (by Efremov Alexey). ## 5.1 “King and President Zagan” -* Add URI in source map support (by Mark Finger). -* Add `map.from` option (by Mark Finger). -* Add `` mappings for nodes without source (by Bogdan Chadkin). -* Add function value support to `map.prev` option (by Chris Montoro). -* Add declaration value type check in shortcut creating (by 刘祺). -* `Result#warn` now returns new created warning. -* Don’t call plugin creator in `postcss.plugin` call. -* Add source maps to PostCSS ES5 build. -* Add JSDoc to PostCSS classes. -* Clean npm package from unnecessary docs. + +- Add URI in source map support (by Mark Finger). +- Add `map.from` option (by Mark Finger). +- Add `` mappings for nodes without source (by Bogdan Chadkin). +- Add function value support to `map.prev` option (by Chris Montoro). +- Add declaration value type check in shortcut creating (by 刘祺). +- `Result#warn` now returns new created warning. +- Don’t call plugin creator in `postcss.plugin` call. +- Add source maps to PostCSS ES5 build. +- Add JSDoc to PostCSS classes. +- Clean npm package from unnecessary docs. ## 5.0.21 -* Fix support with input source mao with `utf8` encoding name. + +- Fix support with input source mao with `utf8` encoding name. ## 5.0.20 -* Fix between raw value parsing (by David Clark). -* Update TypeScript definitions (by Jed Mao). -* Clean fake node.source after `append(string)`. + +- Fix between raw value parsing (by David Clark). +- Update TypeScript definitions (by Jed Mao). +- Clean fake node.source after `append(string)`. ## 5.0.19 -* Fix indent-based syntaxes support. + +- Fix indent-based syntaxes support. ## 5.0.18 -* Parse new lines according W3C CSS syntax specification. + +- Parse new lines according W3C CSS syntax specification. ## 5.0.17 -* Fix options argument in `Node#warn` (by Ben Briggs). -* Fix TypeScript definitions (by Jed Mao). + +- Fix options argument in `Node#warn` (by Ben Briggs). +- Fix TypeScript definitions (by Jed Mao). ## 5.0.16 -* Fix CSS syntax error position on unclosed quotes. + +- Fix CSS syntax error position on unclosed quotes. ## 5.0.15 -* Fix `Node#clone()` on `null` value somewhere in node. + +- Fix `Node#clone()` on `null` value somewhere in node. ## 5.0.14 -* Allow to use PostCSS in webpack bundle without JSON loader. + +- Allow to use PostCSS in webpack bundle without JSON loader. ## 5.0.13 -* Fix `index` and `word` options in `Warning#toString` (by Bogdan Chadkin). -* Fix input source content loading in errors. -* Fix map options on using `LazyResult` as input CSS. -* 100% test coverage. -* Use Babel 6. + +- Fix `index` and `word` options in `Warning#toString` (by Bogdan Chadkin). +- Fix input source content loading in errors. +- Fix map options on using `LazyResult` as input CSS. +- 100% test coverage. +- Use Babel 6. ## 5.0.12 -* Allow passing a previous map with no mappings (by Andreas Lind). + +- Allow passing a previous map with no mappings (by Andreas Lind). ## 5.0.11 -* Increase plugins performance by 1.5 times. + +- Increase plugins performance by 1.5 times. ## 5.0.10 -* Fix warning from nodes without source. + +- Fix warning from nodes without source. ## 5.0.9 -* Fix source map type detection (by @asan). + +- Fix source map type detection (by @asan). ## 5.0.8 -* Fixed a missed step in `5.0.7` that caused the module to be published as + +- Fixed a missed step in `5.0.7` that caused the module to be published as ES6 code. ## 5.0.7 -* PostCSS now requires that node 0.12 is installed via the engines property + +- PostCSS now requires that node 0.12 is installed via the engines property in package.json (by Howard Zuo). ## 5.0.6 -* Fix parsing nested at-rule without semicolon (by Matt Drake). -* Trim `Declaration#value` (by Bogdan Chadkin). + +- Fix parsing nested at-rule without semicolon (by Matt Drake). +- Trim `Declaration#value` (by Bogdan Chadkin). ## 5.0.5 -* Fix multi-tokens property parsing (by Matt Drake). + +- Fix multi-tokens property parsing (by Matt Drake). ## 5.0.4 -* Fix start position in `Root#source`. -* Fix source map annotation, when CSS uses `\r\n` (by Mohammad Younes). + +- Fix start position in `Root#source`. +- Fix source map annotation, when CSS uses `\r\n` (by Mohammad Younes). ## 5.0.3 -* Fix `url()` parsing. -* Fix using `selectors` in `Rule` constructor. -* Add start source to `Root` node. + +- Fix `url()` parsing. +- Fix using `selectors` in `Rule` constructor. +- Add start source to `Root` node. ## 5.0.2 -* Fix `remove(index)` to be compatible with 4.x plugin. + +- Fix `remove(index)` to be compatible with 4.x plugin. ## 5.0.1 -* Fix PostCSS 4.x plugins compatibility. -* Fix type definition loading (by Jed Mao). + +- Fix PostCSS 4.x plugins compatibility. +- Fix type definition loading (by Jed Mao). ## 5.0 “President Valac” -* Remove `safe` option. Move Safe Parser to separate project. -* `Node#toString` does not include `before` for root nodes. -* Remove plugin returning `Root` API. -* Remove Promise polyfill for node.js 0.10. -* Deprecate `eachInside`, `eachDecl`, `eachRule`, `eachAtRule` and `eachComment` + +- Remove `safe` option. Move Safe Parser to separate project. +- `Node#toString` does not include `before` for root nodes. +- Remove plugin returning `Root` API. +- Remove Promise polyfill for node.js 0.10. +- Deprecate `eachInside`, `eachDecl`, `eachRule`, `eachAtRule` and `eachComment` in favor of `walk`, `walkDecls`, `walkRules`, `walkAtRules` and `walkComments` (by Jed Mao). -* Deprecate `Container#remove` and `Node#removeSelf` +- Deprecate `Container#remove` and `Node#removeSelf` in favor of `Container#removeChild` and `Node#remove` (by Ben Briggs). -* Deprecate `Node#replace` in favor of `replaceWith` (by Ben Briggs). -* Deprecate raw properties in favor of `Node#raws` object. -* Deprecate `Node#style` in favor of `raw`. -* Deprecate `CssSyntaxError#generated` in favor of `input`. -* Deprecate `Node#cleanStyles` in favor of `cleanRaws`. -* Deprecate `Root#prevMap` in favor of `Root.source.input.map`. -* Add `syntax`, `parser` and `stringifier` options for Custom Syntaxes. -* Add stringifier option to `Node#toString`. -* Add `Result#content` alias for non-CSS syntaxes. -* Add `plugin.process(css)` shortcut to every plugin function (by Ben Briggs). -* Add multiple nodes support to insert methods (by Jonathan Neal). -* Add `Node#warn` shortcut (by Ben Briggs). -* Add `word` and `index` options to errors and warnings (by David Clark). -* Add `line`, `column` properties to `Warning`. -* Use `supports-color` library to detect color support in error output. -* Add type definitions for TypeScript plugin developers (by Jed Mao). -* `Rule#selectors` setter detects separators. -* Add `postcss.stringify` method. -* Throw descriptive errors for incorrectly formatted plugins. -* Add docs to npm release. -* Fix `url()` parsing. -* Fix Windows support (by Jed Mao). +- Deprecate `Node#replace` in favor of `replaceWith` (by Ben Briggs). +- Deprecate raw properties in favor of `Node#raws` object. +- Deprecate `Node#style` in favor of `raw`. +- Deprecate `CssSyntaxError#generated` in favor of `input`. +- Deprecate `Node#cleanStyles` in favor of `cleanRaws`. +- Deprecate `Root#prevMap` in favor of `Root.source.input.map`. +- Add `syntax`, `parser` and `stringifier` options for Custom Syntaxes. +- Add stringifier option to `Node#toString`. +- Add `Result#content` alias for non-CSS syntaxes. +- Add `plugin.process(css)` shortcut to every plugin function (by Ben Briggs). +- Add multiple nodes support to insert methods (by Jonathan Neal). +- Add `Node#warn` shortcut (by Ben Briggs). +- Add `word` and `index` options to errors and warnings (by David Clark). +- Add `line`, `column` properties to `Warning`. +- Use `supports-color` library to detect color support in error output. +- Add type definitions for TypeScript plugin developers (by Jed Mao). +- `Rule#selectors` setter detects separators. +- Add `postcss.stringify` method. +- Throw descriptive errors for incorrectly formatted plugins. +- Add docs to npm release. +- Fix `url()` parsing. +- Fix Windows support (by Jed Mao). ## 4.1.16 -* Fix errors without stack trace. + +- Fix errors without stack trace. ## 4.1.15 -* Allow asynchronous plugins to change processor plugins list (by Ben Briggs). + +- Allow asynchronous plugins to change processor plugins list (by Ben Briggs). ## 4.1.14 -* Fix for plugins packs defined by `postcss.plugin`. + +- Fix for plugins packs defined by `postcss.plugin`. ## 4.1.13 -* Fix input inlined source maps with UTF-8 encoding. + +- Fix input inlined source maps with UTF-8 encoding. ## 4.1.12 -* Update Promise polyfill. + +- Update Promise polyfill. ## 4.1.11 -* Fix error message on wrong plugin format. + +- Fix error message on wrong plugin format. ## 4.1.10 -* Fix Promise behavior on sync plugin errors. -* Automatically fill `plugin` field in `CssSyntaxError`. -* Fix warning message (by Ben Briggs). + +- Fix Promise behavior on sync plugin errors. +- Automatically fill `plugin` field in `CssSyntaxError`. +- Fix warning message (by Ben Briggs). ## 4.1.9 -* Speed up `node.clone()`. + +- Speed up `node.clone()`. ## 4.1.8 -* Accepts `Processor` instance in `postcss()` constructor too. + +- Accepts `Processor` instance in `postcss()` constructor too. ## 4.1.7 -* Speed up `postcss.list` (by Bogdan Chadkin). + +- Speed up `postcss.list` (by Bogdan Chadkin). ## 4.1.6 -* Fix Promise behavior on parsing error. + +- Fix Promise behavior on parsing error. ## 4.1.5 -* Parse at-words in declaration values. + +- Parse at-words in declaration values. ## 4.1.4 -* Fix Promise polyfill dependency (by Anton Yakushev and Matija Marohnić). + +- Fix Promise polyfill dependency (by Anton Yakushev and Matija Marohnić). ## 4.1.3 -* Add Promise polyfill for node.js 0.10 and IE. + +- Add Promise polyfill for node.js 0.10 and IE. ## 4.1.2 -* List helpers can be accessed independently `var space = postcss.list.space`. + +- List helpers can be accessed independently `var space = postcss.list.space`. ## 4.1.1 -* Show deprecated message only once. + +- Show deprecated message only once. ## 4.1 “Marquis Andras” -* Asynchronous plugin support. -* Add warnings from plugins and `Result#messages`. -* Add `postcss.plugin()` to create plugins with a standard API. -* Insert nodes by CSS string. -* Show version warning message on error from an outdated plugin. -* Send `Result` instance to plugins as the second argument. -* Add `CssSyntaxError#plugin`. -* Add `CssSyntaxError#showSourceCode()`. -* Add `postcss.list` and `postcss.vendor` aliases. -* Add `Processor#version`. -* Parse wrong closing bracket. -* Parse `!important` statement with spaces and comments inside (by Ben Briggs). -* Throw an error on declaration without `prop` or `value` (by Philip Peterson). -* Fix source map mappings position. -* Add indexed source map support. -* Always set `error.generated`. -* Clean all source map annotation comments. + +- Asynchronous plugin support. +- Add warnings from plugins and `Result#messages`. +- Add `postcss.plugin()` to create plugins with a standard API. +- Insert nodes by CSS string. +- Show version warning message on error from an outdated plugin. +- Send `Result` instance to plugins as the second argument. +- Add `CssSyntaxError#plugin`. +- Add `CssSyntaxError#showSourceCode()`. +- Add `postcss.list` and `postcss.vendor` aliases. +- Add `Processor#version`. +- Parse wrong closing bracket. +- Parse `!important` statement with spaces and comments inside (by Ben Briggs). +- Throw an error on declaration without `prop` or `value` (by Philip Peterson). +- Fix source map mappings position. +- Add indexed source map support. +- Always set `error.generated`. +- Clean all source map annotation comments. ## 4.0.6 -* Remove `babel` from released package dependencies (by Andres Suarez). + +- Remove `babel` from released package dependencies (by Andres Suarez). ## 4.0.5 -* Fix error message on double colon in declaration. + +- Fix error message on double colon in declaration. ## 4.0.4 -* Fix indent detection in some rare cases. + +- Fix indent detection in some rare cases. ## 4.0.3 -* Faster API with 6to5 Loose mode. -* Fix indexed source maps support. + +- Faster API with 6to5 Loose mode. +- Fix indexed source maps support. ## 4.0.2 -* Do not copy IE hacks to code style. + +- Do not copy IE hacks to code style. ## 4.0.1 -* Add `source.input` to `Root` too. + +- Add `source.input` to `Root` too. ## 4.0 “Duke Flauros” -* Rename `Container#childs` to `nodes`. -* Rename `PostCSS#processors` to `plugins`. -* Add `Node#replaceValues()` method. -* Add `Node#moveTo()`, `moveBefore()` and `moveAfter()` methods. -* Add `Node#cloneBefore()` and `cloneAfter()` shortcuts. -* Add `Node#next()`, `prev()` and `root()` shortcuts. -* Add `Node#replaceWith()` method. -* Add `Node#error()` method. -* Add `Container#removeAll()` method. -* Add filter argument to `eachDecl()` and `eachAtRule()`. -* Add `Node#source.input` and move `source.file` or `source.id` to `input`. -* Change code indent, when node was moved. -* Better fix code style on `Rule`, `AtRule` and `Comment` nodes changes. -* Allow to create rules and at-rules by hash shortcut in append methods. -* Add class name to CSS syntax error output. + +- Rename `Container#childs` to `nodes`. +- Rename `PostCSS#processors` to `plugins`. +- Add `Node#replaceValues()` method. +- Add `Node#moveTo()`, `moveBefore()` and `moveAfter()` methods. +- Add `Node#cloneBefore()` and `cloneAfter()` shortcuts. +- Add `Node#next()`, `prev()` and `root()` shortcuts. +- Add `Node#replaceWith()` method. +- Add `Node#error()` method. +- Add `Container#removeAll()` method. +- Add filter argument to `eachDecl()` and `eachAtRule()`. +- Add `Node#source.input` and move `source.file` or `source.id` to `input`. +- Change code indent, when node was moved. +- Better fix code style on `Rule`, `AtRule` and `Comment` nodes changes. +- Allow to create rules and at-rules by hash shortcut in append methods. +- Add class name to CSS syntax error output. ## 3.0.7 -* Fix IE filter parsing with multiple commands. -* Safer way to consume PostCSS object as plugin (by Maxime Thirouin). + +- Fix IE filter parsing with multiple commands. +- Safer way to consume PostCSS object as plugin (by Maxime Thirouin). ## 3.0.6 -* Fix missing semicolon when comment comes after last declaration. -* Fix Safe Mode declaration parsing on unclosed blocks. + +- Fix missing semicolon when comment comes after last declaration. +- Fix Safe Mode declaration parsing on unclosed blocks. ## 3.0.5 -* Fix parser to support difficult cases with backslash escape and brackets. -* Add `CssSyntaxError#stack` (by Maxime Thirouin). + +- Fix parser to support difficult cases with backslash escape and brackets. +- Add `CssSyntaxError#stack` (by Maxime Thirouin). ## 3.0.4 -* Fix Safe Mode on unknown word before declaration. + +- Fix Safe Mode on unknown word before declaration. ## 3.0.3 -* Increase tokenizer speed (by Roman Dvornov). + +- Increase tokenizer speed (by Roman Dvornov). ## 3.0.2 -* Fix empty comment parsing. -* Fix `Root#normalize` in some inserts. + +- Fix empty comment parsing. +- Fix `Root#normalize` in some inserts. ## 3.0.1 -* Fix Rhino JS runtime support. -* Typo in deprecated warning (by Maxime Thirouin). + +- Fix Rhino JS runtime support. +- Typo in deprecated warning (by Maxime Thirouin). ## 3.0 “Marquis Andrealphus” -* New parser, which become the fastest ever CSS parser written in JavaScript. -* Parser can now parse declarations and rules in one parent (like in `@page`) + +- New parser, which become the fastest ever CSS parser written in JavaScript. +- Parser can now parse declarations and rules in one parent (like in `@page`) and nested declarations for plugins like `postcss-nested`. -* Child nodes array is now in `childs` property, instead of `decls` and `rules`. -* `map.inline` and `map.sourcesContent` options are now `true` by default. -* Fix iterators (`each`, `insertAfter`) on children array changes. -* Use previous source map to show origin source of CSS syntax error. -* Use 6to5 ES6 compiler, instead of ES6 Transpiler. -* Use code style for manually added rules from existing rules. -* Use `from` option from previous source map `file` field. -* Set `to` value to `from` if `to` option is missing. -* Use better node source name when missing `from` option. -* Show a syntax error when `;` is missed between declarations. -* Allow to pass `PostCSS` instance or list of plugins to `use()` method. -* Allow to pass `Result` instance to `process()` method. -* Trim Unicode BOM on source maps parsing. -* Parse at-rules without spaces like `@import"file"`. -* Better previous `sourceMappingURL` annotation comment cleaning. -* Do not remove previous `sourceMappingURL` comment on `map.annotation: false`. -* Parse nameless at-rules in Safe Mode. -* Fix source map generation for nodes without source. -* Fix next child `before` if `Root` first child got removed. +- Child nodes array is now in `childs` property, instead of `decls` and `rules`. +- `map.inline` and `map.sourcesContent` options are now `true` by default. +- Fix iterators (`each`, `insertAfter`) on children array changes. +- Use previous source map to show origin source of CSS syntax error. +- Use 6to5 ES6 compiler, instead of ES6 Transpiler. +- Use code style for manually added rules from existing rules. +- Use `from` option from previous source map `file` field. +- Set `to` value to `from` if `to` option is missing. +- Use better node source name when missing `from` option. +- Show a syntax error when `;` is missed between declarations. +- Allow to pass `PostCSS` instance or list of plugins to `use()` method. +- Allow to pass `Result` instance to `process()` method. +- Trim Unicode BOM on source maps parsing. +- Parse at-rules without spaces like `@import"file"`. +- Better previous `sourceMappingURL` annotation comment cleaning. +- Do not remove previous `sourceMappingURL` comment on `map.annotation: false`. +- Parse nameless at-rules in Safe Mode. +- Fix source map generation for nodes without source. +- Fix next child `before` if `Root` first child got removed. ## 2.2.6 -* Fix map generation for nodes without source (by Josiah Savary). + +- Fix map generation for nodes without source (by Josiah Savary). ## 2.2.5 -* Fix source map with BOM marker support (by Mohammad Younes). -* Fix source map paths (by Mohammad Younes). + +- Fix source map with BOM marker support (by Mohammad Younes). +- Fix source map paths (by Mohammad Younes). ## 2.2.4 -* Fix `prepend()` on empty `Root`. + +- Fix `prepend()` on empty `Root`. ## 2.2.3 -* Allow to use object shortcut in `use()` with functions like `autoprefixer`. + +- Allow to use object shortcut in `use()` with functions like `autoprefixer`. ## 2.2.2 -* Add shortcut to set processors in `use()` via object with `.postcss` property. + +- Add shortcut to set processors in `use()` via object with `.postcss` property. ## 2.2.1 -* Send `opts` from `Processor#process(css, opts)` to processors. + +- Send `opts` from `Processor#process(css, opts)` to processors. ## 2.2 “Marquis Cimeies” -* Use GNU style syntax error messages. -* Add `Node#replace` method. -* Add `CssSyntaxError#reason` property. + +- Use GNU style syntax error messages. +- Add `Node#replace` method. +- Add `CssSyntaxError#reason` property. ## 2.1.2 -* Fix UTF-8 support in inline source map. -* Fix source map `sourcesContent` if there is no `from` and `to` options. + +- Fix UTF-8 support in inline source map. +- Fix source map `sourcesContent` if there is no `from` and `to` options. ## 2.1.1 -* Allow to miss `to` and `from` options for inline source maps. -* Add `Node#source.id` if file name is unknown. -* Better detect splitter between rules in CSS concatenation tools. -* Automatically clone node in insert methods. + +- Allow to miss `to` and `from` options for inline source maps. +- Add `Node#source.id` if file name is unknown. +- Better detect splitter between rules in CSS concatenation tools. +- Automatically clone node in insert methods. ## 2.1 “King Amdusias” -* Change Traceur ES6 compiler to ES6 Transpiler. -* Show broken CSS line in syntax error. + +- Change Traceur ES6 compiler to ES6 Transpiler. +- Show broken CSS line in syntax error. ## 2.0 “King Belial” -* Project was rewritten from CoffeeScript to ES6. -* Add Safe Mode to works with live input or with hacks from legacy code. -* More safer parser to pass all hacks from Browserhacks.com. -* Use real properties instead of magic getter/setter for raw properties. + +- Project was rewritten from CoffeeScript to ES6. +- Add Safe Mode to works with live input or with hacks from legacy code. +- More safer parser to pass all hacks from Browserhacks.com. +- Use real properties instead of magic getter/setter for raw properties. ## 1.0 “Marquis Decarabia” -* Save previous source map for each node to support CSS concatenation + +- Save previous source map for each node to support CSS concatenation with multiple previous maps. -* Add `map.sourcesContent` option to add origin content to `sourcesContent` +- Add `map.sourcesContent` option to add origin content to `sourcesContent` inside map. -* Allow to set different place of output map in annotation comment. -* Allow to use arrays and `Root` in `Container#append` and same methods. -* Add `Root#prevMap` with information about previous map. -* Allow to use latest PostCSS from GitHub by npm. -* `Result` now is lazy and it will generate output CSS only if you use `css` +- Allow to set different place of output map in annotation comment. +- Allow to use arrays and `Root` in `Container#append` and same methods. +- Add `Root#prevMap` with information about previous map. +- Allow to use latest PostCSS from GitHub by npm. +- `Result` now is lazy and it will generate output CSS only if you use `css` or `map` property. -* Use separated `map.prev` option to set previous map. -* Rename `inlineMap` option to `map.inline`. -* Rename `mapAnnotation` option to `map.annotation`. -* `Result#map` now return `SourceMapGenerator` object, instead of string. -* Run previous map autodetect only if input CSS contains annotation comment. -* Add `map: 'inline'` shortcut for `map: { inline: true }` option. -* `Node#source.file` now will contains absolute path. -* Clean `Declaration#between` style on node clone. +- Use separated `map.prev` option to set previous map. +- Rename `inlineMap` option to `map.inline`. +- Rename `mapAnnotation` option to `map.annotation`. +- `Result#map` now return `SourceMapGenerator` object, instead of string. +- Run previous map autodetect only if input CSS contains annotation comment. +- Add `map: 'inline'` shortcut for `map: { inline: true }` option. +- `Node#source.file` now will contains absolute path. +- Clean `Declaration#between` style on node clone. ## 0.3.5 -* Allow to use `Root` or `Result` as first argument in `process()`. -* Save parsed AST to `Result#root`. + +- Allow to use `Root` or `Result` as first argument in `process()`. +- Save parsed AST to `Result#root`. ## 0.3.4 -* Better space symbol detect to read UTF-8 BOM correctly. + +- Better space symbol detect to read UTF-8 BOM correctly. ## 0.3.3 -* Remove source map hacks by using new Mozilla’s `source-map` (by Simon Lydell). + +- Remove source map hacks by using new Mozilla’s `source-map` (by Simon Lydell). ## 0.3.2 -* Add URI encoding support for inline source maps. + +- Add URI encoding support for inline source maps. ## 0.3.1 -* Fix relative paths from previous source map. -* Safer space split in `Rule#selectors` (by Simon Lydell). + +- Fix relative paths from previous source map. +- Safer space split in `Rule#selectors` (by Simon Lydell). ## 0.3 “Prince Seere” -* Add `Comment` node for comments between declarations or rules. -* Add source map annotation comment to output CSS. -* Allow to inline source map to annotation comment by data:uri. -* Fix source maps on Windows. -* Fix source maps for subdirectory (by Dmitry Nikitenko and Simon Lydell). -* Autodetect previous source map. -* Add `first` and `last` shortcuts to container nodes. -* Parse `!important` to separated property in `Declaration`. -* Allow to break iteration by returning `false`. -* Copy code style to new nodes. -* Add `eachInside` method to recursively iterate all nodes. -* Add `selectors` shortcut to get selectors array. -* Add `toResult` method to `Rule` to simplify work with several input files. -* Clean declaration’s `value`, rule’s `selector` and at-rule’s `params` + +- Add `Comment` node for comments between declarations or rules. +- Add source map annotation comment to output CSS. +- Allow to inline source map to annotation comment by data:uri. +- Fix source maps on Windows. +- Fix source maps for subdirectory (by Dmitry Nikitenko and Simon Lydell). +- Autodetect previous source map. +- Add `first` and `last` shortcuts to container nodes. +- Parse `!important` to separated property in `Declaration`. +- Allow to break iteration by returning `false`. +- Copy code style to new nodes. +- Add `eachInside` method to recursively iterate all nodes. +- Add `selectors` shortcut to get selectors array. +- Add `toResult` method to `Rule` to simplify work with several input files. +- Clean declaration’s `value`, rule’s `selector` and at-rule’s `params` by storing spaces in `between` property. ## 0.2 “Duke Dantalion” -* Add source map support. -* Add shortcuts to create nodes. -* Method `process()` now returns object with `css` and `map` keys. -* Origin CSS file option was renamed from `file` to `from`. -* Rename `Node#remove()` method to `removeSelf()` to fix name conflict. -* Node source was moved to `source` property with origin file + +- Add source map support. +- Add shortcuts to create nodes. +- Method `process()` now returns object with `css` and `map` keys. +- Origin CSS file option was renamed from `file` to `from`. +- Rename `Node#remove()` method to `removeSelf()` to fix name conflict. +- Node source was moved to `source` property with origin file and node end position. -* You can set own CSS generate function. +- You can set own CSS generate function. ## 0.1 “Count Andromalius” -* Initial release. + +- Initial release. diff --git a/LICENSE b/LICENSE index da057b456..c2314d53d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright 2013 Andrey Sitnik +Copyright 2013 Andrey Sitnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/README.md b/README.md index c6a041523..08a75c1bc 100644 --- a/README.md +++ b/README.md @@ -9,20 +9,20 @@ These plugins can lint your CSS, support variables and mixins, transpile future CSS syntax, inline images, and more. PostCSS is used by industry leaders including Wikipedia, Twitter, Alibaba, -and JetBrains. The [Autoprefixer] and [Stylelint] PostCSS plugins is one of the most popular CSS tools. +and JetBrains. The [Autoprefixer] and [Stylelint] PostCSS plugins are some of the most popular CSS tools. --- -  Made in Evil Martians, product consulting for developer tools. +  Built by +Evil Martians, go-to agency for developer tools. --- -[Abstract Syntax Tree]: https://en.wikipedia.org/wiki/Abstract_syntax_tree -[Evil Martians]: https://evilmartians.com/?utm_source=postcss -[Autoprefixer]: https://github.com/postcss/autoprefixer -[Stylelint]: https://stylelint.io/ -[plugins]: https://github.com/postcss/postcss#plugins - +[Abstract Syntax Tree]: https://en.wikipedia.org/wiki/Abstract_syntax_tree +[Evil Martians]: https://evilmartians.com/?utm_source=postcss +[Autoprefixer]: https://github.com/postcss/autoprefixer +[Stylelint]: https://stylelint.io/ +[plugins]: https://github.com/postcss/postcss#plugins ## Sponsorship @@ -31,12 +31,10 @@ PostCSS needs your support. We are accepting donations Sponsored by Tailwind CSS -       + alt="Sponsored by Tailwind CSS" width="213" height="50">       + Sponsored by ThemeIsle - - + alt="Sponsored by ThemeIsle" width="171" height="56"> ## Plugins @@ -46,97 +44,90 @@ This API can then be used by [plugins] to do a lot of useful things, e.g., to find errors automatically, or to insert vendor prefixes. Currently, PostCSS has more than 200 plugins. You can find all of the plugins -in the [plugins list] or in the [searchable catalog]. Below is a list -of our favorite plugins — the best demonstrations of what can be built -on top of PostCSS. +in the [plugins list]. Below is a list of our favorite plugins — +the best demonstrations of what can be built on top of PostCSS. If you have any new ideas, [PostCSS plugin development] is really easy. -[searchable catalog]: https://www.postcss.parts/ -[plugins list]: https://github.com/postcss/postcss/blob/main/docs/plugins.md - +[plugins list]: https://github.com/postcss/postcss/blob/main/docs/plugins.md ### Solve Global CSS Problem -* [`postcss-use`] allows you to explicitly set PostCSS plugins within CSS +- [`postcss-use`] allows you to explicitly set PostCSS plugins within CSS and execute them only for the current file. -* [`postcss-modules`] and [`react-css-modules`] automatically isolate +- [`postcss-modules`] and [`react-css-modules`] automatically isolate selectors within components. -* [`postcss-autoreset`] is an alternative to using a global reset +- [`postcss-autoreset`] is an alternative to using a global reset that is better for isolatable components. -* [`postcss-initial`] adds `all: initial` support, which resets +- [`postcss-initial`] adds `all: initial` support, which resets all inherited styles. -* [`cq-prolyfill`] adds container query support, allowing styles that respond +- [`cq-prolyfill`] adds container query support, allowing styles that respond to the width of the parent. - ### Use Future CSS, Today -* [`autoprefixer`] adds vendor prefixes, using data from Can I Use. -* [`postcss-preset-env`] allows you to use future CSS features today. - +- [`autoprefixer`] adds vendor prefixes, using data from Can I Use. +- [`postcss-preset-env`] allows you to use future CSS features today. ### Better CSS Readability -* [`postcss-nested`] unwraps nested rules the way Sass does. -* [`postcss-sorting`] sorts the content of rules and at-rules. -* [`postcss-utilities`] includes the most commonly used shortcuts and helpers. -* [`short`] adds and extends numerous shorthand properties. - +- [`postcss-nested`] unwraps nested rules the way Sass does. +- [`postcss-sorting`] sorts the content of rules and at-rules. +- [`postcss-utilities`] includes the most commonly used shortcuts and helpers. +- [`short`] adds and extends numerous shorthand properties. ### Images and Fonts -* [`postcss-url`] postcss plugin to rebase url(), inline or copy asset. -* [`postcss-sprites`] generates image sprites. -* [`font-magician`] generates all the `@font-face` rules needed in CSS. -* [`postcss-inline-svg`] allows you to inline SVG and customize its styles. -* [`postcss-write-svg`] allows you to write simple SVG directly in your CSS. -* [`webp-in-css`] to use WebP image format in CSS background. -* [`avif-in-css`] to use AVIF image format in CSS background. +- [`postcss-url`] postcss plugin to rebase url(), inline or copy asset. +- [`postcss-sprites`] generates image sprites. +- [`font-magician`] generates all the `@font-face` rules needed in CSS. +- [`postcss-inline-svg`] allows you to inline SVG and customize its styles. +- [`postcss-write-svg`] allows you to write simple SVG directly in your CSS. +- [`webp-in-css`] to use WebP image format in CSS background. +- [`avif-in-css`] to use AVIF image format in CSS background. ### Linters -* [`stylelint`] is a modular stylesheet linter. -* [`stylefmt`] is a tool that automatically formats CSS +- [`stylelint`] is a modular stylesheet linter. +- [`stylefmt`] is a tool that automatically formats CSS according `stylelint` rules. -* [`doiuse`] lints CSS for browser support, using data from Can I Use. -* [`colorguard`] helps you maintain a consistent color palette. - +- [`doiuse`] lints CSS for browser support, using data from Can I Use. +- [`colorguard`] helps you maintain a consistent color palette. ### Other -* [`cssnano`] is a modular CSS minifier. -* [`lost`] is a feature-rich `calc()` grid system. -* [`rtlcss`] mirrors styles for right-to-left locales. - -[PostCSS plugin development]: https://github.com/postcss/postcss/blob/main/docs/writing-a-plugin.md -[`postcss-inline-svg`]: https://github.com/TrySound/postcss-inline-svg -[`postcss-preset-env`]: https://github.com/csstools/postcss-plugins/tree/main/plugin-packs/postcss-preset-env -[`react-css-modules`]: https://github.com/gajus/react-css-modules -[`postcss-autoreset`]: https://github.com/maximkoretskiy/postcss-autoreset -[`postcss-write-svg`]: https://github.com/csstools/postcss-write-svg -[`postcss-utilities`]: https://github.com/ismamz/postcss-utilities -[`postcss-initial`]: https://github.com/maximkoretskiy/postcss-initial -[`postcss-sprites`]: https://github.com/2createStudio/postcss-sprites -[`postcss-modules`]: https://github.com/outpunk/postcss-modules -[`postcss-sorting`]: https://github.com/hudochenkov/postcss-sorting -[`font-magician`]: https://github.com/csstools/postcss-font-magician -[`autoprefixer`]: https://github.com/postcss/autoprefixer -[`cq-prolyfill`]: https://github.com/ausi/cq-prolyfill -[`postcss-url`]: https://github.com/postcss/postcss-url -[`postcss-use`]: https://github.com/postcss/postcss-use -[`css-modules`]: https://github.com/css-modules/css-modules -[`webp-in-css`]: https://github.com/ai/webp-in-css -[`avif-in-css`]: https://github.com/nucliweb/avif-in-css -[`colorguard`]: https://github.com/SlexAxton/css-colorguard -[`stylelint`]: https://github.com/stylelint/stylelint -[`stylefmt`]: https://github.com/morishitter/stylefmt -[`cssnano`]: https://cssnano.co/ -[`postcss-nested`]: https://github.com/postcss/postcss-nested -[`doiuse`]: https://github.com/anandthakker/doiuse -[`rtlcss`]: https://github.com/MohammadYounes/rtlcss -[`short`]: https://github.com/csstools/postcss-short -[`lost`]: https://github.com/peterramsing/lost +- [`cssnano`] is a modular CSS minifier. +- [`lost`] is a feature-rich `calc()` grid system. +- [`rtlcss`] mirrors styles for right-to-left locales. + +[PostCSS plugin development]: https://github.com/postcss/postcss/blob/main/docs/writing-a-plugin.md +[`postcss-inline-svg`]: https://github.com/TrySound/postcss-inline-svg +[`postcss-preset-env`]: https://github.com/csstools/postcss-plugins/tree/main/plugin-packs/postcss-preset-env +[`react-css-modules`]: https://github.com/gajus/react-css-modules +[`postcss-autoreset`]: https://github.com/maximkoretskiy/postcss-autoreset +[`postcss-write-svg`]: https://github.com/csstools/postcss-write-svg +[`postcss-utilities`]: https://github.com/ismamz/postcss-utilities +[`postcss-initial`]: https://github.com/maximkoretskiy/postcss-initial +[`postcss-sprites`]: https://github.com/2createStudio/postcss-sprites +[`postcss-modules`]: https://github.com/outpunk/postcss-modules +[`postcss-sorting`]: https://github.com/hudochenkov/postcss-sorting +[`font-magician`]: https://github.com/csstools/postcss-font-magician +[`autoprefixer`]: https://github.com/postcss/autoprefixer +[`cq-prolyfill`]: https://github.com/ausi/cq-prolyfill +[`postcss-url`]: https://github.com/postcss/postcss-url +[`postcss-use`]: https://github.com/postcss/postcss-use +[`css-modules`]: https://github.com/css-modules/css-modules +[`webp-in-css`]: https://github.com/ai/webp-in-css +[`avif-in-css`]: https://github.com/nucliweb/avif-in-css +[`colorguard`]: https://github.com/SlexAxton/css-colorguard +[`stylelint`]: https://github.com/stylelint/stylelint +[`stylefmt`]: https://github.com/morishitter/stylefmt +[`cssnano`]: https://cssnano.github.io/cssnano/ +[`postcss-nested`]: https://github.com/postcss/postcss-nested +[`doiuse`]: https://github.com/anandthakker/doiuse +[`rtlcss`]: https://github.com/MohammadYounes/rtlcss +[`short`]: https://github.com/csstools/postcss-short +[`lost`]: https://github.com/peterramsing/lost ## Syntaxes @@ -144,56 +135,53 @@ PostCSS can transform styles in any syntax, not just CSS. If there is not yet support for your favorite syntax, you can write a parser and/or stringifier to extend PostCSS. -* [`sugarss`] is a indent-based syntax like Sass or Stylus. -* [`postcss-syntax`] switch syntax automatically by file extensions. -* [`postcss-html`] parsing styles in `' }).input + * input.document //=> "" + * input.css //=> "a{}" + * ``` + */ + document: string + /** * The absolute path to the CSS source file defined * with the `from` option. @@ -100,12 +120,29 @@ declare class Input_ { */ map: PreviousMap + /** + * The CSS source identifier. Contains `Input#file` if the user + * set the `from` option, or `Input#id` if they did not. + * + * ```js + * const root = postcss.parse(css, { from: 'a.css' }) + * root.source.input.from //=> "/home/ai/a.css" + * + * const root = postcss.parse(css) + * root.source.input.from //=> "" + * ``` + */ + get from(): string + /** * @param css Input CSS source. * @param opts Process options. */ constructor(css: string, opts?: ProcessOptions) + /** + * Returns `CssSyntaxError` with information about the error and its position. + */ error( message: string, start: @@ -126,29 +163,34 @@ declare class Input_ { }, opts?: { plugin?: CssSyntaxError['plugin'] } ): CssSyntaxError - - /** - * Returns `CssSyntaxError` with information about the error and its position. - */ error( message: string, line: number, column: number, opts?: { plugin?: CssSyntaxError['plugin'] } ): CssSyntaxError - error( message: string, offset: number, opts?: { plugin?: CssSyntaxError['plugin'] } ): CssSyntaxError + /** + * Converts source line and column to offset. + * + * @param line Source line. + * @param column Source column. + * @return Source offset. + */ + fromLineAndColumn(line: number, column: number): number + /** * Converts source offset to line and column. * * @param offset Source offset. */ fromOffset(offset: number): { col: number; line: number } | null + /** * Reads the input source map and returns a symbol position * in the input source (e.g., in a Sass file that was compiled @@ -174,19 +216,9 @@ declare class Input_ { endLine?: number, endColumn?: number ): false | Input.FilePosition - /** - * The CSS source identifier. Contains `Input#file` if the user - * set the `from` option, or `Input#id` if they did not. - * - * ```js - * const root = postcss.parse(css, { from: 'a.css' }) - * root.source.input.from //=> "/home/ai/a.css" - * - * const root = postcss.parse(css) - * root.source.input.from //=> "" - * ``` - */ - get from(): string + + /** Converts this to a JSON-friendly object representation. */ + toJSON(): object } declare class Input extends Input_ {} diff --git a/lib/input.js b/lib/input.js index 4b5ee5e02..1dab92836 100644 --- a/lib/input.js +++ b/lib/input.js @@ -1,20 +1,39 @@ 'use strict' +let { nanoid } = require('nanoid/non-secure') +let { isAbsolute, resolve } = require('path') let { SourceMapConsumer, SourceMapGenerator } = require('source-map-js') let { fileURLToPath, pathToFileURL } = require('url') -let { isAbsolute, resolve } = require('path') -let { nanoid } = require('nanoid/non-secure') -let terminalHighlight = require('./terminal-highlight') let CssSyntaxError = require('./css-syntax-error') let PreviousMap = require('./previous-map') +let terminalHighlight = require('./terminal-highlight') -let fromOffsetCache = Symbol('fromOffsetCache') +let lineToIndexCache = Symbol('lineToIndexCache') let sourceMapAvailable = Boolean(SourceMapConsumer && SourceMapGenerator) let pathAvailable = Boolean(resolve && isAbsolute) +function getLineToIndex(input) { + if (input[lineToIndexCache]) return input[lineToIndexCache] + let lines = input.css.split('\n') + let lineToIndex = new Array(lines.length) + let prevIndex = 0 + + for (let i = 0, l = lines.length; i < l; i++) { + lineToIndex[i] = prevIndex + prevIndex += lines[i].length + 1 + } + + input[lineToIndexCache] = lineToIndex + return lineToIndex +} + class Input { + get from() { + return this.file || this.id + } + constructor(css, opts = {}) { if ( css === null || @@ -33,6 +52,9 @@ class Input { this.hasBOM = false } + this.document = this.css + if (opts.document) this.document = opts.document.toString() + if (opts.from) { if ( !pathAvailable || @@ -61,31 +83,38 @@ class Input { } error(message, line, column, opts = {}) { - let result, endLine, endColumn + let endColumn, endLine, endOffset, offset, result if (line && typeof line === 'object') { let start = line let end = column if (typeof start.offset === 'number') { - let pos = this.fromOffset(start.offset) + offset = start.offset + let pos = this.fromOffset(offset) line = pos.line column = pos.col } else { line = start.line column = start.column + offset = this.fromLineAndColumn(line, column) } if (typeof end.offset === 'number') { - let pos = this.fromOffset(end.offset) + endOffset = end.offset + let pos = this.fromOffset(endOffset) endLine = pos.line endColumn = pos.col } else { endLine = end.line endColumn = end.column + endOffset = this.fromLineAndColumn(end.line, end.column) } } else if (!column) { - let pos = this.fromOffset(line) + offset = line + let pos = this.fromOffset(offset) line = pos.line column = pos.col + } else { + offset = this.fromLineAndColumn(line, column) } let origin = this.origin(line, column, endLine, endColumn) @@ -113,7 +142,15 @@ class Input { ) } - result.input = { column, endColumn, endLine, line, source: this.css } + result.input = { + column, + endColumn, + endLine, + endOffset, + line, + offset, + source: this.css + } if (this.file) { if (pathToFileURL) { result.input.url = pathToFileURL(this.file).toString() @@ -124,23 +161,15 @@ class Input { return result } - fromOffset(offset) { - let lastLine, lineToIndex - if (!this[fromOffsetCache]) { - let lines = this.css.split('\n') - lineToIndex = new Array(lines.length) - let prevIndex = 0 - - for (let i = 0, l = lines.length; i < l; i++) { - lineToIndex[i] = prevIndex - prevIndex += lines[i].length + 1 - } + fromLineAndColumn(line, column) { + let lineToIndex = getLineToIndex(this) + let index = lineToIndex[line - 1] + return index + column - 1 + } - this[fromOffsetCache] = lineToIndex - } else { - lineToIndex = this[fromOffsetCache] - } - lastLine = lineToIndex[lineToIndex.length - 1] + fromOffset(offset) { + let lineToIndex = getLineToIndex(this) + let lastLine = lineToIndex[lineToIndex.length - 1] let min = 0 if (offset >= lastLine) { @@ -234,10 +263,6 @@ class Input { } return json } - - get from() { - return this.file || this.id - } } module.exports = Input diff --git a/lib/lazy-result.d.ts b/lib/lazy-result.d.ts index dd291aa3a..599a614bf 100644 --- a/lib/lazy-result.d.ts +++ b/lib/lazy-result.d.ts @@ -6,7 +6,6 @@ import Root from './root.js' import Warning from './warning.js' declare namespace LazyResult { - // eslint-disable-next-line @typescript-eslint/no-use-before-define export { LazyResult_ as default } } @@ -19,9 +18,9 @@ declare namespace LazyResult { * const lazy = postcss([autoprefixer]).process(css) * ``` */ -declare class LazyResult_ - implements PromiseLike> -{ +declare class LazyResult_ implements PromiseLike< + Result +> { /** * Processes input CSS through synchronous and asynchronous plugins * and calls onRejected for each error thrown in any plugin. @@ -67,46 +66,6 @@ declare class LazyResult_ */ then: Promise>['then'] - /** - * @param processor Processor used for this transformation. - * @param css CSS to parse and transform. - * @param opts Options from the `Processor#process` or `Root#toResult`. - */ - constructor(processor: Processor, css: string, opts: ResultOptions) - - /** - * Run plugin in async way and return `Result`. - * - * @return Result with output content. - */ - async(): Promise> - - /** - * Run plugin in sync way and return `Result`. - * - * @return Result with output content. - */ - sync(): Result - - /** - * Alias for the `LazyResult#css` property. - * - * ```js - * lazy + '' === lazy.css - * ``` - * - * @return Output CSS. - */ - toString(): string - - /** - * Processes input CSS through synchronous plugins - * and calls `Result#warnings`. - * - * @return Warnings from plugins. - */ - warnings(): Warning[] - /** * An alias for the `css` property. Use it with syntaxes * that generate non-CSS output. @@ -181,6 +140,46 @@ declare class LazyResult_ * Required to implement the Promise interface. */ get [Symbol.toStringTag](): string + + /** + * @param processor Processor used for this transformation. + * @param css CSS to parse and transform. + * @param opts Options from the `Processor#process` or `Root#toResult`. + */ + constructor(processor: Processor, css: string, opts: ResultOptions) + + /** + * Run plugin in async way and return `Result`. + * + * @return Result with output content. + */ + async(): Promise> + + /** + * Run plugin in sync way and return `Result`. + * + * @return Result with output content. + */ + sync(): Result + + /** + * Alias for the `LazyResult#css` property. + * + * ```js + * lazy + '' === lazy.css + * ``` + * + * @return Output CSS. + */ + toString(): string + + /** + * Processes input CSS through synchronous plugins + * and calls `Result#warnings`. + * + * @return Warnings from plugins. + */ + warnings(): Warning[] } declare class LazyResult< diff --git a/lib/lazy-result.js b/lib/lazy-result.js index 126f40c7e..9026a7c86 100644 --- a/lib/lazy-result.js +++ b/lib/lazy-result.js @@ -1,14 +1,14 @@ 'use strict' -let { isClean, my } = require('./symbols') -let MapGenerator = require('./map-generator') -let stringify = require('./stringify') let Container = require('./container') let Document = require('./document') -let warnOnce = require('./warn-once') -let Result = require('./result') +let MapGenerator = require('./map-generator') let parse = require('./parse') +let Result = require('./result') let Root = require('./root') +let stringify = require('./stringify') +let { isClean, my } = require('./symbols') +let warnOnce = require('./warn-once') const TYPE_TO_CLASS_NAME = { atrule: 'AtRule', @@ -105,6 +105,38 @@ function cleanMarks(node) { let postcss = {} class LazyResult { + get content() { + return this.stringify().content + } + + get css() { + return this.stringify().css + } + + get map() { + return this.stringify().map + } + + get messages() { + return this.sync().messages + } + + get opts() { + return this.result.opts + } + + get processor() { + return this.result.processor + } + + get root() { + return this.sync().root + } + + get [Symbol.toStringTag]() { + return 'LazyResult' + } + constructor(processor, css, opts) { this.stringified = false this.processed = false @@ -346,6 +378,19 @@ class LazyResult { if (opts.stringifier) str = opts.stringifier if (str.stringify) str = str.stringify + let rootSource = this.result.root.source + if ( + opts.map === undefined && + !(rootSource && rootSource.input && rootSource.input.map) + ) { + let result = '' + str(this.result.root, i => { + result += i + }) + this.result.css = result + return this.result + } + let map = new MapGenerator(str, this.result.root, this.result.opts) let data = map.generate() this.result.css = data[0] @@ -505,38 +550,6 @@ class LazyResult { warnings() { return this.sync().warnings() } - - get content() { - return this.stringify().content - } - - get css() { - return this.stringify().css - } - - get map() { - return this.stringify().map - } - - get messages() { - return this.sync().messages - } - - get opts() { - return this.result.opts - } - - get processor() { - return this.result.processor - } - - get root() { - return this.sync().root - } - - get [Symbol.toStringTag]() { - return 'LazyResult' - } } LazyResult.registerPostcss = dependant => { diff --git a/lib/list.d.ts b/lib/list.d.ts index 1a74d74cf..119624e87 100644 --- a/lib/list.d.ts +++ b/lib/list.d.ts @@ -47,11 +47,14 @@ declare namespace list { * @param last boolean indicator. * @return Split values. */ - split(string: string, separators: string[], last: boolean): string[] + split( + string: string, + separators: readonly string[], + last: boolean + ): string[] } } -// eslint-disable-next-line @typescript-eslint/no-redeclare -declare const list: list.List +declare let list: list.List export = list diff --git a/lib/map-generator.js b/lib/map-generator.js index 523b46397..df880ac99 100644 --- a/lib/map-generator.js +++ b/lib/map-generator.js @@ -1,7 +1,7 @@ 'use strict' -let { SourceMapConsumer, SourceMapGenerator } = require('source-map-js') let { dirname, relative, resolve, sep } = require('path') +let { SourceMapConsumer, SourceMapGenerator } = require('source-map-js') let { pathToFileURL } = require('url') let Input = require('./input') @@ -16,6 +16,7 @@ class MapGenerator { this.root = root this.opts = opts this.css = cssString + this.originalCSS = cssString this.usesFileUrls = !this.mapOpts.from && this.mapOpts.absolute this.memoizedFileURLs = new Map() @@ -51,7 +52,7 @@ class MapGenerator { if (this.mapOpts.sourcesContent === false) { map = new SourceMapConsumer(prev.text) if (map.sourcesContent) { - map.sourcesContent = map.sourcesContent.map(() => null) + map.sourcesContent = null } } else { map = prev.consumer() @@ -69,12 +70,20 @@ class MapGenerator { for (let i = this.root.nodes.length - 1; i >= 0; i--) { node = this.root.nodes[i] if (node.type !== 'comment') continue - if (node.text.indexOf('# sourceMappingURL=') === 0) { + if (node.text.startsWith('# sourceMappingURL=')) { this.root.removeChild(i) } } } else if (this.css) { - this.css = this.css.replace(/(\n)?\/\*#[\S\s]*?\*\/$/gm, '') + let startIndex + while ((startIndex = this.css.lastIndexOf('/*#')) !== -1) { + let endIndex = this.css.indexOf('*/', startIndex + 3) + if (endIndex === -1) break + while (startIndex > 0 && this.css[startIndex - 1] === '\n') { + startIndex-- + } + this.css = this.css.slice(0, startIndex) + this.css.slice(endIndex + 2) + } } } @@ -97,9 +106,14 @@ class MapGenerator { } else if (this.previous().length === 1) { let prev = this.previous()[0].consumer() prev.file = this.outputFile() - this.map = SourceMapGenerator.fromSourceMap(prev) + this.map = SourceMapGenerator.fromSourceMap(prev, { + ignoreInvalidMapping: true + }) } else { - this.map = new SourceMapGenerator({ file: this.outputFile() }) + this.map = new SourceMapGenerator({ + file: this.outputFile(), + ignoreInvalidMapping: true + }) this.map.addMapping({ generated: { column: 0, line: 1 }, original: { column: 0, line: 1 }, @@ -122,7 +136,10 @@ class MapGenerator { generateString() { this.css = '' - this.map = new SourceMapGenerator({ file: this.outputFile() }) + this.map = new SourceMapGenerator({ + file: this.outputFile(), + ignoreInvalidMapping: true + }) let line = 1 let column = 1 @@ -134,7 +151,7 @@ class MapGenerator { source: '' } - let lines, last + let last, lines this.stringify(this.root, (str, node, type) => { this.css += str @@ -276,7 +293,7 @@ class MapGenerator { } }) } else { - let input = new Input(this.css, this.opts) + let input = new Input(this.originalCSS, this.opts) if (input.map) this.previousMaps.push(input.map) } } diff --git a/lib/no-work-result.d.ts b/lib/no-work-result.d.ts index 803907654..fa9d28484 100644 --- a/lib/no-work-result.d.ts +++ b/lib/no-work-result.d.ts @@ -6,7 +6,6 @@ import Root from './root.js' import Warning from './warning.js' declare namespace NoWorkResult { - // eslint-disable-next-line @typescript-eslint/no-use-before-define export { NoWorkResult_ as default } } @@ -26,11 +25,6 @@ declare class NoWorkResult_ implements LazyResult { catch: Promise>['catch'] finally: Promise>['finally'] then: Promise>['then'] - constructor(processor: Processor, css: string, opts: ResultOptions) - async(): Promise> - sync(): Result - toString(): string - warnings(): Warning[] get content(): string get css(): string get map(): SourceMap @@ -39,6 +33,11 @@ declare class NoWorkResult_ implements LazyResult { get processor(): Processor get root(): Root get [Symbol.toStringTag](): string + constructor(processor: Processor, css: string, opts: ResultOptions) + async(): Promise> + sync(): Result + toString(): string + warnings(): Warning[] } declare class NoWorkResult extends NoWorkResult_ {} diff --git a/lib/no-work-result.js b/lib/no-work-result.js index a0609f797..7ec1a7425 100644 --- a/lib/no-work-result.js +++ b/lib/no-work-result.js @@ -1,12 +1,62 @@ 'use strict' let MapGenerator = require('./map-generator') +let parse = require('./parse') +let Result = require('./result') let stringify = require('./stringify') let warnOnce = require('./warn-once') -let parse = require('./parse') -const Result = require('./result') class NoWorkResult { + get content() { + return this.result.css + } + + get css() { + return this.result.css + } + + get map() { + return this.result.map + } + + get messages() { + return [] + } + + get opts() { + return this.result.opts + } + + get processor() { + return this.result.processor + } + + get root() { + if (this._root) { + return this._root + } + + let root + let parser = parse + + try { + root = parser(this._css, this._opts) + } catch (error) { + this.error = error + } + + if (this.error) { + throw this.error + } else { + this._root = root + return root + } + } + + get [Symbol.toStringTag]() { + return 'NoWorkResult' + } + constructor(processor, css, opts) { css = css.toString() this.stringified = false @@ -15,10 +65,9 @@ class NoWorkResult { this._css = css this._opts = opts this._map = undefined - let root let str = stringify - this.result = new Result(this._processor, root, this._opts) + this.result = new Result(this._processor, undefined, this._opts) this.result.css = css let self = this @@ -28,7 +77,7 @@ class NoWorkResult { } }) - let map = new MapGenerator(str, root, this._opts, css) + let map = new MapGenerator(str, undefined, this._opts, css) if (map.isMap()) { let [generatedCSS, generatedMap] = map.generate() if (generatedCSS) { @@ -37,6 +86,9 @@ class NoWorkResult { if (generatedMap) { this.result.map = generatedMap } + } else { + map.clearAnnotation() + this.result.css = map.css } } @@ -79,56 +131,6 @@ class NoWorkResult { warnings() { return [] } - - get content() { - return this.result.css - } - - get css() { - return this.result.css - } - - get map() { - return this.result.map - } - - get messages() { - return [] - } - - get opts() { - return this.result.opts - } - - get processor() { - return this.result.processor - } - - get root() { - if (this._root) { - return this._root - } - - let root - let parser = parse - - try { - root = parser(this._css, this._opts) - } catch (error) { - this.error = error - } - - if (this.error) { - throw this.error - } else { - this._root = root - return root - } - } - - get [Symbol.toStringTag]() { - return 'NoWorkResult' - } } module.exports = NoWorkResult diff --git a/lib/node.d.ts b/lib/node.d.ts index 71b30159a..ecd86e231 100644 --- a/lib/node.d.ts +++ b/lib/node.d.ts @@ -1,8 +1,7 @@ import AtRule = require('./at-rule.js') - import { AtRuleProps } from './at-rule.js' import Comment, { CommentProps } from './comment.js' -import Container from './container.js' +import Container, { NewChild } from './container.js' import CssSyntaxError from './css-syntax-error.js' import Declaration, { DeclarationProps } from './declaration.js' import Document from './document.js' @@ -66,6 +65,22 @@ declare namespace Node { /** * The inclusive ending position for the source * code of a node. + * + * However, `end.offset` of a non `Root` node is the exclusive position. + * See https://github.com/postcss/postcss/pull/1879 for details. + * + * ```js + * const root = postcss.parse('a { color: black }') + * const a = root.first + * const color = a.first + * + * // The offset of `Root` node is the inclusive position + * css.source.end // { line: 1, column: 19, offset: 18 } + * + * // The offset of non `Root` node is the exclusive position + * a.source.end // { line: 1, column: 18, offset: 18 } + * color.source.end // { line: 1, column: 16, offset: 16 } + * ``` */ end?: Position @@ -111,7 +126,6 @@ declare namespace Node { word?: string } - // eslint-disable-next-line @typescript-eslint/no-shadow class Node extends Node_ {} export { Node as default } } @@ -246,7 +260,9 @@ declare abstract class Node_ { * @param newNode New node. * @return This node for methods chain. */ - after(newNode: Node | Node.ChildProps | Node[] | string): this + after( + newNode: Node | Node.ChildProps | readonly Node[] | string | undefined + ): this /** * It assigns properties to an existing node instance. @@ -273,7 +289,9 @@ declare abstract class Node_ { * @param newNode New node. * @return This node for methods chain. */ - before(newNode: Node | Node.ChildProps | Node[] | string): this + before( + newNode: Node | Node.ChildProps | readonly Node[] | string | undefined + ): this /** * Clear the code style properties for the node and its children. @@ -303,7 +321,7 @@ declare abstract class Node_ { * * @return Duplicate of the node instance. */ - clone(overrides?: object): Node + clone(overrides?: object): this /** * Shortcut to clone the node and insert the resulting cloned node @@ -312,7 +330,7 @@ declare abstract class Node_ { * @param overrides New properties to override in the clone. * @return New node. */ - cloneAfter(overrides?: object): Node + cloneAfter(overrides?: object): this /** * Shortcut to clone the node and insert the resulting cloned node @@ -326,7 +344,7 @@ declare abstract class Node_ { * * @return New node */ - cloneBefore(overrides?: object): Node + cloneBefore(overrides?: object): this /** * It creates an instance of the class `CssSyntaxError` and parameters passed @@ -420,7 +438,7 @@ declare abstract class Node_ { * @return Range. */ rangeBy( - opts?: Pick + opts?: Pick ): Node.Range /** @@ -470,14 +488,7 @@ declare abstract class Node_ { * @param nodes Mode(s) to replace current one. * @return Current node to methods chain. */ - replaceWith( - ...nodes: ( - | Node.ChildNode - | Node.ChildNode[] - | Node.ChildProps - | Node.ChildProps[] - )[] - ): this + replaceWith(...nodes: NewChild[]): this /** * Finds the Root instance of the node’s tree. @@ -529,8 +540,16 @@ declare abstract class Node_ { * @return `Warning` instance is returned */ warn(result: Result, message: string, options?: WarningOptions): Warning + + /** + * If this node isn't already dirty, marks it and its ancestors as such. This + * indicates to the LazyResult processor that the {@link Root} has been + * modified by the current plugin and may need to be processed again by other + * plugins. + */ + protected markDirty(): void } -declare class Node extends Node_ { } +declare class Node extends Node_ {} export = Node diff --git a/lib/node.js b/lib/node.js index d79dd56e5..b403b7136 100644 --- a/lib/node.js +++ b/lib/node.js @@ -1,9 +1,9 @@ 'use strict' -let { isClean, my } = require('./symbols') let CssSyntaxError = require('./css-syntax-error') let Stringifier = require('./stringifier') let stringify = require('./stringify') +let { isClean, my } = require('./symbols') function cloneNode(obj, parent) { let cloned = new obj.constructor() @@ -32,7 +32,38 @@ function cloneNode(obj, parent) { return cloned } +function sourceOffset(inputCSS, position) { + // Not all custom syntaxes support `offset` in `source.start` and `source.end` + if (position && typeof position.offset !== 'undefined') { + return position.offset + } + + let column = 1 + let line = 1 + let offset = 0 + + for (let i = 0; i < inputCSS.length; i++) { + if (line === position.line && column === position.column) { + offset = i + break + } + + if (inputCSS[i] === '\n') { + column = 1 + line += 1 + } else { + column += 1 + } + } + + return offset +} + class Node { + get proxyOf() { + return this + } + constructor(defaults = {}) { this.raws = {} this[isClean] = false @@ -153,6 +184,11 @@ class Node { } } + /* c8 ignore next 3 */ + markClean() { + this[isClean] = true + } + markDirty() { if (this[isClean]) { this[isClean] = false @@ -169,25 +205,37 @@ class Node { return this.parent.nodes[index + 1] } - positionBy(opts, stringRepresentation) { + positionBy(opts = {}) { let pos = this.source.start if (opts.index) { - pos = this.positionInside(opts.index, stringRepresentation) + pos = this.positionInside(opts.index) } else if (opts.word) { - stringRepresentation = this.toString() + let inputString = + 'document' in this.source.input + ? this.source.input.document + : this.source.input.css + let stringRepresentation = inputString.slice( + sourceOffset(inputString, this.source.start), + sourceOffset(inputString, this.source.end) + ) let index = stringRepresentation.indexOf(opts.word) - if (index !== -1) pos = this.positionInside(index, stringRepresentation) + if (index !== -1) pos = this.positionInside(index) } return pos } - positionInside(index, stringRepresentation) { - let string = stringRepresentation || this.toString() + positionInside(index) { let column = this.source.start.column let line = this.source.start.line - - for (let i = 0; i < index; i++) { - if (string[i] === '\n') { + let inputString = + 'document' in this.source.input + ? this.source.input.document + : this.source.input.css + let offset = sourceOffset(inputString, this.source.start) + let end = offset + index + + for (let i = offset; i < end; i++) { + if (inputString[i] === '\n') { column = 1 line += 1 } else { @@ -195,7 +243,7 @@ class Node { } } - return { column, line } + return { column, line, offset: end } } prev() { @@ -204,33 +252,51 @@ class Node { return this.parent.nodes[index - 1] } - rangeBy(opts) { + rangeBy(opts = {}) { + let inputString = + 'document' in this.source.input + ? this.source.input.document + : this.source.input.css let start = { column: this.source.start.column, - line: this.source.start.line + line: this.source.start.line, + offset: sourceOffset(inputString, this.source.start) } let end = this.source.end ? { - column: this.source.end.column + 1, - line: this.source.end.line - } + column: this.source.end.column + 1, + line: this.source.end.line, + offset: + typeof this.source.end.offset === 'number' + ? // `source.end.offset` is exclusive, so we don't need to add 1 + this.source.end.offset + : // Since line/column in this.source.end is inclusive, + // the `sourceOffset(... , this.source.end)` returns an inclusive offset. + // So, we add 1 to convert it to exclusive. + sourceOffset(inputString, this.source.end) + 1 + } : { - column: start.column + 1, - line: start.line - } + column: start.column + 1, + line: start.line, + offset: start.offset + 1 + } if (opts.word) { - let stringRepresentation = this.toString() + let stringRepresentation = inputString.slice( + sourceOffset(inputString, this.source.start), + sourceOffset(inputString, this.source.end) + ) let index = stringRepresentation.indexOf(opts.word) if (index !== -1) { - start = this.positionInside(index, stringRepresentation) - end = this.positionInside(index + opts.word.length, stringRepresentation) + start = this.positionInside(index) + end = this.positionInside(index + opts.word.length) } } else { if (opts.start) { start = { column: opts.start.column, - line: opts.start.line + line: opts.start.line, + offset: sourceOffset(inputString, opts.start) } } else if (opts.index) { start = this.positionInside(opts.index) @@ -239,9 +305,10 @@ class Node { if (opts.end) { end = { column: opts.end.column, - line: opts.end.line + line: opts.end.line, + offset: sourceOffset(inputString, opts.end) } - } else if (opts.endIndex) { + } else if (typeof opts.endIndex === 'number') { end = this.positionInside(opts.endIndex) } else if (opts.index) { end = this.positionInside(opts.index + 1) @@ -252,7 +319,11 @@ class Node { end.line < start.line || (end.line === start.line && end.column <= start.column) ) { - end = { column: start.column + 1, line: start.line } + end = { + column: start.column + 1, + line: start.line, + offset: start.offset + 1 + } } return { end, start } @@ -327,6 +398,7 @@ class Node { } else if (typeof value === 'object' && value.toJSON) { fixed[name] = value.toJSON(null, inputs) } else if (name === 'source') { + if (value == null) continue let inputId = inputs.get(value.input) if (inputId == null) { inputId = inputsNextIndex @@ -366,15 +438,11 @@ class Node { return result } - warn(result, text, opts) { + warn(result, text, opts = {}) { let data = { node: this } for (let i in opts) data[i] = opts[i] return result.warn(text, data) } - - get proxyOf() { - return this - } } module.exports = Node diff --git a/lib/parse.d.ts b/lib/parse.d.ts index 4c943a4d6..ffe35b439 100644 --- a/lib/parse.d.ts +++ b/lib/parse.d.ts @@ -4,6 +4,6 @@ interface Parse extends Parser { default: Parse } -declare const parse: Parse +declare let parse: Parse export = parse diff --git a/lib/parse.js b/lib/parse.js index 971431f23..00a1037aa 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -1,8 +1,8 @@ 'use strict' let Container = require('./container') -let Parser = require('./parser') let Input = require('./input') +let Parser = require('./parser') function parse(css, opts) { let input = new Input(css, opts) diff --git a/lib/parser.js b/lib/parser.js index e1e2e19e2..b29ff5b2d 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -1,11 +1,11 @@ 'use strict' -let Declaration = require('./declaration') -let tokenizer = require('./tokenize') -let Comment = require('./comment') let AtRule = require('./at-rule') +let Comment = require('./comment') +let Declaration = require('./declaration') let Root = require('./root') let Rule = require('./rule') +let tokenizer = require('./tokenize') const SAFE_COMMENT_NEIGHBOR = { empty: true, @@ -28,7 +28,6 @@ class Parser { this.current = this.root this.spaces = '' this.semicolon = false - this.customProperty = false this.createTokenizer() this.root.source = { input, start: { column: 1, line: 1, offset: 0 } } @@ -144,7 +143,7 @@ class Parser { colon(tokens) { let brackets = 0 - let token, type, prev + let prev, token, type for (let [i, element] of tokens.entries()) { token = element type = token[0] @@ -177,7 +176,7 @@ class Parser { node.source.end.offset++ let text = token[1].slice(2, -2) - if (/^\s*$/.test(text)) { + if (!text.trim()) { node.text = '' node.raws.left = text node.raws.right = '' @@ -268,12 +267,12 @@ class Parser { let str = '' for (let j = i; j > 0; j--) { let type = cache[j][0] - if (str.trim().indexOf('!') === 0 && type !== 'space') { + if (str.trim().startsWith('!') && type !== 'space') { break } str = cache.pop()[1] + str } - if (str.trim().indexOf('!') === 0) { + if (str.trim().startsWith('!')) { node.important = true node.raws.important = str tokens = cache @@ -348,6 +347,8 @@ class Parser { if (prev && prev.type === 'rule' && !prev.raws.ownSemicolon) { prev.raws.ownSemicolon = this.spaces this.spaces = '' + prev.source.end = this.getPosition(token[2]) + prev.source.end.offset += prev.raws.ownSemicolon.length } } } @@ -592,7 +593,7 @@ class Parser { unknownWord(tokens) { throw this.input.error( - 'Unknown word', + 'Unknown word ' + tokens[0][1], { offset: tokens[0][2] }, { offset: tokens[0][2] + tokens[0][1].length } ) diff --git a/lib/postcss.d.mts b/lib/postcss.d.mts index a8ca8c7a1..eaec8681f 100644 --- a/lib/postcss.d.mts +++ b/lib/postcss.d.mts @@ -1,72 +1,66 @@ export { - // postcss function / namespace - default, - - // Value exports from postcss.mjs - stringify, - fromJSON, - // @ts-expect-error This value exists, but it’s untyped. - plugin, - parse, - list, - - document, - comment, - atRule, - rule, - decl, - root, - - CssSyntaxError, - Declaration, - Container, - Processor, - Document, - Comment, - Warning, - AtRule, - Result, - Input, - Rule, - Root, - Node, - // Type-only exports AcceptedPlugin, AnyNode, + atRule, + AtRule, AtRuleProps, Builder, ChildNode, ChildProps, + comment, + Comment, CommentProps, + Container, ContainerProps, + CssSyntaxError, + decl, + Declaration, DeclarationProps, + // postcss function / namespace + default, + document, + Document, DocumentProps, FilePosition, + fromJSON, Helpers, + Input, JSONHydrator, + // This is a class, but it’s not re-exported. That’s why it’s exported as type-only here. + type LazyResult, + list, Message, + Node, NodeErrorOptions, NodeProps, OldPlugin, + parse, Parser, + // @ts-expect-error This value exists, but it’s untyped. + plugin, Plugin, PluginCreator, Position, Postcss, ProcessOptions, + Processor, + Result, + root, + Root, RootProps, + rule, + Rule, RuleProps, Source, SourceMap, SourceMapOptions, Stringifier, + // Value exports from postcss.mjs + stringify, Syntax, TransformCallback, Transformer, - WarningOptions, - - // This is a class, but it’s not re-exported. That’s why it’s exported as type-only here. - type LazyResult, - + Warning, + WarningOptions } from './postcss.js' diff --git a/lib/postcss.d.ts b/lib/postcss.d.ts index 70d758959..667d82092 100644 --- a/lib/postcss.d.ts +++ b/lib/postcss.d.ts @@ -2,7 +2,7 @@ import { RawSourceMap, SourceMapGenerator } from 'source-map-js' import AtRule, { AtRuleProps } from './at-rule.js' import Comment, { CommentProps } from './comment.js' -import Container, { ContainerProps } from './container.js' +import Container, { ContainerProps, NewChild } from './container.js' import CssSyntaxError from './css-syntax-error.js' import Declaration, { DeclarationProps } from './declaration.js' import Document, { DocumentProps } from './document.js' @@ -28,13 +28,22 @@ type DocumentProcessor = ( document: Document, helper: postcss.Helpers ) => Promise | void -type RootProcessor = (root: Root, helper: postcss.Helpers) => Promise | void +type RootProcessor = ( + root: Root, + helper: postcss.Helpers +) => Promise | void type DeclarationProcessor = ( decl: Declaration, helper: postcss.Helpers ) => Promise | void -type RuleProcessor = (rule: Rule, helper: postcss.Helpers) => Promise | void -type AtRuleProcessor = (atRule: AtRule, helper: postcss.Helpers) => Promise | void +type RuleProcessor = ( + rule: Rule, + helper: postcss.Helpers +) => Promise | void +type AtRuleProcessor = ( + atRule: AtRule, + helper: postcss.Helpers +) => Promise | void type CommentProcessor = ( comment: Comment, helper: postcss.Helpers @@ -161,6 +170,7 @@ declare namespace postcss { LazyResult, list, Message, + NewChild, Node, NodeErrorOptions, NodeProps, @@ -176,9 +186,9 @@ declare namespace postcss { WarningOptions } - export type SourceMap = SourceMapGenerator & { + export type SourceMap = { toJSON(): RawSourceMap - } + } & SourceMapGenerator export type Helpers = { postcss: Postcss; result: Result } & Postcss @@ -219,7 +229,7 @@ declare namespace postcss { export interface Parser { ( css: { toString(): string } | string, - opts?: Pick + opts?: Pick ): RootNode } @@ -305,11 +315,16 @@ declare namespace postcss { } export interface ProcessOptions { + /** + * Input file if it is not simple CSS file, but HTML with ' }) + is(root.source?.input.css, 'a {} b {}') + is(root.source?.input.document, '') + + let a = root.first as Rule + + // Offset the source location of `a` to mimic syntaxes like `postcss-html` + a.source = { + end: { + column: 12, + line: 1, + offset: 12 + }, + input: a.source!.input, + start: { + column: 8, + line: 1, + offset: 7 + } + } + + equal(a.positionInside(0), { column: 8, line: 1, offset: 7 }) + equal(a.positionInside(1), { column: 9, line: 1, offset: 8 }) +}) + +test('positionBy() returns position', () => { + let css = parse('a { one: X }') + let a = css.first as Rule + let one = a.first as Declaration + equal(one.positionBy(), { column: 6, line: 1, offset: 5 }) + equal(a.positionBy(), { column: 1, line: 1, offset: 0 }) +}) + +test('positionBy() returns position after AST mutations', () => { + let css = parse('a {\n\tone: 1;\n\ttwo: 2;}') + let a = css.first as Rule + let one = a.first as Declaration + let two = one.next() as Declaration + + equal(a.positionBy(), { column: 1, line: 1, offset: 0 }) + equal(two.positionBy(), { column: 2, line: 3, offset: 14 }) + + one.remove() + + equal(a.positionBy(), { column: 1, line: 1, offset: 0 }) + equal(two.positionBy(), { column: 2, line: 3, offset: 14 }) +}) + +test('positionBy() returns position', () => { + let css = parse('a { one: X }') + let a = css.first as Rule + let one = a.first as Declaration + equal(one.positionBy(), { column: 6, line: 1, offset: 5 }) + equal(a.positionBy(), { column: 1, line: 1, offset: 0 }) +}) + +test('positionBy() returns position after AST mutations', () => { + let css = parse('a {\n\tone: 1;\n\ttwo: 2;}') + let a = css.first as Rule + let one = a.first as Declaration + let two = one.next() as Declaration + + equal(a.positionBy(), { column: 1, line: 1, offset: 0 }) + equal(two.positionBy(), { column: 2, line: 3, offset: 14 }) + + one.remove() + + equal(a.positionBy(), { column: 1, line: 1, offset: 0 }) + equal(two.positionBy(), { column: 2, line: 3, offset: 14 }) }) test('positionBy() returns position for word', () => { let css = parse('a { one: X }') let a = css.first as Rule let one = a.first as Declaration - equal(one.positionBy({ word: 'one' }), { column: 6, line: 1 }) + equal(one.positionBy({ word: 'one' }), { column: 6, line: 1, offset: 5 }) + equal(one.positionBy({ word: 'X' }), { column: 11, line: 1, offset: 10 }) + equal(a.positionBy({ word: '}' }), { column: 14, line: 1, offset: 13 }) +}) + +test('positionBy() returns position for word after AST mutations', () => { + let css = parse('a {\n\tone: 1;\n\ttwo: 2;}') + let a = css.first as Rule + let one = a.first as Declaration + let two = one.next() as Declaration + + equal(a.positionBy({ word: 'two' }), { column: 2, line: 3, offset: 14 }) + equal(two.positionBy({ word: 'two' }), { column: 2, line: 3, offset: 14 }) + + one.remove() + + equal(a.positionBy({ word: 'two' }), { column: 2, line: 3, offset: 14 }) + equal(two.positionBy({ word: 'two' }), { column: 2, line: 3, offset: 14 }) }) test('positionBy() returns position for index', () => { let css = parse('a { one: X }') let a = css.first as Rule let one = a.first as Declaration - equal(one.positionBy({ index: 1 }), { column: 7, line: 1 }) + equal(one.positionBy({ index: 1 }), { column: 7, line: 1, offset: 6 }) +}) + +test('positionBy() returns position for index after AST mutations', () => { + let css = parse('a {\n\tone: 1;\n\ttwo: 2;}') + let a = css.first as Rule + let one = a.first as Declaration + let two = one.next() as Declaration + + equal(a.positionBy({ index: 15 }), { column: 3, line: 3, offset: 15 }) + equal(two.positionBy({ index: 1 }), { column: 3, line: 3, offset: 15 }) + + one.remove() + + equal(a.positionBy({ index: 15 }), { column: 3, line: 3, offset: 15 }) + equal(two.positionBy({ index: 1 }), { column: 3, line: 3, offset: 15 }) +}) + +test('positionBy() supports multi-root documents', () => { + let root = parse('a {} b {}', { document: '' }) + is(root.source?.input.css, 'a {} b {}') + is(root.source?.input.document, '') + + let a = root.first as Rule + + // Offset the source location of `a` to mimic syntaxes like `postcss-html` + a.source = { + end: { + column: 12, + line: 1, + offset: 12 + }, + input: a.source!.input, + start: { + column: 8, + line: 1, + offset: 7 + } + } + + // `offset` is present because the `0` index returns `source.start` + equal(a.positionBy({ index: 0 }), { column: 8, line: 1, offset: 7 }) + equal(a.positionBy({ index: 1 }), { column: 9, line: 1, offset: 8 }) + equal(a.positionBy({ word: 'a' }), { column: 8, line: 1, offset: 7 }) +}) + +test('rangeBy() returns range', () => { + let css = parse('a { one: X }') + let a = css.first as Rule + let one = a.first as Declaration + equal(one.rangeBy(), { + end: { column: 12, line: 1, offset: 11 }, + start: { column: 6, line: 1, offset: 5 } + }) +}) + +test('rangeBy() returns range when offsets are missing', () => { + let css = parse('a { one: X }') + let a = css.first as Rule + let one = a.first as Declaration + + // @ts-expect-error Testing non-standard AST + if (one.source?.start) delete one.source.start.offset + // @ts-expect-error Testing non-standard AST + if (one.source?.end) delete one.source.end.offset + + equal(one.rangeBy(), { + end: { column: 12, line: 1, offset: 11 }, + start: { column: 6, line: 1, offset: 5 } + }) +}) + +test('rangeBy() returns range for empty object even after AST mutations', () => { + let css = parse('a {\n\tone: 1;\n\ttwo: 2;}') + let a = css.first as Rule + let one = a.first as Declaration + let two = one.next() as Declaration + + equal(a.rangeBy(), { + end: { column: 10, line: 3, offset: 22 }, + start: { column: 1, line: 1, offset: 0 } + }) + equal(two.rangeBy(), { + end: { column: 9, line: 3, offset: 21 }, + start: { column: 2, line: 3, offset: 14 } + }) + + one.remove() + + equal(a.rangeBy(), { + end: { column: 10, line: 3, offset: 22 }, + start: { column: 1, line: 1, offset: 0 } + }) + equal(two.rangeBy(), { + end: { column: 9, line: 3, offset: 21 }, + start: { column: 2, line: 3, offset: 14 } + }) +}) + +test('rangeBy() returns range', () => { + let css = parse('a { one: X }') + let a = css.first as Rule + let one = a.first as Declaration + equal(one.rangeBy(), { + end: { column: 12, line: 1, offset: 11 }, + start: { column: 6, line: 1, offset: 5 } + }) +}) + +test('rangeBy() returns range when offsets are missing', () => { + let css = parse('a { one: X }') + let a = css.first as Rule + let one = a.first as Declaration + + // @ts-expect-error Testing non-standard AST + if (one.source?.start) delete one.source.start.offset + // @ts-expect-error Testing non-standard AST + if (one.source?.end) delete one.source.end.offset + + equal(one.rangeBy(), { + end: { column: 12, line: 1, offset: 11 }, + start: { column: 6, line: 1, offset: 5 } + }) +}) + +test('rangeBy() returns range for empty object even after AST mutations', () => { + let css = parse('a {\n\tone: 1;\n\ttwo: 2;}') + let a = css.first as Rule + let one = a.first as Declaration + let two = one.next() as Declaration + + equal(a.rangeBy(), { + end: { column: 10, line: 3, offset: 22 }, + start: { column: 1, line: 1, offset: 0 } + }) + equal(two.rangeBy(), { + end: { column: 9, line: 3, offset: 21 }, + start: { column: 2, line: 3, offset: 14 } + }) + + one.remove() + + equal(a.rangeBy(), { + end: { column: 10, line: 3, offset: 22 }, + start: { column: 1, line: 1, offset: 0 } + }) + equal(two.rangeBy(), { + end: { column: 9, line: 3, offset: 21 }, + start: { column: 2, line: 3, offset: 14 } + }) }) test('rangeBy() returns range for word', () => { @@ -431,18 +684,244 @@ test('rangeBy() returns range for word', () => { let a = css.first as Rule let one = a.first as Declaration equal(one.rangeBy({ word: 'one' }), { - end: { column: 9, line: 1 }, - start: { column: 6, line: 1 } + end: { column: 9, line: 1, offset: 8 }, + start: { column: 6, line: 1, offset: 5 } + }) +}) + +test('rangeBy() returns range for word when offsets are missing', () => { + let css = parse('a { one: X }') + let a = css.first as Rule + let one = a.first as Declaration + + // @ts-expect-error Testing non-standard AST + if (one.source?.start) delete one.source.start.offset + // @ts-expect-error Testing non-standard AST + if (one.source?.end) delete one.source.end.offset + + equal(one.rangeBy({ word: 'one' }), { + end: { column: 9, line: 1, offset: 8 }, + start: { column: 6, line: 1, offset: 5 } + }) +}) + +test('rangeBy() returns range for word even after AST mutations', () => { + let css = parse('a {\n\tone: 1;\n\ttwo: 2;}') + let a = css.first as Rule + let one = a.first as Declaration + let two = one.next() as Declaration + + equal(a.rangeBy({ word: 'two' }), { + end: { column: 5, line: 3, offset: 17 }, + start: { column: 2, line: 3, offset: 14 } + }) + equal(two.rangeBy({ word: 'two' }), { + end: { column: 5, line: 3, offset: 17 }, + start: { column: 2, line: 3, offset: 14 } + }) + + one.remove() + + equal(a.rangeBy({ word: 'two' }), { + end: { column: 5, line: 3, offset: 17 }, + start: { column: 2, line: 3, offset: 14 } + }) + equal(two.rangeBy({ word: 'two' }), { + end: { column: 5, line: 3, offset: 17 }, + start: { column: 2, line: 3, offset: 14 } + }) +}) + +test('rangeBy() returns range for word even after AST mutations when offsets are missing', () => { + let css = parse('a {\n\tone: 1;\n\ttwo: 2;}') + let a = css.first as Rule + let one = a.first as Declaration + let two = one.next() as Declaration + + // @ts-expect-error Testing non-standard AST + if (a.source?.start) delete a.source.start.offset + // @ts-expect-error Testing non-standard AST + if (a.source?.end) delete a.source.end.offset + // @ts-expect-error Testing non-standard AST + if (two.source?.start) delete two.source.start.offset + // @ts-expect-error Testing non-standard AST + if (two.source?.end) delete two.source.end.offset + + equal(a.rangeBy({ word: 'two' }), { + end: { column: 5, line: 3, offset: 17 }, + start: { column: 2, line: 3, offset: 14 } + }) + equal(two.rangeBy({ word: 'two' }), { + end: { column: 5, line: 3, offset: 17 }, + start: { column: 2, line: 3, offset: 14 } + }) + + one.remove() + + equal(a.rangeBy({ word: 'two' }), { + end: { column: 5, line: 3, offset: 17 }, + start: { column: 2, line: 3, offset: 14 } + }) + equal(two.rangeBy({ word: 'two' }), { + end: { column: 5, line: 3, offset: 17 }, + start: { column: 2, line: 3, offset: 14 } }) }) +test('rangeBy() returns range for start and end', () => { + let css = parse('a { one: X }') + let a = css.first as Rule + let one = a.first as Declaration + equal( + one.rangeBy({ end: { column: 9, line: 1 }, start: { column: 7, line: 1 } }), + { + end: { column: 9, line: 1, offset: 8 }, + start: { column: 7, line: 1, offset: 6 } + } + ) +}) + +test('rangeBy() returns range for start and end when offsets are missing', () => { + let css = parse('a { one: X }') + let a = css.first as Rule + let one = a.first as Declaration + + // @ts-expect-error Testing non-standard AST + if (one.source?.start) delete one.source.start.offset + // @ts-expect-error Testing non-standard AST + if (one.source?.end) delete one.source.end.offset + + equal( + one.rangeBy({ end: { column: 9, line: 1 }, start: { column: 7, line: 1 } }), + { + end: { column: 9, line: 1, offset: 8 }, + start: { column: 7, line: 1, offset: 6 } + } + ) +}) + +test('rangeBy() returns range for start and end after AST mutations', () => { + let css = parse('a {\n\tone: 1;\n\ttwo: 2;}') + let a = css.first as Rule + let one = a.first as Declaration + let two = one.next() as Declaration + + equal( + a.rangeBy({ end: { column: 5, line: 3 }, start: { column: 3, line: 3 } }), + { + end: { column: 5, line: 3, offset: 17 }, + start: { column: 3, line: 3, offset: 15 } + } + ) + equal( + two.rangeBy({ end: { column: 5, line: 3 }, start: { column: 3, line: 3 } }), + { + end: { column: 5, line: 3, offset: 17 }, + start: { column: 3, line: 3, offset: 15 } + } + ) + + one.remove() + + equal( + a.rangeBy({ end: { column: 5, line: 3 }, start: { column: 3, line: 3 } }), + { + end: { column: 5, line: 3, offset: 17 }, + start: { column: 3, line: 3, offset: 15 } + } + ) + equal( + two.rangeBy({ end: { column: 5, line: 3 }, start: { column: 3, line: 3 } }), + { + end: { column: 5, line: 3, offset: 17 }, + start: { column: 3, line: 3, offset: 15 } + } + ) +}) + test('rangeBy() returns range for index and endIndex', () => { let css = parse('a { one: X }') let a = css.first as Rule let one = a.first as Declaration equal(one.rangeBy({ endIndex: 3, index: 1 }), { - end: { column: 9, line: 1 }, - start: { column: 7, line: 1 } + end: { column: 9, line: 1, offset: 8 }, + start: { column: 7, line: 1, offset: 6 } + }) +}) + +test('rangeBy() returns range for index and endIndex when offsets are missing', () => { + let css = parse('a { one: X }') + let a = css.first as Rule + let one = a.first as Declaration + + // @ts-expect-error Testing non-standard AST + if (one.source?.start) delete one.source.start.offset + // @ts-expect-error Testing non-standard AST + if (one.source?.end) delete one.source.end.offset + + equal(one.rangeBy({ endIndex: 3, index: 1 }), { + end: { column: 9, line: 1, offset: 8 }, + start: { column: 7, line: 1, offset: 6 } + }) +}) + +test('rangeBy() returns range for index and endIndex after AST mutations', () => { + let css = parse('a {\n\tone: 1;\n\ttwo: 2;}') + let a = css.first as Rule + let one = a.first as Declaration + let two = one.next() as Declaration + + equal(a.rangeBy({ endIndex: 17, index: 15 }), { + end: { column: 5, line: 3, offset: 17 }, + start: { column: 3, line: 3, offset: 15 } + }) + equal(two.rangeBy({ endIndex: 3, index: 1 }), { + end: { column: 5, line: 3, offset: 17 }, + start: { column: 3, line: 3, offset: 15 } + }) + + one.remove() + + equal(a.rangeBy({ endIndex: 17, index: 15 }), { + end: { column: 5, line: 3, offset: 17 }, + start: { column: 3, line: 3, offset: 15 } + }) + equal(two.rangeBy({ endIndex: 3, index: 1 }), { + end: { column: 5, line: 3, offset: 17 }, + start: { column: 3, line: 3, offset: 15 } + }) +}) + +test('rangeBy() supports multi-root documents', () => { + let root = parse('a {} b {}', { document: '' }) + is(root.source?.input.css, 'a {} b {}') + is(root.source?.input.document, '') + + let a = root.first as Rule + + // Offset the source location of `a` to mimic syntaxes like `postcss-html` + a.source = { + end: { + column: 12, + line: 1, + offset: 12 + }, + input: a.source!.input, + start: { + column: 8, + line: 1, + offset: 7 + } + } + + equal(a.rangeBy({ endIndex: 1, index: 0 }), { + end: { column: 9, line: 1, offset: 8 }, + start: { column: 8, line: 1, offset: 7 } + }) + + equal(a.rangeBy({ word: 'a' }), { + end: { column: 9, line: 1, offset: 8 }, + start: { column: 8, line: 1, offset: 7 } }) }) diff --git a/test/old-node.js b/test/old-node.js index 43357955c..9f674c4c1 100644 --- a/test/old-node.js +++ b/test/old-node.js @@ -1,2 +1,27 @@ // eslint-disable-next-line globalThis = Function('return this')() + +let Module = require('module') +let path = require('path') +let originalRequire = Module.prototype.require + +Module.prototype.require = function (request) { + if (request.startsWith('node:')) { + request = request.slice(5) + } + return originalRequire.call(this, request) +} + +process.env.TS_NODE_COMPILER_OPTIONS = JSON.stringify({ + moduleResolution: 'node' +}) + +require( + path.join( + process.cwd(), + 'node_modules', + 'ts-node', + 'register', + 'transpile-only' + ) +) diff --git a/test/postcss.test.ts b/test/postcss.test.ts index 683aef570..fddd982fe 100755 --- a/test/postcss.test.ts +++ b/test/postcss.test.ts @@ -1,8 +1,8 @@ -import postcss = require('../lib/postcss.js') import { restoreAll, spyOn } from 'nanospy' import { test } from 'uvu' import { equal, is, match, throws, type } from 'uvu/assert' +import postcss = require('../lib/postcss.js') import postcssDefault, { PluginCreator, Root } from '../lib/postcss.js' import Processor from '../lib/processor.js' @@ -112,7 +112,7 @@ test('contains list module', () => { test('works with null', () => { throws(() => { - // @ts-expect-error + // @ts-expect-error Testing invalid input postcss([() => {}]).process(null).css }, /PostCSS received null instead of CSS string/) }) diff --git a/test/previous-map.test.ts b/test/previous-map.test.ts index 0f97abca8..efda7ff92 100755 --- a/test/previous-map.test.ts +++ b/test/previous-map.test.ts @@ -162,7 +162,7 @@ test('raises on unknown inline encoding', () => { test('raises on unknown map format', () => { throws(() => { - // @ts-expect-error + // @ts-expect-error Invalid input parse('a{}', { map: { prev: 1 } }) }, 'Unsupported previous source map format: 1') }) diff --git a/test/processor.test.ts b/test/processor.test.ts index f1ed61831..74803073d 100755 --- a/test/processor.test.ts +++ b/test/processor.test.ts @@ -1,4 +1,3 @@ -// @ts-ignore type definitions for nanodelay@1 are wrong. import { delay } from 'nanodelay' import { restoreAll, spyOn } from 'nanospy' import { resolve as pathResolve } from 'path' @@ -103,7 +102,7 @@ test('returns itself', () => { test('throws on wrong format', () => { let pr = new Processor() throws(() => { - // @ts-expect-error + // @ts-expect-error Testing invalid API pr.use(1) }, /1 is not a PostCSS plugin/) }) @@ -300,8 +299,8 @@ test('supports async errors', async () => { let err1 = await catchError(async () => await result) equal(err1, error) - let err2: Error | undefined - result.catch(catched => { + let err2: unknown + result.catch((catched: unknown) => { err2 = catched }) await delay(10) @@ -337,7 +336,7 @@ test('throws error on sync method to async plugin', () => { }, /async/) }) -test('throws a sync call in async running', async () => { +test('throws a sync call in async running', () => { let async = (): Promise => new Promise(resolve => setTimeout(resolve, 1)) @@ -495,7 +494,7 @@ test('throws on syntax as plugin', () => { let processor = new Processor([() => {}]) throws(() => { processor.use({ - // @ts-expect-error + // @ts-expect-error Testing invalid API parse() {} }) }, /syntax/) @@ -518,7 +517,7 @@ test('warns about missed from', async () => { ]) }) -test('returns NoWorkResult object', async () => { +test('returns NoWorkResult object', () => { let result = new Processor().process('a{}') instance(result, NoWorkResult) }) @@ -526,10 +525,10 @@ test('returns NoWorkResult object', async () => { test('without plugins parses CSS only on root access', async () => { let noWorkResult = new Processor().process('a{}') let result = await noWorkResult - // @ts-expect-error + // @ts-expect-error Testing private API type(noWorkResult._root, 'undefined') is(result.root.nodes.length, 1) - // @ts-expect-error + // @ts-expect-error Testing private API not.type(noWorkResult._root, 'undefined') is(noWorkResult.root.nodes.length, 1) }) @@ -543,7 +542,7 @@ test('catches error with empty processor', async () => { let err = await catchError(async () => await noWorkResult) - noWorkResult.catch(e => { + noWorkResult.catch((e: unknown) => { instance(e, CssSyntaxError) }) diff --git a/test/stringifier.test.js b/test/stringifier.test.js index 86ddf2b9c..4414cd46e 100755 --- a/test/stringifier.test.js +++ b/test/stringifier.test.js @@ -285,4 +285,74 @@ test('handles document with three roots, with before and after raws', () => { is(s, 'a.one {}AFTER_ONEa.two {}AFTER_TWOa.three {}AFTER_THREE') }) +test('escapes { + let root = new Root() + root.append(new Rule({ selector: '' })) + root.append(new AtRule({ name: 'media', params: '