├── .editorconfig
├── .github
└── workflows
│ └── test.yml
├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── index.test.mjs
├── package-lock.json
├── package.json
├── src
├── index.mjs
└── lib
│ ├── get-custom-media-from-imports.mjs
│ ├── get-custom-media-from-root.mjs
│ └── parse-media.mjs
└── test
└── import-custom-media.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 | branches:
5 | - 'main'
6 | - 'master'
7 | pull_request:
8 | workflow_dispatch:
9 |
10 | defaults:
11 | run:
12 | shell: bash
13 |
14 | jobs:
15 | test:
16 | runs-on: ubuntu-latest
17 | steps:
18 | - uses: actions/checkout@v4
19 | with:
20 | fetch-depth: 1
21 | - uses: actions/setup-node@v4
22 | with:
23 | node-version: lts/*
24 |
25 | - name: npm ci
26 | run: |
27 | npm ci --ignore-scripts
28 |
29 | - name: npm test
30 | run: |
31 | npm test
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | *.log*
3 | !.editorconfig
4 | !.gitignore
5 | !.rollup.js
6 | !.tape.js
7 | !.travis.yml
8 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changes to Media Use Custom Media
2 |
3 | ### 4.0.0 (Dec 10, 2023)
4 |
5 | - Updated: peer `stylelint` to >=16 (breaking)
6 | - Removed `false` option, use `never` instead
7 |
8 | ### 3.0.0 (Dec 10, 2023)
9 |
10 | - Updated: peer `stylelint` to 10 - 15 (major)
11 |
12 | This package is in need of some larger maintenance and we can't guarantee that this package actually works with Stylelint 15.
13 | We however do not want a technical hurdle like a version constraint to get in the way.
14 |
15 | ### 2.0.1 (Nov 6, 2022)
16 |
17 | - Updated: peer `stylelint` to 10 - 14 (patch)
18 |
19 | ### 2.0.0 (May 12, 2020)
20 |
21 | - Updated: peer `stylelint` to 10 - 13 (major)
22 | - Updated: Node 10+ compatibility (major)
23 |
24 | ### 1.0.0 (September 25, 2018)
25 |
26 | - Initial version
27 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Media Use Custom Media
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/stylelint-media-use-custom-media.git
24 |
25 | # Navigate to the newly cloned directory
26 | cd stylelint-media-use-custom-media
27 |
28 | # Assign the original repo to a remote called "upstream"
29 | git remote add upstream git@github.com:csstools/stylelint-media-use-custom-media.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 |
--------------------------------------------------------------------------------
/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 | # Media Use Custom Media [
][stylelint]
2 |
3 | [![NPM Version][npm-img]][npm-url]
4 | [](https://github.com/csstools/stylelint-media-use-custom-media/actions/workflows/test.yml)
5 | [![Support Chat][git-img]][git-url]
6 |
7 | [Media Use Custom Media] is a [stylelint] rule to enforce usage of custom media
8 | queries in CSS.
9 |
10 | ## Usage
11 |
12 | Add [stylelint] and [Media Use Custom Media] to your project.
13 |
14 | ```bash
15 | npm install stylelint stylelint-media-use-custom-media --save-dev
16 | ```
17 |
18 | Add [Media Use Custom Media] to your [stylelint configuration].
19 |
20 | ```js
21 | {
22 | "plugins": [
23 | "stylelint-media-use-custom-media"
24 | ],
25 | "rules": {
26 | "csstools/media-use-custom-media": "always" || "always-known" || "known" || "never" || "ignore"
27 | }
28 | }
29 | ```
30 |
31 | ## Options
32 |
33 | ### always
34 |
35 | If the first option is `"always"` or `true`, then [Media Use Custom Media]
36 | requires all `@media` queries to use Custom Media, and the following patterns
37 | are _not_ considered violations:
38 |
39 | ```pcss
40 | @media (--sm) {}
41 |
42 | @media (--sm), (--md) {}
43 |
44 | @media screen and (--sm) {}
45 | ```
46 |
47 | While the following patterns are considered violations:
48 |
49 | ```pcss
50 | @media (max-width: 40rem) {}
51 |
52 | @media (max-width: 40rem), (--md) {}
53 | ```
54 |
55 | ### never
56 |
57 | If the first option is `"never"`, then [Media Use Custom Media]
58 | requires all `@media` queries to not use Custom Media, and the following
59 | patterns are _not_ considered violations:
60 |
61 | ```pcss
62 | @media (max-width: 40rem) {}
63 |
64 | @media screen and (max-width: 40rem) {}
65 | ```
66 |
67 | While the following patterns are considered violations:
68 |
69 | ```pcss
70 | @media (--md) {}
71 |
72 | @media screen and (--md) {}
73 |
74 | @media (--md), (max-width: 40rem) {}
75 | ```
76 |
77 | ### known
78 |
79 | If the first option is `"known"`, then [Media Use Custom Media] requires all
80 | `@media` queries referencing Custom Media to be known from either
81 | `@custom-media` declarations in the file or imported using the second
82 | option. Then the following patterns are _not_ considered violations:
83 |
84 | ```pcss
85 | @custom-media --sm (min-width: 40rem);
86 |
87 | @media (--sm) {}
88 |
89 | @media (--sm), (min-width: 40rem) {}
90 | ```
91 |
92 | While the following patterns are considered violations:
93 |
94 | ```pcss
95 | @media (--md) {}
96 |
97 | @media (--md), (min-width: 40rem) {}
98 | ```
99 |
100 | ### always-known
101 |
102 | If the first option is `"always-known"`, then [Media Use Custom Media] requires all
103 | `@media` queries to use known Custom Media from either `@custom-media`
104 | declarations in the file or imported using the second option. Then the
105 | following patterns are _not_ considered violations:
106 |
107 | ```pcss
108 | @custom-media --sm (min-width: 40rem);
109 |
110 | @media (--sm) {}
111 | ```
112 |
113 | While the following patterns are considered violations:
114 |
115 | ```pcss
116 | @custom-media --sm (min-width: 40rem);
117 |
118 | @media (--sm), (min-width: 40rem) {}
119 |
120 | @media (--md) {}
121 | ```
122 |
123 | ### ignore
124 |
125 | If the first option is `"ignore"` or `null`, then [Media Use Custom Media] does
126 | nothing.
127 |
128 | ---
129 |
130 | ### importFrom
131 |
132 | When the first option is `"always-known"` or `"known"`, then the second option
133 | can specify sources where Custom Properties should be imported from by using an
134 | `importFrom` key. These imports might be CSS, JS, and JSON files, functions,
135 | and directly passed objects.
136 |
137 | ```js
138 | // .stylelintrc
139 | {
140 | "plugins": [
141 | "stylelint-media-use-custom-media"
142 | ],
143 | "rules": {
144 | "csstools/media-use-custom-media": ["known", {
145 | "importFrom": [
146 | "path/to/file.css", // => @custom-media --sm (min-width: 40rem);
147 | "path/to/file.json" // => { "custom-media": { "--sm": "(min-width: 40rem)" } }
148 | ]
149 | }
150 | }
151 | }
152 | ```
153 |
154 | [git-img]: https://img.shields.io/badge/support-chat-blue.svg
155 | [git-url]: https://gitter.im/stylelint/stylelint
156 | [npm-img]: https://img.shields.io/npm/v/stylelint-media-use-custom-media.svg
157 | [npm-url]: https://www.npmjs.com/package/stylelint-media-use-custom-media
158 |
159 | [stylelint]: https://github.com/stylelint/stylelint
160 | [stylelint configuration]: https://github.com/stylelint/stylelint/blob/master/docs/user-guide/configuration.md#readme
161 | [Media Use Custom Media]: https://github.com/csstools/stylelint-media-use-custom-media
162 |
--------------------------------------------------------------------------------
/index.test.mjs:
--------------------------------------------------------------------------------
1 | import { testRule } from 'stylelint-test-rule-node';
2 | import plugin from './src/index.mjs';
3 |
4 | const rule = plugin.rule;
5 | const messages = plugin.rule.messages;
6 |
7 | let accept = [], reject = [];
8 |
9 | /* Test basic checks
10 | /* ========================================================================== */
11 |
12 | testRule({ plugins: ['./src/index.mjs'], ruleName: rule.ruleName, config: 'ignore', accept: [''] });
13 | testRule({ plugins: ['./src/index.mjs'], ruleName: rule.ruleName, config: null, accept: [''] });
14 | testRule({ plugins: ['./src/index.mjs'], ruleName: rule.ruleName, config: 'always', accept: [''] });
15 | testRule({ plugins: ['./src/index.mjs'], ruleName: rule.ruleName, config: true, accept: [''] });
16 | testRule({ plugins: ['./src/index.mjs'], ruleName: rule.ruleName, config: 'never', accept: [''] });
17 |
18 | // /* Test "ignore"
19 | // /* ========================================================================== */
20 |
21 | accept = [
22 | { code: '@media (--sm) {}', description: 'valid custom media' },
23 | { code: '@media (min-width: 40rem) {}', description: 'invalid custom media' }
24 | ];
25 |
26 | testRule({ plugins: ['./src/index.mjs'], ruleName: rule.ruleName, config: 'ignore', accept: accept });
27 | testRule({ plugins: ['./src/index.mjs'], ruleName: rule.ruleName, config: null, accept: accept });
28 |
29 | // /* Test "always"
30 | // /* ========================================================================== */
31 |
32 | accept = [
33 | { code: '@media (--sm) {}', description: 'valid custom media' },
34 | { code: '@media screen and (--sm) {}', description: 'valid custom media' },
35 | { code: '@media not print and (--sm) {}', description: 'valid custom media' },
36 | { code: '@media screen and (--sm), (--md) {}', description: 'valid custom media' },
37 | { code: '@media not print and (--sm), (--md) {}', description: 'valid custom media' }
38 | ];
39 |
40 | reject = [
41 | {
42 | code: '@media (min-width: 40rem) {}',
43 | description: 'invalid custom media',
44 | message: messages.expected('(min-width: 40rem)'),
45 | },
46 | {
47 | code: '@media screen and (min-width: 40rem) {}',
48 | description: 'invalid custom media',
49 | message: messages.expected('screen and (min-width: 40rem)'),
50 | },
51 | {
52 | code: '@media not print and (min-width: 40rem) {}',
53 | description: 'invalid custom media',
54 | message: messages.expected('not print and (min-width: 40rem)'),
55 | },
56 | {
57 | code: '@media screen and (min-width: 40rem), (--md) {}',
58 | description: 'invalid custom media',
59 | message: messages.expected('screen and (min-width: 40rem), (--md)'),
60 | },
61 | {
62 | code: '@media not print and (min-width: 40rem), (--md) {}',
63 | description: 'invalid custom media',
64 | message: messages.expected('not print and (min-width: 40rem), (--md)'),
65 | },
66 | {
67 | code: '@media (--md), screen and (min-width: 40rem) {}',
68 | description: 'invalid custom media',
69 | message: messages.expected('(--md), screen and (min-width: 40rem)'),
70 | },
71 | {
72 | code: '@media (--md), not print and (min-width: 40rem) {}',
73 | description: 'invalid custom media',
74 | message: messages.expected('(--md), not print and (min-width: 40rem)'),
75 | }
76 | ];
77 |
78 | testRule({ plugins: ['./src/index.mjs'], ruleName: rule.ruleName, config: 'always', accept: accept, reject: reject });
79 | testRule({ plugins: ['./src/index.mjs'], ruleName: rule.ruleName, config: true, accept: accept, reject: reject });
80 |
81 | // /* Test "never"
82 | // /* ========================================================================== */
83 |
84 | accept = [
85 | { code: '@media (min-width: 40rem) {}', description: 'valid custom media' }
86 | ];
87 |
88 | reject = [
89 | { code: '@media (--sm) {}', description: 'invalid custom media', message: messages.unexpected('(--sm)') }
90 | ];
91 |
92 | testRule({ plugins: ['./src/index.mjs'], ruleName: rule.ruleName, config: 'never', accept: accept, reject: reject });
93 |
94 | // /* Test "known", [ "known", { importFrom } ] functionality
95 | // /* ========================================================================== */
96 |
97 | accept = [
98 | { code: '@custom-media --sm (min-width: 40rem); @media (--sm) {} @media (min-width: 40em) {}', description: 'known media' }
99 | ];
100 |
101 | reject = [
102 | { code: '@media (--md) {}', description: 'unknown media', message: messages.expected('(--md)') },
103 | ];
104 |
105 | testRule({ plugins: ['./src/index.mjs'], ruleName: rule.ruleName, config: 'known', accept: accept, reject: reject });
106 |
107 | accept = [
108 | { code: '@media (--sm) {} @media (min-width: 40em) {}', description: 'known media' }
109 | ];
110 |
111 | testRule({
112 | plugins: ['./src/index.mjs'], ruleName: rule.ruleName, config: [
113 | 'known',
114 | { importFrom: { customMedia: { '--sm': '(min-width: 40em)' } } }
115 | ], accept: accept, reject: reject });
116 |
117 | // /* Test "always-known", [ "always-known", { importFrom } ] functionality
118 | // /* ========================================================================== */
119 |
120 | accept = [
121 | { code: '@custom-media --sm (min-width: 40rem); @media (--sm) {}', description: 'known custom media' }
122 | ];
123 |
124 | reject = [
125 | { code: '@media (--md) {}', description: 'unknown custom media', message: messages.expected('(--md)') },
126 | { code: '@media (min-width: 40em) {}', description: 'not custom media', message: messages.expected('(min-width: 40em)') }
127 | ];
128 |
129 | testRule({ plugins: ['./src/index.mjs'], ruleName: rule.ruleName, config: 'always-known', accept: accept, reject: reject });
130 |
131 | accept = [
132 | { code: '@media (--sm) {}', description: 'known custom media' }
133 | ];
134 |
135 | testRule({
136 | plugins: ['./src/index.mjs'], ruleName: rule.ruleName, config: [
137 | 'always-known',
138 | { importFrom: { customMedia: { '--sm': '(min-width: 40em)' } } }
139 | ], accept: accept, reject: reject
140 | });
141 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "stylelint-media-use-custom-media",
3 | "version": "4.0.0",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "stylelint-media-use-custom-media",
9 | "version": "4.0.0",
10 | "license": "CC0-1.0",
11 | "devDependencies": {
12 | "stylelint": "^16.0.0",
13 | "stylelint-test-rule-node": "^0.2.0"
14 | },
15 | "engines": {
16 | "node": ">=18.12.0"
17 | },
18 | "peerDependencies": {
19 | "stylelint": ">=16"
20 | }
21 | },
22 | "node_modules/@babel/code-frame": {
23 | "version": "7.26.2",
24 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
25 | "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
26 | "dev": true,
27 | "license": "MIT",
28 | "dependencies": {
29 | "@babel/helper-validator-identifier": "^7.25.9",
30 | "js-tokens": "^4.0.0",
31 | "picocolors": "^1.0.0"
32 | },
33 | "engines": {
34 | "node": ">=6.9.0"
35 | }
36 | },
37 | "node_modules/@babel/helper-validator-identifier": {
38 | "version": "7.25.9",
39 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
40 | "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
41 | "dev": true,
42 | "license": "MIT",
43 | "engines": {
44 | "node": ">=6.9.0"
45 | }
46 | },
47 | "node_modules/@csstools/css-parser-algorithms": {
48 | "version": "3.0.4",
49 | "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz",
50 | "integrity": "sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==",
51 | "dev": true,
52 | "funding": [
53 | {
54 | "type": "github",
55 | "url": "https://github.com/sponsors/csstools"
56 | },
57 | {
58 | "type": "opencollective",
59 | "url": "https://opencollective.com/csstools"
60 | }
61 | ],
62 | "license": "MIT",
63 | "engines": {
64 | "node": ">=18"
65 | },
66 | "peerDependencies": {
67 | "@csstools/css-tokenizer": "^3.0.3"
68 | }
69 | },
70 | "node_modules/@csstools/css-tokenizer": {
71 | "version": "3.0.3",
72 | "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz",
73 | "integrity": "sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==",
74 | "dev": true,
75 | "funding": [
76 | {
77 | "type": "github",
78 | "url": "https://github.com/sponsors/csstools"
79 | },
80 | {
81 | "type": "opencollective",
82 | "url": "https://opencollective.com/csstools"
83 | }
84 | ],
85 | "license": "MIT",
86 | "engines": {
87 | "node": ">=18"
88 | }
89 | },
90 | "node_modules/@csstools/media-query-list-parser": {
91 | "version": "4.0.2",
92 | "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.2.tgz",
93 | "integrity": "sha512-EUos465uvVvMJehckATTlNqGj4UJWkTmdWuDMjqvSUkjGpmOyFZBVwb4knxCm/k2GMTXY+c/5RkdndzFYWeX5A==",
94 | "dev": true,
95 | "funding": [
96 | {
97 | "type": "github",
98 | "url": "https://github.com/sponsors/csstools"
99 | },
100 | {
101 | "type": "opencollective",
102 | "url": "https://opencollective.com/csstools"
103 | }
104 | ],
105 | "license": "MIT",
106 | "engines": {
107 | "node": ">=18"
108 | },
109 | "peerDependencies": {
110 | "@csstools/css-parser-algorithms": "^3.0.4",
111 | "@csstools/css-tokenizer": "^3.0.3"
112 | }
113 | },
114 | "node_modules/@csstools/selector-specificity": {
115 | "version": "5.0.0",
116 | "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz",
117 | "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==",
118 | "dev": true,
119 | "funding": [
120 | {
121 | "type": "github",
122 | "url": "https://github.com/sponsors/csstools"
123 | },
124 | {
125 | "type": "opencollective",
126 | "url": "https://opencollective.com/csstools"
127 | }
128 | ],
129 | "license": "MIT-0",
130 | "engines": {
131 | "node": ">=18"
132 | },
133 | "peerDependencies": {
134 | "postcss-selector-parser": "^7.0.0"
135 | }
136 | },
137 | "node_modules/@dual-bundle/import-meta-resolve": {
138 | "version": "4.1.0",
139 | "resolved": "https://registry.npmjs.org/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz",
140 | "integrity": "sha512-+nxncfwHM5SgAtrVzgpzJOI1ol0PkumhVo469KCf9lUi21IGcY90G98VuHm9VRrUypmAzawAHO9bs6hqeADaVg==",
141 | "dev": true,
142 | "license": "MIT",
143 | "funding": {
144 | "type": "github",
145 | "url": "https://github.com/sponsors/wooorm"
146 | }
147 | },
148 | "node_modules/@nodelib/fs.scandir": {
149 | "version": "2.1.5",
150 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
151 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
152 | "dev": true,
153 | "license": "MIT",
154 | "dependencies": {
155 | "@nodelib/fs.stat": "2.0.5",
156 | "run-parallel": "^1.1.9"
157 | },
158 | "engines": {
159 | "node": ">= 8"
160 | }
161 | },
162 | "node_modules/@nodelib/fs.stat": {
163 | "version": "2.0.5",
164 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
165 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
166 | "dev": true,
167 | "license": "MIT",
168 | "engines": {
169 | "node": ">= 8"
170 | }
171 | },
172 | "node_modules/@nodelib/fs.walk": {
173 | "version": "1.2.8",
174 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
175 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
176 | "dev": true,
177 | "license": "MIT",
178 | "dependencies": {
179 | "@nodelib/fs.scandir": "2.1.5",
180 | "fastq": "^1.6.0"
181 | },
182 | "engines": {
183 | "node": ">= 8"
184 | }
185 | },
186 | "node_modules/ajv": {
187 | "version": "8.17.1",
188 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
189 | "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
190 | "dev": true,
191 | "license": "MIT",
192 | "dependencies": {
193 | "fast-deep-equal": "^3.1.3",
194 | "fast-uri": "^3.0.1",
195 | "json-schema-traverse": "^1.0.0",
196 | "require-from-string": "^2.0.2"
197 | },
198 | "funding": {
199 | "type": "github",
200 | "url": "https://github.com/sponsors/epoberezkin"
201 | }
202 | },
203 | "node_modules/ansi-regex": {
204 | "version": "5.0.1",
205 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
206 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
207 | "dev": true,
208 | "license": "MIT",
209 | "engines": {
210 | "node": ">=8"
211 | }
212 | },
213 | "node_modules/ansi-styles": {
214 | "version": "4.3.0",
215 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
216 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
217 | "dev": true,
218 | "license": "MIT",
219 | "dependencies": {
220 | "color-convert": "^2.0.1"
221 | },
222 | "engines": {
223 | "node": ">=8"
224 | },
225 | "funding": {
226 | "url": "https://github.com/chalk/ansi-styles?sponsor=1"
227 | }
228 | },
229 | "node_modules/argparse": {
230 | "version": "2.0.1",
231 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
232 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
233 | "dev": true,
234 | "license": "Python-2.0"
235 | },
236 | "node_modules/array-union": {
237 | "version": "2.1.0",
238 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
239 | "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
240 | "dev": true,
241 | "license": "MIT",
242 | "engines": {
243 | "node": ">=8"
244 | }
245 | },
246 | "node_modules/astral-regex": {
247 | "version": "2.0.0",
248 | "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
249 | "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
250 | "dev": true,
251 | "license": "MIT",
252 | "engines": {
253 | "node": ">=8"
254 | }
255 | },
256 | "node_modules/balanced-match": {
257 | "version": "2.0.0",
258 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz",
259 | "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==",
260 | "dev": true,
261 | "license": "MIT"
262 | },
263 | "node_modules/braces": {
264 | "version": "3.0.3",
265 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
266 | "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
267 | "dev": true,
268 | "license": "MIT",
269 | "dependencies": {
270 | "fill-range": "^7.1.1"
271 | },
272 | "engines": {
273 | "node": ">=8"
274 | }
275 | },
276 | "node_modules/callsites": {
277 | "version": "3.1.0",
278 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
279 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
280 | "dev": true,
281 | "license": "MIT",
282 | "engines": {
283 | "node": ">=6"
284 | }
285 | },
286 | "node_modules/color-convert": {
287 | "version": "2.0.1",
288 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
289 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
290 | "dev": true,
291 | "license": "MIT",
292 | "dependencies": {
293 | "color-name": "~1.1.4"
294 | },
295 | "engines": {
296 | "node": ">=7.0.0"
297 | }
298 | },
299 | "node_modules/color-name": {
300 | "version": "1.1.4",
301 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
302 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
303 | "dev": true,
304 | "license": "MIT"
305 | },
306 | "node_modules/colord": {
307 | "version": "2.9.3",
308 | "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz",
309 | "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==",
310 | "dev": true,
311 | "license": "MIT"
312 | },
313 | "node_modules/cosmiconfig": {
314 | "version": "9.0.0",
315 | "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz",
316 | "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==",
317 | "dev": true,
318 | "license": "MIT",
319 | "dependencies": {
320 | "env-paths": "^2.2.1",
321 | "import-fresh": "^3.3.0",
322 | "js-yaml": "^4.1.0",
323 | "parse-json": "^5.2.0"
324 | },
325 | "engines": {
326 | "node": ">=14"
327 | },
328 | "funding": {
329 | "url": "https://github.com/sponsors/d-fischer"
330 | },
331 | "peerDependencies": {
332 | "typescript": ">=4.9.5"
333 | },
334 | "peerDependenciesMeta": {
335 | "typescript": {
336 | "optional": true
337 | }
338 | }
339 | },
340 | "node_modules/css-functions-list": {
341 | "version": "3.2.3",
342 | "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.3.tgz",
343 | "integrity": "sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==",
344 | "dev": true,
345 | "license": "MIT",
346 | "engines": {
347 | "node": ">=12 || >=16"
348 | }
349 | },
350 | "node_modules/css-tree": {
351 | "version": "3.1.0",
352 | "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz",
353 | "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==",
354 | "dev": true,
355 | "license": "MIT",
356 | "dependencies": {
357 | "mdn-data": "2.12.2",
358 | "source-map-js": "^1.0.1"
359 | },
360 | "engines": {
361 | "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
362 | }
363 | },
364 | "node_modules/cssesc": {
365 | "version": "3.0.0",
366 | "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
367 | "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
368 | "dev": true,
369 | "license": "MIT",
370 | "bin": {
371 | "cssesc": "bin/cssesc"
372 | },
373 | "engines": {
374 | "node": ">=4"
375 | }
376 | },
377 | "node_modules/debug": {
378 | "version": "4.4.0",
379 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
380 | "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
381 | "dev": true,
382 | "license": "MIT",
383 | "dependencies": {
384 | "ms": "^2.1.3"
385 | },
386 | "engines": {
387 | "node": ">=6.0"
388 | },
389 | "peerDependenciesMeta": {
390 | "supports-color": {
391 | "optional": true
392 | }
393 | }
394 | },
395 | "node_modules/dir-glob": {
396 | "version": "3.0.1",
397 | "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
398 | "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
399 | "dev": true,
400 | "license": "MIT",
401 | "dependencies": {
402 | "path-type": "^4.0.0"
403 | },
404 | "engines": {
405 | "node": ">=8"
406 | }
407 | },
408 | "node_modules/emoji-regex": {
409 | "version": "8.0.0",
410 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
411 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
412 | "dev": true,
413 | "license": "MIT"
414 | },
415 | "node_modules/env-paths": {
416 | "version": "2.2.1",
417 | "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
418 | "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
419 | "dev": true,
420 | "license": "MIT",
421 | "engines": {
422 | "node": ">=6"
423 | }
424 | },
425 | "node_modules/error-ex": {
426 | "version": "1.3.2",
427 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
428 | "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
429 | "dev": true,
430 | "license": "MIT",
431 | "dependencies": {
432 | "is-arrayish": "^0.2.1"
433 | }
434 | },
435 | "node_modules/fast-deep-equal": {
436 | "version": "3.1.3",
437 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
438 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
439 | "dev": true,
440 | "license": "MIT"
441 | },
442 | "node_modules/fast-glob": {
443 | "version": "3.3.2",
444 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
445 | "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
446 | "dev": true,
447 | "license": "MIT",
448 | "dependencies": {
449 | "@nodelib/fs.stat": "^2.0.2",
450 | "@nodelib/fs.walk": "^1.2.3",
451 | "glob-parent": "^5.1.2",
452 | "merge2": "^1.3.0",
453 | "micromatch": "^4.0.4"
454 | },
455 | "engines": {
456 | "node": ">=8.6.0"
457 | }
458 | },
459 | "node_modules/fast-uri": {
460 | "version": "3.0.3",
461 | "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz",
462 | "integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==",
463 | "dev": true,
464 | "license": "BSD-3-Clause"
465 | },
466 | "node_modules/fastest-levenshtein": {
467 | "version": "1.0.16",
468 | "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
469 | "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==",
470 | "dev": true,
471 | "license": "MIT",
472 | "engines": {
473 | "node": ">= 4.9.1"
474 | }
475 | },
476 | "node_modules/fastq": {
477 | "version": "1.18.0",
478 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz",
479 | "integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==",
480 | "dev": true,
481 | "license": "ISC",
482 | "dependencies": {
483 | "reusify": "^1.0.4"
484 | }
485 | },
486 | "node_modules/file-entry-cache": {
487 | "version": "9.1.0",
488 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-9.1.0.tgz",
489 | "integrity": "sha512-/pqPFG+FdxWQj+/WSuzXSDaNzxgTLr/OrR1QuqfEZzDakpdYE70PwUxL7BPUa8hpjbvY1+qvCl8k+8Tq34xJgg==",
490 | "dev": true,
491 | "license": "MIT",
492 | "dependencies": {
493 | "flat-cache": "^5.0.0"
494 | },
495 | "engines": {
496 | "node": ">=18"
497 | }
498 | },
499 | "node_modules/fill-range": {
500 | "version": "7.1.1",
501 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
502 | "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
503 | "dev": true,
504 | "license": "MIT",
505 | "dependencies": {
506 | "to-regex-range": "^5.0.1"
507 | },
508 | "engines": {
509 | "node": ">=8"
510 | }
511 | },
512 | "node_modules/flat-cache": {
513 | "version": "5.0.0",
514 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-5.0.0.tgz",
515 | "integrity": "sha512-JrqFmyUl2PnPi1OvLyTVHnQvwQ0S+e6lGSwu8OkAZlSaNIZciTY2H/cOOROxsBA1m/LZNHDsqAgDZt6akWcjsQ==",
516 | "dev": true,
517 | "license": "MIT",
518 | "dependencies": {
519 | "flatted": "^3.3.1",
520 | "keyv": "^4.5.4"
521 | },
522 | "engines": {
523 | "node": ">=18"
524 | }
525 | },
526 | "node_modules/flatted": {
527 | "version": "3.3.2",
528 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz",
529 | "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==",
530 | "dev": true,
531 | "license": "ISC"
532 | },
533 | "node_modules/glob-parent": {
534 | "version": "5.1.2",
535 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
536 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
537 | "dev": true,
538 | "license": "ISC",
539 | "dependencies": {
540 | "is-glob": "^4.0.1"
541 | },
542 | "engines": {
543 | "node": ">= 6"
544 | }
545 | },
546 | "node_modules/global-modules": {
547 | "version": "2.0.0",
548 | "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz",
549 | "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==",
550 | "dev": true,
551 | "license": "MIT",
552 | "dependencies": {
553 | "global-prefix": "^3.0.0"
554 | },
555 | "engines": {
556 | "node": ">=6"
557 | }
558 | },
559 | "node_modules/global-prefix": {
560 | "version": "3.0.0",
561 | "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz",
562 | "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==",
563 | "dev": true,
564 | "license": "MIT",
565 | "dependencies": {
566 | "ini": "^1.3.5",
567 | "kind-of": "^6.0.2",
568 | "which": "^1.3.1"
569 | },
570 | "engines": {
571 | "node": ">=6"
572 | }
573 | },
574 | "node_modules/globby": {
575 | "version": "11.1.0",
576 | "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
577 | "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
578 | "dev": true,
579 | "license": "MIT",
580 | "dependencies": {
581 | "array-union": "^2.1.0",
582 | "dir-glob": "^3.0.1",
583 | "fast-glob": "^3.2.9",
584 | "ignore": "^5.2.0",
585 | "merge2": "^1.4.1",
586 | "slash": "^3.0.0"
587 | },
588 | "engines": {
589 | "node": ">=10"
590 | },
591 | "funding": {
592 | "url": "https://github.com/sponsors/sindresorhus"
593 | }
594 | },
595 | "node_modules/globby/node_modules/ignore": {
596 | "version": "5.3.2",
597 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
598 | "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
599 | "dev": true,
600 | "license": "MIT",
601 | "engines": {
602 | "node": ">= 4"
603 | }
604 | },
605 | "node_modules/globjoin": {
606 | "version": "0.1.4",
607 | "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz",
608 | "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==",
609 | "dev": true,
610 | "license": "MIT"
611 | },
612 | "node_modules/has-flag": {
613 | "version": "4.0.0",
614 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
615 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
616 | "dev": true,
617 | "license": "MIT",
618 | "engines": {
619 | "node": ">=8"
620 | }
621 | },
622 | "node_modules/html-tags": {
623 | "version": "3.3.1",
624 | "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz",
625 | "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==",
626 | "dev": true,
627 | "license": "MIT",
628 | "engines": {
629 | "node": ">=8"
630 | },
631 | "funding": {
632 | "url": "https://github.com/sponsors/sindresorhus"
633 | }
634 | },
635 | "node_modules/ignore": {
636 | "version": "6.0.2",
637 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-6.0.2.tgz",
638 | "integrity": "sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A==",
639 | "dev": true,
640 | "license": "MIT",
641 | "engines": {
642 | "node": ">= 4"
643 | }
644 | },
645 | "node_modules/import-fresh": {
646 | "version": "3.3.0",
647 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
648 | "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
649 | "dev": true,
650 | "license": "MIT",
651 | "dependencies": {
652 | "parent-module": "^1.0.0",
653 | "resolve-from": "^4.0.0"
654 | },
655 | "engines": {
656 | "node": ">=6"
657 | },
658 | "funding": {
659 | "url": "https://github.com/sponsors/sindresorhus"
660 | }
661 | },
662 | "node_modules/import-fresh/node_modules/resolve-from": {
663 | "version": "4.0.0",
664 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
665 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
666 | "dev": true,
667 | "license": "MIT",
668 | "engines": {
669 | "node": ">=4"
670 | }
671 | },
672 | "node_modules/imurmurhash": {
673 | "version": "0.1.4",
674 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
675 | "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
676 | "dev": true,
677 | "license": "MIT",
678 | "engines": {
679 | "node": ">=0.8.19"
680 | }
681 | },
682 | "node_modules/ini": {
683 | "version": "1.3.8",
684 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
685 | "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
686 | "dev": true,
687 | "license": "ISC"
688 | },
689 | "node_modules/is-arrayish": {
690 | "version": "0.2.1",
691 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
692 | "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
693 | "dev": true,
694 | "license": "MIT"
695 | },
696 | "node_modules/is-extglob": {
697 | "version": "2.1.1",
698 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
699 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
700 | "dev": true,
701 | "license": "MIT",
702 | "engines": {
703 | "node": ">=0.10.0"
704 | }
705 | },
706 | "node_modules/is-fullwidth-code-point": {
707 | "version": "3.0.0",
708 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
709 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
710 | "dev": true,
711 | "license": "MIT",
712 | "engines": {
713 | "node": ">=8"
714 | }
715 | },
716 | "node_modules/is-glob": {
717 | "version": "4.0.3",
718 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
719 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
720 | "dev": true,
721 | "license": "MIT",
722 | "dependencies": {
723 | "is-extglob": "^2.1.1"
724 | },
725 | "engines": {
726 | "node": ">=0.10.0"
727 | }
728 | },
729 | "node_modules/is-number": {
730 | "version": "7.0.0",
731 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
732 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
733 | "dev": true,
734 | "license": "MIT",
735 | "engines": {
736 | "node": ">=0.12.0"
737 | }
738 | },
739 | "node_modules/is-plain-object": {
740 | "version": "5.0.0",
741 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
742 | "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
743 | "dev": true,
744 | "license": "MIT",
745 | "engines": {
746 | "node": ">=0.10.0"
747 | }
748 | },
749 | "node_modules/isexe": {
750 | "version": "2.0.0",
751 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
752 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
753 | "dev": true,
754 | "license": "ISC"
755 | },
756 | "node_modules/js-tokens": {
757 | "version": "4.0.0",
758 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
759 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
760 | "dev": true,
761 | "license": "MIT"
762 | },
763 | "node_modules/js-yaml": {
764 | "version": "4.1.0",
765 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
766 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
767 | "dev": true,
768 | "license": "MIT",
769 | "dependencies": {
770 | "argparse": "^2.0.1"
771 | },
772 | "bin": {
773 | "js-yaml": "bin/js-yaml.js"
774 | }
775 | },
776 | "node_modules/json-buffer": {
777 | "version": "3.0.1",
778 | "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
779 | "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
780 | "dev": true,
781 | "license": "MIT"
782 | },
783 | "node_modules/json-parse-even-better-errors": {
784 | "version": "2.3.1",
785 | "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
786 | "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
787 | "dev": true,
788 | "license": "MIT"
789 | },
790 | "node_modules/json-schema-traverse": {
791 | "version": "1.0.0",
792 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
793 | "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
794 | "dev": true,
795 | "license": "MIT"
796 | },
797 | "node_modules/keyv": {
798 | "version": "4.5.4",
799 | "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
800 | "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
801 | "dev": true,
802 | "license": "MIT",
803 | "dependencies": {
804 | "json-buffer": "3.0.1"
805 | }
806 | },
807 | "node_modules/kind-of": {
808 | "version": "6.0.3",
809 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
810 | "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
811 | "dev": true,
812 | "license": "MIT",
813 | "engines": {
814 | "node": ">=0.10.0"
815 | }
816 | },
817 | "node_modules/known-css-properties": {
818 | "version": "0.35.0",
819 | "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.35.0.tgz",
820 | "integrity": "sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==",
821 | "dev": true,
822 | "license": "MIT"
823 | },
824 | "node_modules/lines-and-columns": {
825 | "version": "1.2.4",
826 | "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
827 | "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
828 | "dev": true,
829 | "license": "MIT"
830 | },
831 | "node_modules/lodash.truncate": {
832 | "version": "4.4.2",
833 | "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
834 | "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==",
835 | "dev": true,
836 | "license": "MIT"
837 | },
838 | "node_modules/mathml-tag-names": {
839 | "version": "2.1.3",
840 | "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz",
841 | "integrity": "sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==",
842 | "dev": true,
843 | "license": "MIT",
844 | "funding": {
845 | "type": "github",
846 | "url": "https://github.com/sponsors/wooorm"
847 | }
848 | },
849 | "node_modules/mdn-data": {
850 | "version": "2.12.2",
851 | "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz",
852 | "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==",
853 | "dev": true,
854 | "license": "CC0-1.0"
855 | },
856 | "node_modules/meow": {
857 | "version": "13.2.0",
858 | "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz",
859 | "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==",
860 | "dev": true,
861 | "license": "MIT",
862 | "engines": {
863 | "node": ">=18"
864 | },
865 | "funding": {
866 | "url": "https://github.com/sponsors/sindresorhus"
867 | }
868 | },
869 | "node_modules/merge2": {
870 | "version": "1.4.1",
871 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
872 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
873 | "dev": true,
874 | "license": "MIT",
875 | "engines": {
876 | "node": ">= 8"
877 | }
878 | },
879 | "node_modules/micromatch": {
880 | "version": "4.0.8",
881 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
882 | "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
883 | "dev": true,
884 | "license": "MIT",
885 | "dependencies": {
886 | "braces": "^3.0.3",
887 | "picomatch": "^2.3.1"
888 | },
889 | "engines": {
890 | "node": ">=8.6"
891 | }
892 | },
893 | "node_modules/ms": {
894 | "version": "2.1.3",
895 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
896 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
897 | "dev": true,
898 | "license": "MIT"
899 | },
900 | "node_modules/nanoid": {
901 | "version": "3.3.8",
902 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
903 | "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
904 | "dev": true,
905 | "funding": [
906 | {
907 | "type": "github",
908 | "url": "https://github.com/sponsors/ai"
909 | }
910 | ],
911 | "license": "MIT",
912 | "bin": {
913 | "nanoid": "bin/nanoid.cjs"
914 | },
915 | "engines": {
916 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
917 | }
918 | },
919 | "node_modules/normalize-path": {
920 | "version": "3.0.0",
921 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
922 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
923 | "dev": true,
924 | "license": "MIT",
925 | "engines": {
926 | "node": ">=0.10.0"
927 | }
928 | },
929 | "node_modules/parent-module": {
930 | "version": "1.0.1",
931 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
932 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
933 | "dev": true,
934 | "license": "MIT",
935 | "dependencies": {
936 | "callsites": "^3.0.0"
937 | },
938 | "engines": {
939 | "node": ">=6"
940 | }
941 | },
942 | "node_modules/parse-json": {
943 | "version": "5.2.0",
944 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
945 | "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
946 | "dev": true,
947 | "license": "MIT",
948 | "dependencies": {
949 | "@babel/code-frame": "^7.0.0",
950 | "error-ex": "^1.3.1",
951 | "json-parse-even-better-errors": "^2.3.0",
952 | "lines-and-columns": "^1.1.6"
953 | },
954 | "engines": {
955 | "node": ">=8"
956 | },
957 | "funding": {
958 | "url": "https://github.com/sponsors/sindresorhus"
959 | }
960 | },
961 | "node_modules/path-type": {
962 | "version": "4.0.0",
963 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
964 | "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
965 | "dev": true,
966 | "license": "MIT",
967 | "engines": {
968 | "node": ">=8"
969 | }
970 | },
971 | "node_modules/picocolors": {
972 | "version": "1.1.1",
973 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
974 | "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
975 | "dev": true,
976 | "license": "ISC"
977 | },
978 | "node_modules/picomatch": {
979 | "version": "2.3.1",
980 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
981 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
982 | "dev": true,
983 | "license": "MIT",
984 | "engines": {
985 | "node": ">=8.6"
986 | },
987 | "funding": {
988 | "url": "https://github.com/sponsors/jonschlinkert"
989 | }
990 | },
991 | "node_modules/postcss": {
992 | "version": "8.4.49",
993 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz",
994 | "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==",
995 | "dev": true,
996 | "funding": [
997 | {
998 | "type": "opencollective",
999 | "url": "https://opencollective.com/postcss/"
1000 | },
1001 | {
1002 | "type": "tidelift",
1003 | "url": "https://tidelift.com/funding/github/npm/postcss"
1004 | },
1005 | {
1006 | "type": "github",
1007 | "url": "https://github.com/sponsors/ai"
1008 | }
1009 | ],
1010 | "license": "MIT",
1011 | "dependencies": {
1012 | "nanoid": "^3.3.7",
1013 | "picocolors": "^1.1.1",
1014 | "source-map-js": "^1.2.1"
1015 | },
1016 | "engines": {
1017 | "node": "^10 || ^12 || >=14"
1018 | }
1019 | },
1020 | "node_modules/postcss-resolve-nested-selector": {
1021 | "version": "0.1.6",
1022 | "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.6.tgz",
1023 | "integrity": "sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw==",
1024 | "dev": true,
1025 | "license": "MIT"
1026 | },
1027 | "node_modules/postcss-safe-parser": {
1028 | "version": "7.0.1",
1029 | "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz",
1030 | "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==",
1031 | "dev": true,
1032 | "funding": [
1033 | {
1034 | "type": "opencollective",
1035 | "url": "https://opencollective.com/postcss/"
1036 | },
1037 | {
1038 | "type": "tidelift",
1039 | "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser"
1040 | },
1041 | {
1042 | "type": "github",
1043 | "url": "https://github.com/sponsors/ai"
1044 | }
1045 | ],
1046 | "license": "MIT",
1047 | "engines": {
1048 | "node": ">=18.0"
1049 | },
1050 | "peerDependencies": {
1051 | "postcss": "^8.4.31"
1052 | }
1053 | },
1054 | "node_modules/postcss-selector-parser": {
1055 | "version": "7.0.0",
1056 | "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz",
1057 | "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==",
1058 | "dev": true,
1059 | "license": "MIT",
1060 | "dependencies": {
1061 | "cssesc": "^3.0.0",
1062 | "util-deprecate": "^1.0.2"
1063 | },
1064 | "engines": {
1065 | "node": ">=4"
1066 | }
1067 | },
1068 | "node_modules/postcss-value-parser": {
1069 | "version": "4.2.0",
1070 | "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
1071 | "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
1072 | "dev": true,
1073 | "license": "MIT"
1074 | },
1075 | "node_modules/queue-microtask": {
1076 | "version": "1.2.3",
1077 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
1078 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
1079 | "dev": true,
1080 | "funding": [
1081 | {
1082 | "type": "github",
1083 | "url": "https://github.com/sponsors/feross"
1084 | },
1085 | {
1086 | "type": "patreon",
1087 | "url": "https://www.patreon.com/feross"
1088 | },
1089 | {
1090 | "type": "consulting",
1091 | "url": "https://feross.org/support"
1092 | }
1093 | ],
1094 | "license": "MIT"
1095 | },
1096 | "node_modules/require-from-string": {
1097 | "version": "2.0.2",
1098 | "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
1099 | "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
1100 | "dev": true,
1101 | "license": "MIT",
1102 | "engines": {
1103 | "node": ">=0.10.0"
1104 | }
1105 | },
1106 | "node_modules/resolve-from": {
1107 | "version": "5.0.0",
1108 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
1109 | "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
1110 | "dev": true,
1111 | "license": "MIT",
1112 | "engines": {
1113 | "node": ">=8"
1114 | }
1115 | },
1116 | "node_modules/reusify": {
1117 | "version": "1.0.4",
1118 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
1119 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
1120 | "dev": true,
1121 | "license": "MIT",
1122 | "engines": {
1123 | "iojs": ">=1.0.0",
1124 | "node": ">=0.10.0"
1125 | }
1126 | },
1127 | "node_modules/run-parallel": {
1128 | "version": "1.2.0",
1129 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
1130 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
1131 | "dev": true,
1132 | "funding": [
1133 | {
1134 | "type": "github",
1135 | "url": "https://github.com/sponsors/feross"
1136 | },
1137 | {
1138 | "type": "patreon",
1139 | "url": "https://www.patreon.com/feross"
1140 | },
1141 | {
1142 | "type": "consulting",
1143 | "url": "https://feross.org/support"
1144 | }
1145 | ],
1146 | "license": "MIT",
1147 | "dependencies": {
1148 | "queue-microtask": "^1.2.2"
1149 | }
1150 | },
1151 | "node_modules/signal-exit": {
1152 | "version": "4.1.0",
1153 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
1154 | "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
1155 | "dev": true,
1156 | "license": "ISC",
1157 | "engines": {
1158 | "node": ">=14"
1159 | },
1160 | "funding": {
1161 | "url": "https://github.com/sponsors/isaacs"
1162 | }
1163 | },
1164 | "node_modules/slash": {
1165 | "version": "3.0.0",
1166 | "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
1167 | "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
1168 | "dev": true,
1169 | "license": "MIT",
1170 | "engines": {
1171 | "node": ">=8"
1172 | }
1173 | },
1174 | "node_modules/slice-ansi": {
1175 | "version": "4.0.0",
1176 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
1177 | "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
1178 | "dev": true,
1179 | "license": "MIT",
1180 | "dependencies": {
1181 | "ansi-styles": "^4.0.0",
1182 | "astral-regex": "^2.0.0",
1183 | "is-fullwidth-code-point": "^3.0.0"
1184 | },
1185 | "engines": {
1186 | "node": ">=10"
1187 | },
1188 | "funding": {
1189 | "url": "https://github.com/chalk/slice-ansi?sponsor=1"
1190 | }
1191 | },
1192 | "node_modules/source-map-js": {
1193 | "version": "1.2.1",
1194 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
1195 | "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
1196 | "dev": true,
1197 | "license": "BSD-3-Clause",
1198 | "engines": {
1199 | "node": ">=0.10.0"
1200 | }
1201 | },
1202 | "node_modules/string-width": {
1203 | "version": "4.2.3",
1204 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
1205 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
1206 | "dev": true,
1207 | "license": "MIT",
1208 | "dependencies": {
1209 | "emoji-regex": "^8.0.0",
1210 | "is-fullwidth-code-point": "^3.0.0",
1211 | "strip-ansi": "^6.0.1"
1212 | },
1213 | "engines": {
1214 | "node": ">=8"
1215 | }
1216 | },
1217 | "node_modules/strip-ansi": {
1218 | "version": "6.0.1",
1219 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
1220 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
1221 | "dev": true,
1222 | "license": "MIT",
1223 | "dependencies": {
1224 | "ansi-regex": "^5.0.1"
1225 | },
1226 | "engines": {
1227 | "node": ">=8"
1228 | }
1229 | },
1230 | "node_modules/stylelint": {
1231 | "version": "16.12.0",
1232 | "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.12.0.tgz",
1233 | "integrity": "sha512-F8zZ3L/rBpuoBZRvI4JVT20ZanPLXfQLzMOZg1tzPflRVh9mKpOZ8qcSIhh1my3FjAjZWG4T2POwGnmn6a6hbg==",
1234 | "dev": true,
1235 | "funding": [
1236 | {
1237 | "type": "opencollective",
1238 | "url": "https://opencollective.com/stylelint"
1239 | },
1240 | {
1241 | "type": "github",
1242 | "url": "https://github.com/sponsors/stylelint"
1243 | }
1244 | ],
1245 | "license": "MIT",
1246 | "dependencies": {
1247 | "@csstools/css-parser-algorithms": "^3.0.4",
1248 | "@csstools/css-tokenizer": "^3.0.3",
1249 | "@csstools/media-query-list-parser": "^4.0.2",
1250 | "@csstools/selector-specificity": "^5.0.0",
1251 | "@dual-bundle/import-meta-resolve": "^4.1.0",
1252 | "balanced-match": "^2.0.0",
1253 | "colord": "^2.9.3",
1254 | "cosmiconfig": "^9.0.0",
1255 | "css-functions-list": "^3.2.3",
1256 | "css-tree": "^3.0.1",
1257 | "debug": "^4.3.7",
1258 | "fast-glob": "^3.3.2",
1259 | "fastest-levenshtein": "^1.0.16",
1260 | "file-entry-cache": "^9.1.0",
1261 | "global-modules": "^2.0.0",
1262 | "globby": "^11.1.0",
1263 | "globjoin": "^0.1.4",
1264 | "html-tags": "^3.3.1",
1265 | "ignore": "^6.0.2",
1266 | "imurmurhash": "^0.1.4",
1267 | "is-plain-object": "^5.0.0",
1268 | "known-css-properties": "^0.35.0",
1269 | "mathml-tag-names": "^2.1.3",
1270 | "meow": "^13.2.0",
1271 | "micromatch": "^4.0.8",
1272 | "normalize-path": "^3.0.0",
1273 | "picocolors": "^1.1.1",
1274 | "postcss": "^8.4.49",
1275 | "postcss-resolve-nested-selector": "^0.1.6",
1276 | "postcss-safe-parser": "^7.0.1",
1277 | "postcss-selector-parser": "^7.0.0",
1278 | "postcss-value-parser": "^4.2.0",
1279 | "resolve-from": "^5.0.0",
1280 | "string-width": "^4.2.3",
1281 | "supports-hyperlinks": "^3.1.0",
1282 | "svg-tags": "^1.0.0",
1283 | "table": "^6.9.0",
1284 | "write-file-atomic": "^5.0.1"
1285 | },
1286 | "bin": {
1287 | "stylelint": "bin/stylelint.mjs"
1288 | },
1289 | "engines": {
1290 | "node": ">=18.12.0"
1291 | }
1292 | },
1293 | "node_modules/stylelint-test-rule-node": {
1294 | "version": "0.2.2",
1295 | "resolved": "https://registry.npmjs.org/stylelint-test-rule-node/-/stylelint-test-rule-node-0.2.2.tgz",
1296 | "integrity": "sha512-muMgHkW0rpGwIHuL+dgxiWgojcPNByNiBHm5+NqZT/vUAWo0QZYY1jCDVbw2G404LFpzHDd0BZ4JEMKOIw/Dlw==",
1297 | "dev": true,
1298 | "funding": [
1299 | {
1300 | "type": "opencollective",
1301 | "url": "https://opencollective.com/stylelint"
1302 | },
1303 | {
1304 | "type": "github",
1305 | "url": "https://github.com/sponsors/stylelint"
1306 | }
1307 | ],
1308 | "license": "MIT",
1309 | "engines": {
1310 | "node": ">=18.12.0"
1311 | },
1312 | "peerDependencies": {
1313 | "stylelint": "^16.0.1"
1314 | }
1315 | },
1316 | "node_modules/supports-color": {
1317 | "version": "7.2.0",
1318 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
1319 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
1320 | "dev": true,
1321 | "license": "MIT",
1322 | "dependencies": {
1323 | "has-flag": "^4.0.0"
1324 | },
1325 | "engines": {
1326 | "node": ">=8"
1327 | }
1328 | },
1329 | "node_modules/supports-hyperlinks": {
1330 | "version": "3.1.0",
1331 | "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.1.0.tgz",
1332 | "integrity": "sha512-2rn0BZ+/f7puLOHZm1HOJfwBggfaHXUpPUSSG/SWM4TWp5KCfmNYwnC3hruy2rZlMnmWZ+QAGpZfchu3f3695A==",
1333 | "dev": true,
1334 | "license": "MIT",
1335 | "dependencies": {
1336 | "has-flag": "^4.0.0",
1337 | "supports-color": "^7.0.0"
1338 | },
1339 | "engines": {
1340 | "node": ">=14.18"
1341 | },
1342 | "funding": {
1343 | "url": "https://github.com/sponsors/sindresorhus"
1344 | }
1345 | },
1346 | "node_modules/svg-tags": {
1347 | "version": "1.0.0",
1348 | "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz",
1349 | "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==",
1350 | "dev": true
1351 | },
1352 | "node_modules/table": {
1353 | "version": "6.9.0",
1354 | "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz",
1355 | "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==",
1356 | "dev": true,
1357 | "license": "BSD-3-Clause",
1358 | "dependencies": {
1359 | "ajv": "^8.0.1",
1360 | "lodash.truncate": "^4.4.2",
1361 | "slice-ansi": "^4.0.0",
1362 | "string-width": "^4.2.3",
1363 | "strip-ansi": "^6.0.1"
1364 | },
1365 | "engines": {
1366 | "node": ">=10.0.0"
1367 | }
1368 | },
1369 | "node_modules/to-regex-range": {
1370 | "version": "5.0.1",
1371 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
1372 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
1373 | "dev": true,
1374 | "license": "MIT",
1375 | "dependencies": {
1376 | "is-number": "^7.0.0"
1377 | },
1378 | "engines": {
1379 | "node": ">=8.0"
1380 | }
1381 | },
1382 | "node_modules/util-deprecate": {
1383 | "version": "1.0.2",
1384 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
1385 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
1386 | "dev": true,
1387 | "license": "MIT"
1388 | },
1389 | "node_modules/which": {
1390 | "version": "1.3.1",
1391 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
1392 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
1393 | "dev": true,
1394 | "license": "ISC",
1395 | "dependencies": {
1396 | "isexe": "^2.0.0"
1397 | },
1398 | "bin": {
1399 | "which": "bin/which"
1400 | }
1401 | },
1402 | "node_modules/write-file-atomic": {
1403 | "version": "5.0.1",
1404 | "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz",
1405 | "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==",
1406 | "dev": true,
1407 | "license": "ISC",
1408 | "dependencies": {
1409 | "imurmurhash": "^0.1.4",
1410 | "signal-exit": "^4.0.1"
1411 | },
1412 | "engines": {
1413 | "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
1414 | }
1415 | }
1416 | }
1417 | }
1418 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "stylelint-media-use-custom-media",
3 | "version": "4.0.0",
4 | "description": "Enforce usage of custom media queries in CSS",
5 | "author": "Jonathan Neal ",
6 | "license": "CC0-1.0",
7 | "repository": "csstools/stylelint-media-use-custom-media",
8 | "homepage": "https://github.com/csstools/stylelint-media-use-custom-media#readme",
9 | "bugs": "https://github.com/csstools/stylelint-media-use-custom-media/issues",
10 | "type": "module",
11 | "main": "src/index.mjs",
12 | "files": [
13 | "src"
14 | ],
15 | "scripts": {
16 | "test": "node --test"
17 | },
18 | "engines": {
19 | "node": ">=18.12.0"
20 | },
21 | "dependencies": {},
22 | "devDependencies": {
23 | "stylelint": "^16.0.0",
24 | "stylelint-test-rule-node": "^0.2.0"
25 | },
26 | "peerDependencies": {
27 | "stylelint": ">=16"
28 | },
29 | "keywords": [
30 | "stylelint",
31 | "stylelint-plugin",
32 | "css",
33 | "use",
34 | "custom",
35 | "media",
36 | "custom-media",
37 | "queries",
38 | "query",
39 | "variables",
40 | "variable",
41 | "vars",
42 | "var"
43 | ]
44 | }
45 |
--------------------------------------------------------------------------------
/src/index.mjs:
--------------------------------------------------------------------------------
1 | import stylelint from "stylelint";
2 | import parseMedia from './lib/parse-media.mjs';
3 | import getCustomMediaFromImports from './lib/get-custom-media-from-imports.mjs';
4 | import getCustomMediaFromRoot from './lib/get-custom-media-from-root.mjs';
5 |
6 | const ruleName = 'csstools/media-use-custom-media';
7 |
8 | const messages = stylelint.utils.ruleMessages(ruleName, {
9 | expected(expression) {
10 | return `Expected a custom media query instead of "${expression}".`;
11 | },
12 | unexpected(expression) {
13 | return `Expected no custom media query instead of "${expression}".`;
14 | }
15 | });
16 |
17 | const ruleFunction = (method, opts) => {
18 | // sources to import custom selectors from
19 | const importFrom = [].concat(Object(opts).importFrom || []);
20 |
21 | // conditionally promise any custom selectors are imported
22 | const customMediaPromise = isMethodAlwaysKnown(method) || isMethodKnown(method)
23 | ? getCustomMediaFromImports(importFrom)
24 | : {};
25 |
26 | return async (root, result) => {
27 | // valid methods are: "always" || "always-known" || "never" || "known" || true || null
28 | const validOptions = stylelint.utils.validateOptions(result, ruleName, {
29 | actual: method,
30 | possible() {
31 | return isMethodAlways(method) || isMethodAlwaysKnown(method) || isMethodIndifferent(method) || isMethodKnown(method) || isMethodNever(method);
32 | }
33 | });
34 |
35 | // conditionally enforce the use of custom media
36 | if (validOptions && !isMethodIndifferent(method)) {
37 | // all custom properties from the file and imports
38 | const customMedia = isMethodAlwaysKnown(method) || isMethodKnown(method)
39 | ? Object.assign(await customMediaPromise, getCustomMediaFromRoot(root))
40 | : {};
41 |
42 | // check every @media at-rule
43 | root.walkAtRules(mediaAtRuleNameRegExp, atrule => {
44 | const mediaAST = parseMedia(atrule.params);
45 | let word = `@${atrule.name}`;
46 |
47 | // check whether media queries are using custom media references
48 | const isCorrectlyUsingMedia = mediaAST.nodes.every(
49 | node => node.nodes.every(
50 | child => {
51 | // whether the expression is like @media (--foo)
52 | const isCustomExpression = checkCustomExpression(child);
53 |
54 | const returnValue = isCustomExpression
55 | ? isMethodKnown(method) || isMethodAlwaysKnown(method)
56 | // @media (--foo) && ("always-known" || "known") && @custom-media --foo bar;
57 | ? child.value.slice(1, -1) in customMedia
58 | // @media (--foo) && "always"
59 | : isMethodAlways(method)
60 | // !@media (--foo) && ("known" || "never")
61 | : isMethodKnown(method) || isMethodNever(method);
62 |
63 | if (!returnValue) {
64 | word = String(child);
65 | }
66 |
67 | return returnValue;
68 | }
69 | )
70 | );
71 |
72 | // conditionally report media queries not using custom media references
73 | if (!isCorrectlyUsingMedia) {
74 | stylelint.utils.report({
75 | message: isMethodNever(method)
76 | ? messages.unexpected(atrule.params)
77 | : messages.expected(atrule.params),
78 | node: atrule,
79 | result,
80 | ruleName,
81 | word
82 | });
83 | }
84 | });
85 | }
86 | };
87 | };
88 |
89 | ruleFunction.ruleName = ruleName;
90 | ruleFunction.messages = messages;
91 |
92 | export default stylelint.createPlugin(ruleName, ruleFunction);
93 |
94 | const mediaAtRuleNameRegExp = /^media$/i;
95 | const customMediaExpressionRegExp = /\(--[\w-]+\)/i;
96 |
97 | const checkCustomExpression = node => node.nodeType === 'expression' && customMediaExpressionRegExp.test(node.value)
98 |
99 | const isMethodIndifferent = method => method === 'ignore' || method === null;
100 | const isMethodAlways = method => method === 'always' || method === true;
101 | const isMethodAlwaysKnown = method => method === 'always-known';
102 | const isMethodKnown = method => method === 'known';
103 | const isMethodNever = method => method === 'never';
104 |
--------------------------------------------------------------------------------
/src/lib/get-custom-media-from-imports.mjs:
--------------------------------------------------------------------------------
1 | import fs from 'fs';
2 | import path from 'path';
3 | import postcss from 'postcss';
4 | import getCustomMediaFromRoot from './get-custom-media-from-root.mjs';
5 |
6 | /* Get Custom Media from CSS File
7 | /* ========================================================================== */
8 |
9 | async function getCustomMediaFromCSSFile(from) {
10 | const css = await readFile(from);
11 | const root = postcss.parse(css, { from });
12 |
13 | return getCustomMediaFromRoot(root);
14 | }
15 |
16 | /* Get Custom Media from Object
17 | /* ========================================================================== */
18 |
19 | function getCustomMediaFromObject(object) {
20 | const customMedia = Object.assign(
21 | {},
22 | Object(object).customMedia,
23 | Object(object)['custom-media']
24 | );
25 |
26 | return customMedia;
27 | }
28 |
29 | /* Get Custom Media from JSON file
30 | /* ========================================================================== */
31 |
32 | async function getCustomMediaFromJSONFile(from) {
33 | const object = await readJSON(from);
34 |
35 | return getCustomMediaFromObject(object);
36 | }
37 |
38 | /* Get Custom Media from JS file
39 | /* ========================================================================== */
40 |
41 | async function getCustomMediaFromJSFile(from) {
42 | const object = await import(from);
43 |
44 | return getCustomMediaFromObject(object);
45 | }
46 |
47 | /* Get Custom Media from Imports
48 | /* ========================================================================== */
49 |
50 | export default function getCustomMediaFromImports(sources) {
51 | return sources.map(source => {
52 | if (source instanceof Promise) {
53 | return source;
54 | } else if (source instanceof Function) {
55 | return source();
56 | }
57 |
58 | // read the source as an object
59 | const opts = source === Object(source) ? source : { from: String(source) };
60 |
61 | // skip objects with Custom Media
62 | if (opts.customMedia || opts['custom-media']) {
63 | return opts
64 | }
65 |
66 | // source pathname
67 | const from = path.resolve(String(opts.from || ''));
68 |
69 | // type of file being read from
70 | const type = (opts.type || path.extname(from).slice(1)).toLowerCase();
71 |
72 | return { type, from };
73 | }).reduce(async (customMedia, source) => {
74 | const { type, from } = await source;
75 |
76 | if (type === 'css') {
77 | return Object.assign(await customMedia, await getCustomMediaFromCSSFile(from));
78 | }
79 |
80 | if (type === 'js') {
81 | return Object.assign(await customMedia, await getCustomMediaFromJSFile(from));
82 | }
83 |
84 | if (type === 'json') {
85 | return Object.assign(await customMedia, await getCustomMediaFromJSONFile(from));
86 | }
87 |
88 | return Object.assign(await customMedia, await getCustomMediaFromObject(await source));
89 | }, {});
90 | }
91 |
92 | /* Promise-ified utilities
93 | /* ========================================================================== */
94 |
95 | const readFile = from => new Promise((resolve, reject) => {
96 | fs.readFile(from, 'utf8', (error, result) => {
97 | if (error) {
98 | reject(error);
99 | } else {
100 | resolve(result);
101 | }
102 | });
103 | });
104 |
105 | const readJSON = async from => JSON.parse(await readFile(from));
106 |
--------------------------------------------------------------------------------
/src/lib/get-custom-media-from-root.mjs:
--------------------------------------------------------------------------------
1 | // return custom selectors from the css root
2 | export default root => {
3 | // initialize custom selectors
4 | const customMedias = {};
5 |
6 | // for each @custom-media at-rule
7 | root.nodes.forEach(node => {
8 | if (isCustomMedia(node)) {
9 | // extract the name and selectors from the params of the custom selector
10 | const [, name, selectors] = node.params.match(customMediaParamsRegExp);
11 |
12 | // write the parsed selectors to the custom selector
13 | customMedias[name] = selectors;
14 | }
15 | });
16 |
17 | // return all custom medias
18 | return customMedias;
19 | };
20 |
21 | // match the custom selector name
22 | const customMediaNameRegExp = /^custom-media$/i;
23 |
24 | // match the custom selector params
25 | const customMediaParamsRegExp = /^(--[A-z][\w-]*)\s+([\W\w]+)\s*$/;
26 |
27 | // whether the atrule is a custom selector
28 | const isCustomMedia = node => node.type === 'atrule' && customMediaNameRegExp.test(node.name) && customMediaParamsRegExp.test(node.params);
29 |
--------------------------------------------------------------------------------
/src/lib/parse-media.mjs:
--------------------------------------------------------------------------------
1 | function parse(string, splitByAnd) {
2 | const array = [];
3 | let buffer = '';
4 | let split = false;
5 | let func = 0;
6 | let i = -1;
7 |
8 | while (++i < string.length) {
9 | const char = string[i];
10 |
11 | if (char === '(') {
12 | func += 1;
13 | } else if (char === ')') {
14 | if (func > 0) {
15 | func -= 1;
16 | }
17 | } else if (func === 0) {
18 | if (splitByAnd && andRegExp.test(buffer + char)) {
19 | split = true;
20 | } else if (!splitByAnd && char === ',') {
21 | split = true;
22 | }
23 | }
24 |
25 | if (split) {
26 | array.push(splitByAnd ? new MediaExpression(buffer + char) : new MediaQuery(buffer));
27 |
28 | buffer = '';
29 | split = false;
30 | } else {
31 | buffer += char
32 | }
33 | }
34 |
35 | if (buffer !== '') {
36 | array.push(splitByAnd ? new MediaExpression(buffer) : new MediaQuery(buffer));
37 | }
38 |
39 | return array;
40 | }
41 |
42 | class MediaQueryList {
43 | constructor(string) {
44 | this.nodes = parse(string);
45 | this.nodeType = 'list';
46 | }
47 |
48 | invert() {
49 | this.nodes.forEach(node => {
50 | node.invert();
51 | })
52 |
53 | return this;
54 | }
55 |
56 | clone() {
57 | return new MediaQueryList(String(this));
58 | }
59 |
60 | toString() {
61 | return this.nodes.join(',');
62 | }
63 | }
64 |
65 | class MediaQuery {
66 | constructor(string) {
67 | const [, before, media, after ] = string.match(spaceWrapRegExp);
68 | const [, modifier = '', afterModifier = ' ', type = '', beforeAnd = '', and = '', beforeExpression = '', expression1 = '', expression2 = ''] = media.match(mediaRegExp) || [];
69 | const raws = { before, after, afterModifier, originalModifier: modifier || '', beforeAnd, and, beforeExpression };
70 | const nodes = parse(expression1 || expression2, true);
71 |
72 | Object.assign(this, {
73 | modifier,
74 | type,
75 | raws,
76 | nodes,
77 | nodeType: 'query'
78 | });
79 | }
80 |
81 | clone(overrides) {
82 | const instance = new MediaQuery(String(this));
83 |
84 | Object.assign(instance, overrides);
85 |
86 | return instance;
87 | }
88 |
89 | invert() {
90 | this.modifier = this.modifier ? '' : this.raws.originalModifier;
91 |
92 | return this;
93 | }
94 |
95 | toString() {
96 | const { raws } = this;
97 |
98 | return `${raws.before}${this.modifier}${this.modifier ? `${raws.afterModifier}` : ''}${this.type}${raws.beforeAnd}${raws.and}${raws.beforeExpression}${this.nodes.join('')}${this.raws.after}`;
99 | }
100 | }
101 |
102 | class MediaExpression {
103 | constructor(string) {
104 | const [, value, after = '', and = '', afterAnd = '' ] = string.match(andRegExp) || [null, string];
105 | const raws = { after, and, afterAnd };
106 |
107 | Object.assign(this, { value, raws, nodeType: 'expression' });
108 | }
109 |
110 | clone(overrides) {
111 | const instance = new MediaExpression(String(this));
112 |
113 | Object.assign(instance, overrides);
114 |
115 | return instance;
116 | }
117 |
118 | toString() {
119 | const { raws } = this;
120 |
121 | return `${this.value}${raws.after}${raws.and}${raws.afterAnd}`;
122 | }
123 | }
124 |
125 | const modifierRE = '(not|only)';
126 | const typeRE = '(all|print|screen|speech)';
127 | const noExpressionRE = '([\\W\\w]*)';
128 | const expressionRE = '([\\W\\w]+)';
129 | const noSpaceRE = '(\\s*)';
130 | const spaceRE = '(\\s+)';
131 | const andRE = '(?:(\\s+)(and))';
132 | const andRegExp = new RegExp(`^${expressionRE}(?:${andRE}${spaceRE})$`, 'i');
133 | const spaceWrapRegExp = new RegExp(`^${noSpaceRE}${noExpressionRE}${noSpaceRE}$`);
134 | const mediaRegExp = new RegExp(`^(?:${modifierRE}${spaceRE})?(?:${typeRE}(?:${andRE}${spaceRE}${expressionRE})?|${expressionRE})$`, 'i');
135 |
136 | export default string => new MediaQueryList(string);
137 |
--------------------------------------------------------------------------------
/test/import-custom-media.css:
--------------------------------------------------------------------------------
1 | @custom-media --md (min-width: 60rem);
2 |
--------------------------------------------------------------------------------