├── .editorconfig ├── .github └── workflows │ └── test.yml ├── .gitignore ├── .tape.js ├── CHANGELOG.md ├── CONTRIBUTING.md ├── INSTALL.md ├── LICENSE.md ├── README.md ├── index.js ├── package.json └── test ├── basic.css ├── basic.expect.css └── basic.preserve-false.expect.css /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_style = tab 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | 10 | [*.md] 11 | trim_trailing_whitespace = false 12 | 13 | [*.{json,md,yml}] 14 | indent_size = 2 15 | indent_style = space 16 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | on: 3 | push: 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | node: [12, 16] 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: actions/setup-node@v2 14 | with: 15 | node-version: ${{ matrix.node }} 16 | 17 | - run: yarn install --ignore-scripts 18 | - run: yarn run test 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | index.*.* 3 | package-lock.json 4 | yarn.lock 5 | *.log* 6 | *.result.css 7 | .* 8 | !.editorconfig 9 | !.github 10 | !.gitignore 11 | !.rollup.js 12 | !.tape.js 13 | -------------------------------------------------------------------------------- /.tape.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'basic': { 3 | message: 'supports basic usage' 4 | }, 5 | 'basic:preserve-false': { 6 | message: 'supports { preserve: false } usage', 7 | options: { 8 | preserve: false 9 | } 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changes to PostCSS Pseudo Class Any Link 2 | 3 | ### 7.0.0 (September 17, 2021) 4 | 5 | - Updated: Support for PostCSS 8+ (major). 6 | - Updated: Support for Node v12+ (major). 7 | 8 | ### 6.0.0 (September 17, 2018) 9 | 10 | - Updated: Support for PostCSS v7+ 11 | - Updated: Support for Node v6+ 12 | - Updated: PostCSS Selector Parser 5.0.0-rc.3 (major) 13 | 14 | ### 5.0.0 (May 7, 2018) 15 | 16 | - Updated: `postcss-selector-parser` to v4.0.0 (major) 17 | - Updated: `postcss` to v6.0.22 (patch) 18 | - Changed: Preserves `:any-link` by default 19 | 20 | ### 4.0.0 (May 10, 2017) 21 | 22 | - Added: Support for PostCSS v6 23 | - Added: Support for Node v4 24 | - Removed: `prefix` option, as that would be non-spec 25 | 26 | ### 3.0.1 (December 8, 2016) 27 | 28 | - Updated: Use destructing assignment on plugin options 29 | - Updated: Use template literals 30 | 31 | ### 3.0.0 (December 5, 2016) 32 | 33 | - Updated: boilerplate conventions (Node v6.9.1 LTS) 34 | 35 | ### 1.0.0 (September 1, 2015) 36 | 37 | - Updated: PostCSS 5 38 | - Updated: Develop dependencies 39 | - Updated: ESLint configuration 40 | 41 | ### 0.3.0 (June 16, 2015) 42 | 43 | - Added: Support for complex uses 44 | - Added: Code documentation 45 | - Changed: Coding conventions 46 | 47 | ### 0.2.1 (June 16, 2015) 48 | 49 | - Fixed: postcss-selector-parser is included as a dependency 50 | 51 | ### 0.2.0 (June 15, 2015) 52 | 53 | - Changed: use postcss-selector-parser 54 | 55 | ### 0.1.1 (June 14, 2015) 56 | 57 | Initial release 58 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to PostCSS Pseudo Class Any Link 2 | 3 | You want to help? You rock! Now, take a moment to be sure your contributions 4 | make sense to everyone else. 5 | 6 | ## Reporting Issues 7 | 8 | Found a problem? Want a new feature? 9 | 10 | - See if your issue or idea has [already been reported]. 11 | - Provide a [reduced test case] or a [live example]. 12 | 13 | Remember, a bug is a _demonstrable problem_ caused by _our_ code. 14 | 15 | ## Submitting Pull Requests 16 | 17 | Pull requests are the greatest contributions, so be sure they are focused in 18 | scope and avoid unrelated commits. 19 | 20 | 1. To begin; [fork this project], clone your fork, and add our upstream. 21 | ```bash 22 | # Clone your fork of the repo into the current directory 23 | git clone git@github.com:YOUR_USER/postcss-pseudo-class-any-link.git 24 | 25 | # Navigate to the newly cloned directory 26 | cd postcss-pseudo-class-any-link 27 | 28 | # Assign the original repo to a remote called "upstream" 29 | git remote add upstream git@github.com:jonathantneal/postcss-pseudo-class-any-link.git 30 | 31 | # Install the tools necessary for testing 32 | npm install 33 | ``` 34 | 35 | 2. Create a branch for your feature or fix: 36 | ```bash 37 | # Move into a new branch for your feature 38 | git checkout -b feature/thing 39 | ``` 40 | ```bash 41 | # Move into a new branch for your fix 42 | git checkout -b fix/something 43 | ``` 44 | 45 | 3. If your code follows our practices, then push your feature branch: 46 | ```bash 47 | # Test current code 48 | npm test 49 | ``` 50 | ```bash 51 | # Push the branch for your new feature 52 | git push origin feature/thing 53 | ``` 54 | ```bash 55 | # Or, push the branch for your update 56 | git push origin update/something 57 | ``` 58 | 59 | That’s it! Now [open a pull request] with a clear title and description. 60 | 61 | [already been reported]: issues 62 | [fork this project]: fork 63 | [live example]: https://codepen.io/pen 64 | [open a pull request]: https://help.github.com/articles/using-pull-requests/ 65 | [reduced test case]: https://css-tricks.com/reduced-test-cases/ 66 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | # Installing PostCSS 2 | 3 | [PostCSS Pseudo Class Any Link] runs in all Node environments, with special 4 | instructions for: 5 | 6 | | [Node](#node) | [PostCSS CLI](#postcss-cli) | [Webpack](#webpack) | [Create React App](#create-react-app) | [Gulp](#gulp) | [Grunt](#grunt) | 7 | | --- | --- | --- | --- | --- | --- | 8 | 9 | ## Node 10 | 11 | Add [PostCSS Pseudo Class Any Link] to your project: 12 | 13 | ```bash 14 | npm install postcss-pseudo-class-any-link --save-dev 15 | ``` 16 | 17 | Use [PostCSS Pseudo Class Any Link] to process your CSS: 18 | 19 | ```js 20 | const postcssPseudoClassAnyLink = require('postcss-pseudo-class-any-link'); 21 | 22 | postcssPseudoClassAnyLink.process(YOUR_CSS /*, processOptions, pluginOptions */); 23 | ``` 24 | 25 | Or use it as a [PostCSS] plugin: 26 | 27 | ```js 28 | const postcss = require('postcss'); 29 | const postcssPseudoClassAnyLink = require('postcss-pseudo-class-any-link'); 30 | 31 | postcss([ 32 | postcssPseudoClassAnyLink(/* pluginOptions */) 33 | ]).process(YOUR_CSS /*, processOptions */); 34 | ``` 35 | 36 | ## PostCSS CLI 37 | 38 | Add [PostCSS CLI] to your project: 39 | 40 | ```bash 41 | npm install postcss-cli --save-dev 42 | ``` 43 | 44 | Use [PostCSS Pseudo Class Any Link] in your `postcss.config.js` configuration 45 | file: 46 | 47 | ```js 48 | const postcssPseudoClassAnyLink = require('postcss-pseudo-class-any-link'); 49 | 50 | module.exports = { 51 | plugins: [ 52 | postcssPseudoClassAnyLink(/* pluginOptions */) 53 | ] 54 | } 55 | ``` 56 | 57 | ## Webpack 58 | 59 | Add [PostCSS Loader] to your project: 60 | 61 | ```bash 62 | npm install postcss-loader --save-dev 63 | ``` 64 | 65 | Use [PostCSS Pseudo Class Any Link] in your Webpack configuration: 66 | 67 | ```js 68 | const postcssPseudoClassAnyLink = require('postcss-pseudo-class-any-link'); 69 | 70 | module.exports = { 71 | module: { 72 | rules: [ 73 | { 74 | test: /\.css$/, 75 | use: [ 76 | 'style-loader', 77 | { loader: 'css-loader', options: { importLoaders: 1 } }, 78 | { loader: 'postcss-loader', options: { 79 | ident: 'postcss', 80 | plugins: () => [ 81 | postcssPseudoClassAnyLink(/* pluginOptions */) 82 | ] 83 | } } 84 | ] 85 | } 86 | ] 87 | } 88 | } 89 | ``` 90 | 91 | ## Create React App 92 | 93 | Add [React App Rewired] and [React App Rewire PostCSS] to your project: 94 | 95 | ```bash 96 | npm install react-app-rewired react-app-rewire-postcss --save-dev 97 | ``` 98 | 99 | Use [React App Rewire PostCSS] and [PostCSS Pseudo Class Any Link] in your 100 | `config-overrides.js` file: 101 | 102 | ```js 103 | const reactAppRewirePostcss = require('react-app-rewire-postcss'); 104 | const postcssPseudoClassAnyLink = require('postcss-pseudo-class-any-link'); 105 | 106 | module.exports = config => reactAppRewirePostcss(config, { 107 | plugins: () => [ 108 | postcssPseudoClassAnyLink(/* pluginOptions */) 109 | ] 110 | }); 111 | ``` 112 | 113 | ## Gulp 114 | 115 | Add [Gulp PostCSS] to your project: 116 | 117 | ```bash 118 | npm install gulp-postcss --save-dev 119 | ``` 120 | 121 | Use [PostCSS Pseudo Class Any Link] in your Gulpfile: 122 | 123 | ```js 124 | const postcss = require('gulp-postcss'); 125 | const postcssPseudoClassAnyLink = require('postcss-pseudo-class-any-link'); 126 | 127 | gulp.task('css', () => gulp.src('./src/*.css').pipe( 128 | postcss([ 129 | postcssPseudoClassAnyLink(/* pluginOptions */) 130 | ]) 131 | ).pipe( 132 | gulp.dest('.') 133 | )); 134 | ``` 135 | 136 | ## Grunt 137 | 138 | Add [Grunt PostCSS] to your project: 139 | 140 | ```bash 141 | npm install grunt-postcss --save-dev 142 | ``` 143 | 144 | Use [PostCSS Pseudo Class Any Link] in your Gruntfile: 145 | 146 | ```js 147 | const postcssPseudoClassAnyLink = require('postcss-pseudo-class-any-link'); 148 | 149 | grunt.loadNpmTasks('grunt-postcss'); 150 | 151 | grunt.initConfig({ 152 | postcss: { 153 | options: { 154 | use: [ 155 | postcssPseudoClassAnyLink(/* pluginOptions */) 156 | ] 157 | }, 158 | dist: { 159 | src: '*.css' 160 | } 161 | } 162 | }); 163 | ``` 164 | 165 | [Gulp PostCSS]: https://github.com/postcss/gulp-postcss 166 | [Grunt PostCSS]: https://github.com/nDmitry/grunt-postcss 167 | [PostCSS]: https://github.com/postcss/postcss 168 | [PostCSS CLI]: https://github.com/postcss/postcss-cli 169 | [PostCSS Loader]: https://github.com/postcss/postcss-loader 170 | [PostCSS Pseudo Class Any Link]: https://github.com/jonathantneal/postcss-pseudo-class-any-link 171 | [React App Rewire PostCSS]: https://github.com/csstools/react-app-rewire-postcss 172 | [React App Rewired]: https://github.com/timarney/react-app-rewired 173 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # CC0 1.0 Universal 2 | 3 | ## Statement of Purpose 4 | 5 | The laws of most jurisdictions throughout the world automatically confer 6 | exclusive Copyright and Related Rights (defined below) upon the creator and 7 | subsequent owner(s) (each and all, an “owner”) of an original work of 8 | authorship and/or a database (each, a “Work”). 9 | 10 | Certain owners wish to permanently relinquish those rights to a Work for the 11 | purpose of contributing to a commons of creative, cultural and scientific works 12 | (“Commons”) that the public can reliably and without fear of later claims of 13 | infringement build upon, modify, incorporate in other works, reuse and 14 | redistribute as freely as possible in any form whatsoever and for any purposes, 15 | including without limitation commercial purposes. These owners may contribute 16 | to the Commons to promote the ideal of a free culture and the further 17 | production of creative, cultural and scientific works, or to gain reputation or 18 | greater distribution for their Work in part through the use and efforts of 19 | others. 20 | 21 | For these and/or other purposes and motivations, and without any expectation of 22 | additional consideration or compensation, the person associating CC0 with a 23 | Work (the “Affirmer”), to the extent that he or she is an owner of Copyright 24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and 25 | publicly distribute the Work under its terms, with knowledge of his or her 26 | Copyright and Related Rights in the Work and the meaning and intended legal 27 | effect of CC0 on those rights. 28 | 29 | 1. Copyright and Related Rights. A Work made available under CC0 may be 30 | protected by copyright and related or neighboring rights (“Copyright and 31 | Related Rights”). Copyright and Related Rights include, but are not limited 32 | to, the following: 33 | 1. the right to reproduce, adapt, distribute, perform, display, communicate, 34 | and translate a Work; 35 | 2. moral rights retained by the original author(s) and/or performer(s); 36 | 3. publicity and privacy rights pertaining to a person’s image or likeness 37 | depicted in a Work; 38 | 4. rights protecting against unfair competition in regards to a Work, 39 | subject to the limitations in paragraph 4(i), below; 40 | 5. rights protecting the extraction, dissemination, use and reuse of data in 41 | a Work; 42 | 6. database rights (such as those arising under Directive 96/9/EC of the 43 | European Parliament and of the Council of 11 March 1996 on the legal 44 | protection of databases, and under any national implementation thereof, 45 | including any amended or successor version of such directive); and 46 | 7. other similar, equivalent or corresponding rights throughout the world 47 | based on applicable law or treaty, and any national implementations 48 | thereof. 49 | 50 | 2. Waiver. To the greatest extent permitted by, but not in contravention of, 51 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and 52 | unconditionally waives, abandons, and surrenders all of Affirmer’s Copyright 53 | and Related Rights and associated claims and causes of action, whether now 54 | known or unknown (including existing as well as future claims and causes of 55 | action), in the Work (i) in all territories worldwide, (ii) for the maximum 56 | duration provided by applicable law or treaty (including future time 57 | extensions), (iii) in any current or future medium and for any number of 58 | copies, and (iv) for any purpose whatsoever, including without limitation 59 | commercial, advertising or promotional purposes (the “Waiver”). Affirmer 60 | makes the Waiver for the benefit of each member of the public at large and 61 | to the detriment of Affirmer’s heirs and successors, fully intending that 62 | such Waiver shall not be subject to revocation, rescission, cancellation, 63 | termination, or any other legal or equitable action to disrupt the quiet 64 | enjoyment of the Work by the public as contemplated by Affirmer’s express 65 | Statement of Purpose. 66 | 67 | 3. Public License Fallback. Should any part of the Waiver for any reason be 68 | judged legally invalid or ineffective under applicable law, then the Waiver 69 | shall be preserved to the maximum extent permitted taking into account 70 | Affirmer’s express Statement of Purpose. In addition, to the extent the 71 | Waiver is so judged Affirmer hereby grants to each affected person a 72 | royalty-free, non transferable, non sublicensable, non exclusive, 73 | irrevocable and unconditional license to exercise Affirmer’s Copyright and 74 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 75 | maximum duration provided by applicable law or treaty (including future time 76 | extensions), (iii) in any current or future medium and for any number of 77 | copies, and (iv) for any purpose whatsoever, including without limitation 78 | commercial, advertising or promotional purposes (the “License”). The License 79 | shall be deemed effective as of the date CC0 was applied by Affirmer to the 80 | Work. Should any part of the License for any reason be judged legally 81 | invalid or ineffective under applicable law, such partial invalidity or 82 | ineffectiveness shall not invalidate the remainder of the License, and in 83 | such case Affirmer hereby affirms that he or she will not (i) exercise any 84 | of his or her remaining Copyright and Related Rights in the Work or (ii) 85 | assert any associated claims and causes of action with respect to the Work, 86 | in either case contrary to Affirmer’s express Statement of Purpose. 87 | 88 | 4. Limitations and Disclaimers. 89 | 1. No trademark or patent rights held by Affirmer are waived, abandoned, 90 | surrendered, licensed or otherwise affected by this document. 91 | 2. Affirmer offers the Work as-is and makes no representations or warranties 92 | of any kind concerning the Work, express, implied, statutory or 93 | otherwise, including without limitation warranties of title, 94 | merchantability, fitness for a particular purpose, non infringement, or 95 | the absence of latent or other defects, accuracy, or the present or 96 | absence of errors, whether or not discoverable, all to the greatest 97 | extent permissible under applicable law. 98 | 3. Affirmer disclaims responsibility for clearing rights of other persons 99 | that may apply to the Work or any use thereof, including without 100 | limitation any person’s Copyright and Related Rights in the Work. 101 | Further, Affirmer disclaims responsibility for obtaining any necessary 102 | consents, permissions or other rights required for any use of the Work. 103 | 4. Affirmer understands and acknowledges that Creative Commons is not a 104 | party to this document and has no duty or obligation with respect to this 105 | CC0 or use of the Work. 106 | 107 | For more information, please see 108 | http://creativecommons.org/publicdomain/zero/1.0/. 109 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
⚠️ PostCSS Pseudo Class Any Link was moved to @csstools/postcss-plugins. ⚠️
2 | Read the announcement
3 | 4 | # PostCSS Pseudo Class Any Link [PostCSS Logo][postcss] 5 | 6 | [![NPM Version][npm-img]][npm-url] 7 | [![CSS Standard Status][css-img]][css-url] 8 | [![Build Status][cli-img]][cli-url] 9 | [![Support Chat][git-img]][git-url] 10 | 11 | [PostCSS Pseudo Class Any Link] lets you `:any-link` pseudo-class in CSS, 12 | following the [Selectors] specification. 13 | 14 | ```pcss 15 | nav :any-link > span { 16 | background-color: yellow; 17 | } 18 | 19 | /* becomes */ 20 | 21 | nav :link > span, nav :visited > span { 22 | background-color: yellow; 23 | } 24 | 25 | nav :any-link > span { 26 | background-color: yellow; 27 | } 28 | ``` 29 | 30 | From the [proposal][Selectors]: 31 | 32 | > The `:any-link` pseudo-class represents an element that acts as the source 33 | anchor of a hyperlink. It matches an element if the element would match 34 | `:link` or `:visited`. 35 | 36 | [!['Can I use' table](https://caniuse.bitsofco.de/image/css-any-link.png)](https://caniuse.com/#feat=css-any-link) 37 | 38 | ## Usage 39 | 40 | Add [PostCSS Pseudo Class Any Link] to your project: 41 | 42 | ```bash 43 | npm install postcss postcss-pseudo-class-any-link --save-dev 44 | ``` 45 | 46 | Use [PostCSS Pseudo Class Any Link] to process your CSS: 47 | 48 | ```js 49 | const postcssPseudoClassAnyLink = require('postcss-pseudo-class-any-link'); 50 | 51 | postcssPseudoClassAnyLink.process(YOUR_CSS /*, processOptions, pluginOptions */); 52 | ``` 53 | 54 | Or use it as a [PostCSS] plugin: 55 | 56 | ```js 57 | const postcss = require('postcss'); 58 | const postcssPseudoClassAnyLink = require('postcss-pseudo-class-any-link'); 59 | 60 | postcss([ 61 | postcssPseudoClassAnyLink(/* pluginOptions */) 62 | ]).process(YOUR_CSS /*, processOptions */); 63 | ``` 64 | 65 | [PostCSS Pseudo Class Any Link] runs in all Node environments, with special 66 | instructions for: 67 | 68 | | [Node](INSTALL.md#node) | [PostCSS CLI](INSTALL.md#postcss-cli) | [Webpack](INSTALL.md#webpack) | [Create React App](INSTALL.md#create-react-app) | [Gulp](INSTALL.md#gulp) | [Grunt](INSTALL.md#grunt) | 69 | | --- | --- | --- | --- | --- | --- | 70 | 71 | ## Options 72 | 73 | ### preserve 74 | 75 | The `preserve` option determines whether the original `:any-link` rule is 76 | preserved. By default, it is preserved. 77 | 78 | ```js 79 | postcssPseudoClassAnyLink({ preserve: false }) 80 | ``` 81 | 82 | ```pcss 83 | nav :any-link > span { 84 | background-color: yellow; 85 | } 86 | 87 | /* becomes */ 88 | 89 | nav :link > span, nav :visited > span { 90 | background-color: yellow; 91 | } 92 | ``` 93 | 94 | [cli-img]: https://github.com/csstools/postcss-pseudo-class-any-link/workflows/test/badge.svg 95 | [cli-url]: https://github.com/csstools/postcss-pseudo-class-any-link/actions/workflows/test.yml?query=workflow/test 96 | [css-img]: https://cssdb.org/badge/any-link-pseudo-class.svg 97 | [css-url]: https://cssdb.org/#any-link-pseudo-class 98 | [git-img]: https://img.shields.io/badge/support-chat-blue.svg 99 | [git-url]: https://gitter.im/postcss/postcss 100 | [npm-img]: https://img.shields.io/npm/v/postcss-pseudo-class-any-link.svg 101 | [npm-url]: https://www.npmjs.com/package/postcss-pseudo-class-any-link 102 | 103 | [Gulp PostCSS]: https://github.com/postcss/gulp-postcss 104 | [Grunt PostCSS]: https://github.com/nDmitry/grunt-postcss 105 | [PostCSS]: https://github.com/postcss/postcss 106 | [PostCSS Loader]: https://github.com/postcss/postcss-loader 107 | [PostCSS Pseudo Class Any Link]: https://github.com/jonathantneal/postcss-pseudo-class-any-link 108 | [Selectors]: https://www.w3.org/TR/selectors-4/#the-any-link-pseudo 109 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const parser = require('postcss-selector-parser'); 2 | 3 | const anyAnyLinkMatch = /:any-link/; 4 | 5 | /** 6 | * @param {{preserve?: boolean}} opts 7 | * @returns {import('postcss').Plugin} 8 | */ 9 | module.exports = function creator(opts) { 10 | const preserve = 'preserve' in Object(opts) ? Boolean(opts.preserve) : true; 11 | 12 | return { 13 | postcssPlugin: 'postcss-pseudo-class-any-link', 14 | Rule(rule) { 15 | if (!anyAnyLinkMatch.test(rule.selector)) { 16 | return; 17 | } 18 | 19 | const rawSelector = rule.raws.selector && rule.raws.selector.raw || rule.selector; 20 | 21 | // workaround for https://github.com/postcss/postcss-selector-parser/issues/28#issuecomment-171910556 22 | if (rawSelector[rawSelector.length - 1] !== ':') { 23 | // update the selector 24 | const updatedSelector = parser(selectors => { 25 | // cache variables 26 | let node; 27 | let nodeIndex; 28 | let selector; 29 | let selectorLink; 30 | let selectorVisited; 31 | 32 | // cache the selector index 33 | let selectorIndex = -1; 34 | 35 | // for each selector 36 | while (selector = selectors.nodes[++selectorIndex]) { 37 | // reset the node index 38 | nodeIndex = -1; 39 | 40 | // for each node 41 | while (node = selector.nodes[++nodeIndex]) { 42 | // if the node value matches the any-link value 43 | if (node.value === ':any-link') { 44 | // clone the selector 45 | selectorLink = selector.clone(); 46 | selectorVisited = selector.clone(); 47 | 48 | // update the matching clone values 49 | selectorLink.nodes[nodeIndex].value = ':link'; 50 | selectorVisited.nodes[nodeIndex].value = ':visited'; 51 | 52 | // replace the selector with the clones and roll back the selector index 53 | selectors.nodes.splice(selectorIndex--, 1, selectorLink, selectorVisited); 54 | 55 | // stop updating the selector 56 | break; 57 | } 58 | } 59 | } 60 | }).processSync(rawSelector); 61 | 62 | if (updatedSelector !== rawSelector) { 63 | if (preserve) { 64 | rule.cloneBefore({ 65 | selector: updatedSelector 66 | }); 67 | } else { 68 | rule.selector = updatedSelector; 69 | } 70 | } 71 | } 72 | } 73 | } 74 | } 75 | 76 | module.exports.postcss = true; 77 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "postcss-pseudo-class-any-link", 3 | "version": "7.0.0", 4 | "description": "Use the :any-link pseudo-class in CSS", 5 | "author": "Jonathan Neal ", 6 | "license": "CC0-1.0", 7 | "repository": "jonathantneal/postcss-pseudo-class-any-link", 8 | "homepage": "https://github.com/jonathantneal/postcss-pseudo-class-any-link#readme", 9 | "bugs": "https://github.com/jonathantneal/postcss-pseudo-class-any-link/issues", 10 | "main": "index.js", 11 | "scripts": { 12 | "prepublishOnly": "npm test", 13 | "test": "npm run test:js && npm run test:tape", 14 | "test:js": "eslint *.js --cache --ignore-path .gitignore --quiet", 15 | "test:tape": "postcss-tape" 16 | }, 17 | "engines": { 18 | "node": ">=12" 19 | }, 20 | "peerDependencies": { 21 | "postcss": "^8.3" 22 | }, 23 | "dependencies": { 24 | "postcss-selector-parser": "^6" 25 | }, 26 | "devDependencies": { 27 | "eslint": "7.32.0", 28 | "postcss": "8.3.6", 29 | "postcss-tape": "6.0.1" 30 | }, 31 | "eslintConfig": { 32 | "env": { 33 | "browser": true, 34 | "es6": true, 35 | "node": true 36 | }, 37 | "parserOptions": { 38 | "sourceType": "module" 39 | }, 40 | "root": true 41 | }, 42 | "keywords": [ 43 | "postcss", 44 | "css", 45 | "postcss-plugin", 46 | "link", 47 | "visited", 48 | "any-link", 49 | "a", 50 | "area", 51 | "hyperlink", 52 | "href" 53 | ] 54 | } 55 | -------------------------------------------------------------------------------- /test/basic.css: -------------------------------------------------------------------------------- 1 | :any-link { 2 | background: blue; 3 | } 4 | 5 | :any-link, 6 | ul a:any-link > span { 7 | background: blue; 8 | } 9 | 10 | :any-link :any-link { 11 | background: blue; 12 | } 13 | -------------------------------------------------------------------------------- /test/basic.expect.css: -------------------------------------------------------------------------------- 1 | :link,:visited { 2 | background: blue; 3 | } 4 | 5 | :any-link { 6 | background: blue; 7 | } 8 | 9 | :link,:visited, 10 | ul a:link > span, 11 | ul a:visited > span { 12 | background: blue; 13 | } 14 | 15 | :any-link, 16 | ul a:any-link > span { 17 | background: blue; 18 | } 19 | 20 | :link :link,:link :visited,:visited :link,:visited :visited { 21 | background: blue; 22 | } 23 | 24 | :any-link :any-link { 25 | background: blue; 26 | } 27 | -------------------------------------------------------------------------------- /test/basic.preserve-false.expect.css: -------------------------------------------------------------------------------- 1 | :link,:visited { 2 | background: blue; 3 | } 4 | 5 | :link,:visited, 6 | ul a:link > span, 7 | ul a:visited > span { 8 | background: blue; 9 | } 10 | 11 | :link :link,:link :visited,:visited :link,:visited :visited { 12 | background: blue; 13 | } 14 | --------------------------------------------------------------------------------