@bhollis/eslint-plugin-css-modules 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,142 @@
1
+ # @bhollis/eslint-plugin-css-modules
2
+
3
+ This plugin intends to help you in tracking down problems when you are using css-modules. It tells if you are using a non-existent css/scss/less class in js or if you forgot to use some classes which you declared in css/scss/less.
4
+
5
+ This is a forked version of https://github.com/atfzl/eslint-plugin-css-modules with fixes to make it compatible with more recent versions of css-loader, especially with [`namedExports: true`](https://webpack.js.org/loaders/css-loader/#namedexport). It is also compatible with ESLint's flat config.
6
+
7
+ ## Rules
8
+
9
+ * `css-modules/no-unused-class`: You must use all the classes defined in css/scss/less file.
10
+
11
+ >If you still want to mark a class as used, then use this comment on top of your file
12
+ ```js
13
+ /* eslint css-modules/no-unused-class: [2, { markAsUsed: ['container'] }] */
14
+ ```
15
+ where container is the css class that you want to mark as used.
16
+ Add all such classes in the array.
17
+
18
+ >If you use the `camelCase` option of `css-loader`, you must also enabled it for this plugin
19
+ ```js
20
+ /* eslint css-modules/no-unused-class: [2, { camelCase: true }] */
21
+ ```
22
+
23
+ * `css-modules/no-undef-class`: You must not use a non existing class, or a property that hasn't been exported using the [:export keyword](https://github.com/css-modules/icss#export).
24
+
25
+ >If you use the `camelCase` option of `css-loader`, you must also enabled it for this plugin
26
+ ```js
27
+ /* eslint css-modules/no-undef-class: [2, { camelCase: true }] */
28
+ ```
29
+
30
+ ## Installation
31
+
32
+ ```
33
+ npm i --save-dev @bhollis/eslint-plugin-css-modules
34
+ ```
35
+
36
+ ## Usage:
37
+
38
+ ```js
39
+ // eslint.config.js
40
+ import { defineConfig } from "eslint/config";
41
+ import cssModules from "@bhollis/eslint-plugin-css-modules";
42
+
43
+ export default defineConfig([
44
+ cssModules.configs.recommended
45
+ {
46
+ files: ["**/*.jsx"], // any patterns you want to apply the config to
47
+ plugins: {
48
+ 'css-modules': cssModules,
49
+ },
50
+ extends: ["css-modules/recommended"],
51
+ },
52
+ ]);
53
+ ```
54
+
55
+ You may also tweak the rules individually. For instance, if you use the [camelCase](https://github.com/webpack-contrib/css-loader#camelcase) option of webpack's css-loader:
56
+
57
+ ```js
58
+ // eslint.config.js
59
+ import { defineConfig } from "eslint/config";
60
+ import cssModules from "@bhollis/eslint-plugin-css-modules";
61
+
62
+ export default defineConfig([
63
+ {
64
+ files: ["**/*.jsx"], // any patterns you want to apply the config to
65
+ plugins: {
66
+ 'css-modules': cssModules,
67
+ },
68
+ rules: {
69
+ "css-modules/no-unused-class": [2, { "camelCase": true }],
70
+ "css-modules/no-undef-class": [2, { "camelCase": true }]
71
+ },
72
+ },
73
+ ]);
74
+ ```
75
+
76
+ The camelCase option has 4 possible values, see [css-loader#camelCase](https://github.com/webpack-contrib/css-loader#camelcase) for description:
77
+ ```js
78
+ true | "dashes" | "only" | "dashes-only"
79
+ ```
80
+
81
+ ## Specifying base path
82
+
83
+ You can specify path for the base directory via plugin settings in eslint.config.js. This is used by the plugin to resolve absolute (S)CSS paths:
84
+
85
+ ```js
86
+ // eslint.config.js
87
+ import { defineConfig } from "eslint/config";
88
+ import cssModules from "@bhollis/eslint-plugin-css-modules";
89
+
90
+ export default defineConfig([
91
+ {
92
+ files: ["**/*.jsx"], // any patterns you want to apply the config to
93
+ plugins: {
94
+ 'css-modules': cssModules,
95
+ },
96
+ settings: {
97
+ 'css-modules': {
98
+ basePath: "app/scripts/..."
99
+ }
100
+ },
101
+ },
102
+ ]);
103
+ ```
104
+
105
+ ## Screen Shot
106
+
107
+ ![ScreenShot](https://raw.githubusercontent.com/bhollis/eslint-plugin-css-modules/master/screenshots/screenshot3.png)
108
+
109
+ ```
110
+ 1:8 error Unused classes found: container css-modules/no-unused-class
111
+ 5:17 error Class 'containr' not found css-modules/no-undef-class
112
+ 10:26 error Class 'foo' not found css-modules/no-undef-class
113
+ ```
114
+
115
+ scss:
116
+
117
+ ```scss
118
+ /* .head is global, will not be used in js */
119
+ :global(.head) {
120
+ color: green;
121
+ }
122
+
123
+ .container {
124
+ width: 116px;
125
+
126
+ i {
127
+ font-size: 2.2rem;
128
+ }
129
+
130
+ .button {
131
+ padding: 7px 0 0 5px;
132
+ }
133
+ }
134
+
135
+ .footer {
136
+ color: cyan;
137
+ }
138
+ ```
139
+
140
+ ## With Thanks
141
+
142
+ * This is forked from [`eslint-plugin-css-modules`](https://github.com/atfzl/eslint-plugin-css-modules).
@@ -0,0 +1,138 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { camelCase } from 'es-toolkit';
4
+ import gonzales from 'gonzales-pe';
5
+ import { getRegularClassesMap, getComposesClassesMap, getExtendClassesMap, getParentSelectorClassesMap, getICSSExportPropsMap, eliminateGlobals } from './traversalUtils.js';
6
+ const styleExtensionRegex = /\.(s?css|less)$/;
7
+ function dashesCamelCase(str) {
8
+ return str.replace(/-+(\w)/g, function (match, firstLetter) {
9
+ return firstLetter.toUpperCase();
10
+ });
11
+ }
12
+ export const getFilePath = (context, styleFilePath) => {
13
+ const settings = context.settings['css-modules'];
14
+ const dirName = path.dirname(context.getFilename());
15
+ const basePath = settings && settings.basePath ? settings.basePath : '';
16
+ return styleFilePath.startsWith('.') ? path.resolve(dirName, styleFilePath) : path.resolve(basePath, styleFilePath);
17
+ };
18
+ export const getPropertyName = node => {
19
+ const propertyName = node.computed
20
+ /*
21
+ square braces eg s['header']
22
+ we won't use node.property.name because it is for cases like
23
+ s[abc] where abc is a variable
24
+ */ ? node.property.value
25
+ /* dot notation, eg s.header */ : node.property.name;
26
+
27
+ /*
28
+ skip property names starting with _
29
+ eg. special functions provided
30
+ by css modules like _getCss()
31
+ Tried to just skip function calls, but the parser
32
+ thinks of normal property access like s._getCss and
33
+ function calls like s._getCss() as same.
34
+ */
35
+ if (!propertyName || propertyName?.toString().startsWith('_')) {
36
+ return null;
37
+ }
38
+ return propertyName;
39
+ };
40
+ export const getClassesMap = (classes, camelCaseOption) => {
41
+ const classesMap = {};
42
+
43
+ // Unroll the loop because of performance!
44
+ // Remember that this function will run on every lint (e.g.: on file save)
45
+ switch (camelCaseOption) {
46
+ case true:
47
+ for (const className of Object.keys(classes)) {
48
+ classesMap[className] = className;
49
+ classesMap[camelCase(className)] = className;
50
+ }
51
+ break;
52
+ case 'dashes':
53
+ for (const className of Object.keys(classes)) {
54
+ classesMap[className] = className;
55
+ classesMap[dashesCamelCase(className)] = className;
56
+ }
57
+ break;
58
+ case 'only':
59
+ for (const className of Object.keys(classes)) {
60
+ classesMap[camelCase(className)] = className;
61
+ }
62
+ break;
63
+ case 'dashes-only':
64
+ for (const className of Object.keys(classes)) {
65
+ classesMap[dashesCamelCase(className)] = className;
66
+ }
67
+ break;
68
+ default:
69
+ for (const className of Object.keys(classes)) {
70
+ classesMap[className] = className;
71
+ }
72
+ }
73
+ return classesMap;
74
+ };
75
+ export const getStyleImportNodeData = node => {
76
+ // path from which it was imported
77
+ const styleFilePath = node?.source?.value;
78
+ if (styleFilePath && styleExtensionRegex.test(styleFilePath)) {
79
+ const importNode = node.specifiers?.find(specifier => specifier.type === 'ImportDefaultSpecifier' || specifier.type === 'ImportNamespaceSpecifier');
80
+ const importName = importNode?.local?.name;
81
+ if (importName) {
82
+ // it had a default or namespace import
83
+ return {
84
+ importName,
85
+ styleFilePath,
86
+ importNode
87
+ };
88
+ }
89
+ }
90
+ };
91
+ export const fileExists = filePath => {
92
+ try {
93
+ // check if file exists
94
+ fs.statSync(filePath);
95
+ return true;
96
+ } catch (e) {
97
+ return false;
98
+ }
99
+ };
100
+
101
+ /**
102
+ * @returns AST of the parsed file or null if parse failed
103
+ */
104
+ export const getAST = filePath => {
105
+ const fileContent = fs.readFileSync(filePath);
106
+ const syntax = path.extname(filePath).slice(1); // remove leading .
107
+
108
+ try {
109
+ return gonzales.parse(fileContent.toString(), {
110
+ syntax
111
+ });
112
+ } catch (e) {
113
+ return null;
114
+ }
115
+ };
116
+ export const getStyleClasses = ast => {
117
+ /*
118
+ mutates ast by removing :global scopes
119
+ */
120
+ eliminateGlobals(ast);
121
+ const classesMap = getRegularClassesMap(ast);
122
+ const composedClassesMap = getComposesClassesMap(ast);
123
+ const extendClassesMap = getExtendClassesMap(ast);
124
+ const parentSelectorClassesMap = getParentSelectorClassesMap(ast);
125
+ return {
126
+ ...classesMap,
127
+ ...composedClassesMap,
128
+ ...extendClassesMap,
129
+ ...parentSelectorClassesMap
130
+ };
131
+ };
132
+ export const getExportPropsMap = ast => {
133
+ const exportPropsMap = getICSSExportPropsMap(ast);
134
+ return {
135
+ ...exportPropsMap
136
+ };
137
+ };
138
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJmcyIsInBhdGgiLCJjYW1lbENhc2UiLCJnb256YWxlcyIsImdldFJlZ3VsYXJDbGFzc2VzTWFwIiwiZ2V0Q29tcG9zZXNDbGFzc2VzTWFwIiwiZ2V0RXh0ZW5kQ2xhc3Nlc01hcCIsImdldFBhcmVudFNlbGVjdG9yQ2xhc3Nlc01hcCIsImdldElDU1NFeHBvcnRQcm9wc01hcCIsImVsaW1pbmF0ZUdsb2JhbHMiLCJzdHlsZUV4dGVuc2lvblJlZ2V4IiwiZGFzaGVzQ2FtZWxDYXNlIiwic3RyIiwicmVwbGFjZSIsIm1hdGNoIiwiZmlyc3RMZXR0ZXIiLCJ0b1VwcGVyQ2FzZSIsImdldEZpbGVQYXRoIiwiY29udGV4dCIsInN0eWxlRmlsZVBhdGgiLCJzZXR0aW5ncyIsImRpck5hbWUiLCJkaXJuYW1lIiwiZ2V0RmlsZW5hbWUiLCJiYXNlUGF0aCIsInN0YXJ0c1dpdGgiLCJyZXNvbHZlIiwiZ2V0UHJvcGVydHlOYW1lIiwibm9kZSIsInByb3BlcnR5TmFtZSIsImNvbXB1dGVkIiwicHJvcGVydHkiLCJ2YWx1ZSIsIm5hbWUiLCJ0b1N0cmluZyIsImdldENsYXNzZXNNYXAiLCJjbGFzc2VzIiwiY2FtZWxDYXNlT3B0aW9uIiwiY2xhc3Nlc01hcCIsImNsYXNzTmFtZSIsIk9iamVjdCIsImtleXMiLCJnZXRTdHlsZUltcG9ydE5vZGVEYXRhIiwic291cmNlIiwidGVzdCIsImltcG9ydE5vZGUiLCJzcGVjaWZpZXJzIiwiZmluZCIsInNwZWNpZmllciIsInR5cGUiLCJpbXBvcnROYW1lIiwibG9jYWwiLCJmaWxlRXhpc3RzIiwiZmlsZVBhdGgiLCJzdGF0U3luYyIsImUiLCJnZXRBU1QiLCJmaWxlQ29udGVudCIsInJlYWRGaWxlU3luYyIsInN5bnRheCIsImV4dG5hbWUiLCJzbGljZSIsInBhcnNlIiwiZ2V0U3R5bGVDbGFzc2VzIiwiYXN0IiwiY29tcG9zZWRDbGFzc2VzTWFwIiwiZXh0ZW5kQ2xhc3Nlc01hcCIsInBhcmVudFNlbGVjdG9yQ2xhc3Nlc01hcCIsImdldEV4cG9ydFByb3BzTWFwIiwiZXhwb3J0UHJvcHNNYXAiXSwic291cmNlcyI6WyIuLi8uLi9saWIvY29yZS9pbmRleC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyIvLyBAZmxvd1xuXG5pbXBvcnQgZnMgZnJvbSAnbm9kZTpmcyc7XG5pbXBvcnQgcGF0aCBmcm9tICdub2RlOnBhdGgnO1xuaW1wb3J0IHsgY2FtZWxDYXNlIH0gZnJvbSAnZXMtdG9vbGtpdCc7XG5pbXBvcnQgZ29uemFsZXMgZnJvbSAnZ29uemFsZXMtcGUnO1xuXG5pbXBvcnQgdHlwZSB7IEpzTm9kZSwgZ0FTVE5vZGUgfSBmcm9tICcuLi90eXBlcy9pbmRleC5qcyc7XG5cbmltcG9ydCB7XG4gIGdldFJlZ3VsYXJDbGFzc2VzTWFwLFxuICBnZXRDb21wb3Nlc0NsYXNzZXNNYXAsXG4gIGdldEV4dGVuZENsYXNzZXNNYXAsXG4gIGdldFBhcmVudFNlbGVjdG9yQ2xhc3Nlc01hcCxcbiAgZ2V0SUNTU0V4cG9ydFByb3BzTWFwLFxuICBlbGltaW5hdGVHbG9iYWxzLFxufSBmcm9tICcuL3RyYXZlcnNhbFV0aWxzLmpzJztcblxuY29uc3Qgc3R5bGVFeHRlbnNpb25SZWdleCA9IC9cXC4ocz9jc3N8bGVzcykkLztcblxuZnVuY3Rpb24gZGFzaGVzQ2FtZWxDYXNlIChzdHI6IHN0cmluZykge1xuICByZXR1cm4gc3RyLnJlcGxhY2UoLy0rKFxcdykvZywgZnVuY3Rpb24gKG1hdGNoLCBmaXJzdExldHRlcikge1xuICAgIHJldHVybiBmaXJzdExldHRlci50b1VwcGVyQ2FzZSgpO1xuICB9KTtcbn1cblxuZXhwb3J0IGNvbnN0IGdldEZpbGVQYXRoID0gKGNvbnRleHQsIHN0eWxlRmlsZVBhdGgpID0+IHtcbiAgY29uc3Qgc2V0dGluZ3MgPSBjb250ZXh0LnNldHRpbmdzWydjc3MtbW9kdWxlcyddO1xuXG4gIGNvbnN0IGRpck5hbWUgPSBwYXRoLmRpcm5hbWUoY29udGV4dC5nZXRGaWxlbmFtZSgpKTtcbiAgY29uc3QgYmFzZVBhdGggPSAoc2V0dGluZ3MgJiYgc2V0dGluZ3MuYmFzZVBhdGgpID8gc2V0dGluZ3MuYmFzZVBhdGggOiAnJztcblxuICByZXR1cm4gc3R5bGVGaWxlUGF0aC5zdGFydHNXaXRoKCcuJylcbiAgICA/IHBhdGgucmVzb2x2ZShkaXJOYW1lLCBzdHlsZUZpbGVQYXRoKVxuICAgIDogcGF0aC5yZXNvbHZlKGJhc2VQYXRoLCBzdHlsZUZpbGVQYXRoKTtcbn07XG5cbmV4cG9ydCBjb25zdCBnZXRQcm9wZXJ0eU5hbWUgPSAobm9kZTogSnNOb2RlKTogP3N0cmluZyA9PiB7XG4gIGNvbnN0IHByb3BlcnR5TmFtZSA9IG5vZGUuY29tcHV0ZWRcbiAgICAvKlxuICAgICAgIHNxdWFyZSBicmFjZXMgZWcgc1snaGVhZGVyJ11cbiAgICAgICB3ZSB3b24ndCB1c2Ugbm9kZS5wcm9wZXJ0eS5uYW1lIGJlY2F1c2UgaXQgaXMgZm9yIGNhc2VzIGxpa2VcbiAgICAgICBzW2FiY10gd2hlcmUgYWJjIGlzIGEgdmFyaWFibGVcbiAgICAgKi9cbiAgICA/IG5vZGUucHJvcGVydHkudmFsdWVcbiAgICAvKiBkb3Qgbm90YXRpb24sIGVnIHMuaGVhZGVyICovXG4gICAgOiBub2RlLnByb3BlcnR5Lm5hbWU7XG5cbiAgLypcbiAgICAgc2tpcCBwcm9wZXJ0eSBuYW1lcyBzdGFydGluZyB3aXRoIF9cbiAgICAgZWcuIHNwZWNpYWwgZnVuY3Rpb25zIHByb3ZpZGVkXG4gICAgIGJ5IGNzcyBtb2R1bGVzIGxpa2UgX2dldENzcygpXG5cbiAgICAgVHJpZWQgdG8ganVzdCBza2lwIGZ1bmN0aW9uIGNhbGxzLCBidXQgdGhlIHBhcnNlclxuICAgICB0aGlua3Mgb2Ygbm9ybWFsIHByb3BlcnR5IGFjY2VzcyBsaWtlIHMuX2dldENzcyBhbmRcbiAgICAgZnVuY3Rpb24gY2FsbHMgbGlrZSBzLl9nZXRDc3MoKSBhcyBzYW1lLlxuICAgKi9cbiAgaWYgKCFwcm9wZXJ0eU5hbWUgfHwgcHJvcGVydHlOYW1lPy50b1N0cmluZygpLnN0YXJ0c1dpdGgoJ18nKSkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgcmV0dXJuIHByb3BlcnR5TmFtZTtcbn07XG5cbmV4cG9ydCBjb25zdCBnZXRDbGFzc2VzTWFwID0gKGNsYXNzZXM6IE9iamVjdCwgY2FtZWxDYXNlT3B0aW9uOiBzdHJpbmd8Ym9vbGVhbik6IE9iamVjdCA9PiB7XG4gIGNvbnN0IGNsYXNzZXNNYXAgPSB7fTtcblxuICAvLyBVbnJvbGwgdGhlIGxvb3AgYmVjYXVzZSBvZiBwZXJmb3JtYW5jZSFcbiAgLy8gUmVtZW1iZXIgdGhhdCB0aGlzIGZ1bmN0aW9uIHdpbGwgcnVuIG9uIGV2ZXJ5IGxpbnQgKGUuZy46IG9uIGZpbGUgc2F2ZSlcbiAgc3dpdGNoIChjYW1lbENhc2VPcHRpb24pIHtcbiAgICBjYXNlIHRydWU6XG4gICAgICBmb3IgKGNvbnN0IGNsYXNzTmFtZSBvZiBPYmplY3Qua2V5cyhjbGFzc2VzKSkge1xuICAgICAgICBjbGFzc2VzTWFwW2NsYXNzTmFtZV0gPSBjbGFzc05hbWU7XG4gICAgICAgIGNsYXNzZXNNYXBbY2FtZWxDYXNlKGNsYXNzTmFtZSldID0gY2xhc3NOYW1lO1xuICAgICAgfVxuICAgICAgYnJlYWs7XG4gICAgY2FzZSAnZGFzaGVzJzpcbiAgICAgIGZvciAoY29uc3QgY2xhc3NOYW1lIG9mIE9iamVjdC5rZXlzKGNsYXNzZXMpKSB7XG4gICAgICAgIGNsYXNzZXNNYXBbY2xhc3NOYW1lXSA9IGNsYXNzTmFtZTtcbiAgICAgICAgY2xhc3Nlc01hcFtkYXNoZXNDYW1lbENhc2UoY2xhc3NOYW1lKV0gPSBjbGFzc05hbWU7XG4gICAgICB9XG4gICAgICBicmVhaztcbiAgICBjYXNlICdvbmx5JzpcbiAgICAgIGZvciAoY29uc3QgY2xhc3NOYW1lIG9mIE9iamVjdC5rZXlzKGNsYXNzZXMpKSB7XG4gICAgICAgIGNsYXNzZXNNYXBbY2FtZWxDYXNlKGNsYXNzTmFtZSldID0gY2xhc3NOYW1lO1xuICAgICAgfVxuICAgICAgYnJlYWs7XG4gICAgY2FzZSAnZGFzaGVzLW9ubHknOlxuICAgICAgZm9yIChjb25zdCBjbGFzc05hbWUgb2YgT2JqZWN0LmtleXMoY2xhc3NlcykpIHtcbiAgICAgICAgY2xhc3Nlc01hcFtkYXNoZXNDYW1lbENhc2UoY2xhc3NOYW1lKV0gPSBjbGFzc05hbWU7XG4gICAgICB9XG4gICAgICBicmVhaztcbiAgICBkZWZhdWx0OlxuICAgICAgZm9yIChjb25zdCBjbGFzc05hbWUgb2YgT2JqZWN0LmtleXMoY2xhc3NlcykpIHtcbiAgICAgICAgY2xhc3Nlc01hcFtjbGFzc05hbWVdID0gY2xhc3NOYW1lO1xuICAgICAgfVxuICB9XG5cbiAgcmV0dXJuIGNsYXNzZXNNYXA7XG59O1xuXG5leHBvcnQgY29uc3QgZ2V0U3R5bGVJbXBvcnROb2RlRGF0YSA9IChub2RlOiBKc05vZGUpOiA/T2JqZWN0ID0+IHtcbiAgLy8gcGF0aCBmcm9tIHdoaWNoIGl0IHdhcyBpbXBvcnRlZFxuICBjb25zdCBzdHlsZUZpbGVQYXRoID0gbm9kZT8uc291cmNlPy52YWx1ZTtcblxuICBpZiAoc3R5bGVGaWxlUGF0aCAmJiBzdHlsZUV4dGVuc2lvblJlZ2V4LnRlc3Qoc3R5bGVGaWxlUGF0aCkpIHtcbiAgICBjb25zdCBpbXBvcnROb2RlID0gbm9kZS5zcGVjaWZpZXJzPy5maW5kKFxuICAgICAgKHNwZWNpZmllcikgPT5cbiAgICAgICAgc3BlY2lmaWVyLnR5cGUgPT09ICdJbXBvcnREZWZhdWx0U3BlY2lmaWVyJyB8fCBzcGVjaWZpZXIudHlwZSA9PT0gJ0ltcG9ydE5hbWVzcGFjZVNwZWNpZmllcidcbiAgICApO1xuICAgIGNvbnN0IGltcG9ydE5hbWUgPSBpbXBvcnROb2RlPy5sb2NhbD8ubmFtZTtcbiAgICBpZiAoaW1wb3J0TmFtZSkge1xuICAgICAgLy8gaXQgaGFkIGEgZGVmYXVsdCBvciBuYW1lc3BhY2UgaW1wb3J0XG4gICAgICByZXR1cm4geyBpbXBvcnROYW1lLCBzdHlsZUZpbGVQYXRoLCBpbXBvcnROb2RlIH07XG4gICAgfVxuICB9XG59O1xuXG5leHBvcnQgY29uc3QgZmlsZUV4aXN0cyA9IChmaWxlUGF0aDogc3RyaW5nKTogYm9vbGVhbiA9PiB7XG4gIHRyeSB7XG4gICAgLy8gY2hlY2sgaWYgZmlsZSBleGlzdHNcbiAgICBmcy5zdGF0U3luYyhmaWxlUGF0aCk7XG4gICAgcmV0dXJuIHRydWU7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn07XG5cbi8qKlxuICogQHJldHVybnMgQVNUIG9mIHRoZSBwYXJzZWQgZmlsZSBvciBudWxsIGlmIHBhcnNlIGZhaWxlZFxuICovXG5leHBvcnQgY29uc3QgZ2V0QVNUID0gKGZpbGVQYXRoOiBzdHJpbmcpOiBnQVNUTm9kZSB8IG51bGwgPT4ge1xuICBjb25zdCBmaWxlQ29udGVudCA9IGZzLnJlYWRGaWxlU3luYyhmaWxlUGF0aCk7XG5cbiAgY29uc3Qgc3ludGF4ID0gcGF0aC5leHRuYW1lKGZpbGVQYXRoKS5zbGljZSgxKTsgLy8gcmVtb3ZlIGxlYWRpbmcgLlxuXG4gIHRyeSB7XG4gICAgcmV0dXJuIGdvbnphbGVzLnBhcnNlKGZpbGVDb250ZW50LnRvU3RyaW5nKCksIHsgc3ludGF4IH0pO1xuICB9IGNhdGNoIChlKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbn07XG5cbmV4cG9ydCBjb25zdCBnZXRTdHlsZUNsYXNzZXMgPSAoYXN0OiBnQVNUTm9kZSk6ID9PYmplY3QgPT4ge1xuICAvKlxuICAgICBtdXRhdGVzIGFzdCBieSByZW1vdmluZyA6Z2xvYmFsIHNjb3Blc1xuICAgKi9cbiAgZWxpbWluYXRlR2xvYmFscyhhc3QpO1xuXG4gIGNvbnN0IGNsYXNzZXNNYXAgPSBnZXRSZWd1bGFyQ2xhc3Nlc01hcChhc3QpO1xuICBjb25zdCBjb21wb3NlZENsYXNzZXNNYXAgPSBnZXRDb21wb3Nlc0NsYXNzZXNNYXAoYXN0KTtcbiAgY29uc3QgZXh0ZW5kQ2xhc3Nlc01hcCA9IGdldEV4dGVuZENsYXNzZXNNYXAoYXN0KTtcbiAgY29uc3QgcGFyZW50U2VsZWN0b3JDbGFzc2VzTWFwID0gZ2V0UGFyZW50U2VsZWN0b3JDbGFzc2VzTWFwKGFzdCk7XG5cbiAgcmV0dXJuIHtcbiAgICAuLi5jbGFzc2VzTWFwLFxuICAgIC4uLmNvbXBvc2VkQ2xhc3Nlc01hcCxcbiAgICAuLi5leHRlbmRDbGFzc2VzTWFwLFxuICAgIC4uLnBhcmVudFNlbGVjdG9yQ2xhc3Nlc01hcFxuICB9O1xufTtcblxuZXhwb3J0IGNvbnN0IGdldEV4cG9ydFByb3BzTWFwID0gKGFzdDogZ0FTVE5vZGUpOiA/T2JqZWN0ID0+IHtcbiAgY29uc3QgZXhwb3J0UHJvcHNNYXAgPSBnZXRJQ1NTRXhwb3J0UHJvcHNNYXAoYXN0KTtcbiAgcmV0dXJuIHtcbiAgICAuLi5leHBvcnRQcm9wc01hcFxuICB9O1xufTtcbiJdLCJtYXBwaW5ncyI6IkFBRUEsT0FBT0EsRUFBRSxNQUFNLFNBQVM7QUFDeEIsT0FBT0MsSUFBSSxNQUFNLFdBQVc7QUFDNUIsU0FBU0MsU0FBUyxRQUFRLFlBQVk7QUFDdEMsT0FBT0MsUUFBUSxNQUFNLGFBQWE7QUFJbEMsU0FDRUMsb0JBQW9CLEVBQ3BCQyxxQkFBcUIsRUFDckJDLG1CQUFtQixFQUNuQkMsMkJBQTJCLEVBQzNCQyxxQkFBcUIsRUFDckJDLGdCQUFnQixRQUNYLHFCQUFxQjtBQUU1QixNQUFNQyxtQkFBbUIsR0FBRyxpQkFBaUI7QUFFN0MsU0FBU0MsZUFBZUEsQ0FBRUMsR0FBVyxFQUFFO0VBQ3JDLE9BQU9BLEdBQUcsQ0FBQ0MsT0FBTyxDQUFDLFNBQVMsRUFBRSxVQUFVQyxLQUFLLEVBQUVDLFdBQVcsRUFBRTtJQUMxRCxPQUFPQSxXQUFXLENBQUNDLFdBQVcsQ0FBQyxDQUFDO0VBQ2xDLENBQUMsQ0FBQztBQUNKO0FBRUEsT0FBTyxNQUFNQyxXQUFXLEdBQUdBLENBQUNDLE9BQU8sRUFBRUMsYUFBYSxLQUFLO0VBQ3JELE1BQU1DLFFBQVEsR0FBR0YsT0FBTyxDQUFDRSxRQUFRLENBQUMsYUFBYSxDQUFDO0VBRWhELE1BQU1DLE9BQU8sR0FBR3BCLElB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
@@ -0,0 +1,186 @@
1
+ /* eslint-disable no-param-reassign */
2
+ export const getICSSExportPropsMap = ast => {
3
+ const ruleSets = [];
4
+ ast.traverseByType('ruleset', node => ruleSets.push(node));
5
+ return ruleSets.filter(ruleSet => {
6
+ const content = ruleSet.content || [];
7
+ return content.some(item => item.type === 'selector' && item.content?.some(selectorItem => selectorItem.type === 'pseudoClass' && selectorItem.content?.some(pseudoItem => pseudoItem.type === 'ident' && pseudoItem.content === 'export')));
8
+ }).reduce((result, ruleSet) => {
9
+ const declarations = (ruleSet.content || []).filter(item => item.type === 'block').flatMap(block => block.content || []).filter(item => item.type === 'declaration');
10
+ for (const declaration of declarations) {
11
+ const property = (declaration.content || []).find(item => item.type === 'property');
12
+ const propName = (property?.content || [])[0]?.content;
13
+ if (propName) {
14
+ result[propName] = propName;
15
+ }
16
+ }
17
+ return result;
18
+ }, {});
19
+ };
20
+ export const getRegularClassesMap = ast => {
21
+ const ruleSets = [];
22
+ ast.traverseByType('ruleset', node => ruleSets.push(node));
23
+ return ruleSets.reduce((result, ruleSet) => {
24
+ const selectors = ruleSet.content?.filter(item => item.type === 'selector') ?? [];
25
+ for (const selector of selectors) {
26
+ const classes = selector.content?.filter(item => item.type === 'class') ?? [];
27
+ for (const classNode of classes) {
28
+ const ident = classNode.content?.find(item => item.type === 'ident');
29
+ if (ident?.content) {
30
+ result[ident.content] = false;
31
+ }
32
+ }
33
+ }
34
+ return result;
35
+ }, {});
36
+ };
37
+ export const getComposesClassesMap = ast => {
38
+ const declarations = [];
39
+ ast.traverseByType('declaration', node => declarations.push(node));
40
+ return declarations.reduce((result, declaration) => {
41
+ const content = declaration.content;
42
+ const property = content?.find(item => item.type === 'property');
43
+ const hasComposes = property?.content?.some(item => item.type === 'ident' && item.content === 'composes');
44
+ if (!hasComposes) return result;
45
+ const value = content?.find(item => item.type === 'value');
46
+ const valueContent = value?.content;
47
+
48
+ // Reject classes composing from other files, e.g. `composes: foo from './other.css'`
49
+ if (valueContent?.some(item => item.type === 'ident' && item.content === 'from')) {
50
+ return result;
51
+ }
52
+
53
+ // Extract and mark composed classes
54
+ const composedClasses = valueContent?.filter(item => item.type === 'ident' && item.content) ?? [];
55
+ for (const item of composedClasses) {
56
+ result[item.content] = true;
57
+ }
58
+ return result;
59
+ }, {});
60
+ };
61
+ export const getExtendClassesMap = ast => {
62
+ const extendNodes = [];
63
+ ast.traverseByType('extend', node => extendNodes.push(node));
64
+ return extendNodes.reduce((result, extendNode) => {
65
+ const selector = extendNode.content?.find(item => item.type === 'selector');
66
+ const classNode = selector?.content?.find(item => item.type === 'class');
67
+ const ident = classNode?.content?.find(item => item.type === 'ident');
68
+ const className = ident?.content;
69
+ if (className) {
70
+ result[className] = true; // mark extend classes as true
71
+ }
72
+
73
+ return result;
74
+ }, {});
75
+ };
76
+
77
+ /**
78
+ * Resolves parent selectors to their full class names.
79
+ *
80
+ * E.g. `.foo { &_bar {color: blue } }` to `.foo_bar`.
81
+ */
82
+ export const getParentSelectorClassesMap = ast => {
83
+ const classesMap = {};
84
+
85
+ // Recursively traverses down the tree looking for parent selector
86
+ // extensions. Recursion is necessary as these selectors can be nested.
87
+ const getExtensions = nodeContent => {
88
+ const blockContent = nodeContent.filter(item => item.type === 'block').flatMap(item => item.content || []);
89
+ const rulesetChildren = blockContent.filter(item => item.type === 'ruleset');
90
+ const rulesetDescendants = blockContent.filter(item => item.type === 'include').flatMap(item => item.content || []).filter(subItem => subItem.type === 'block').flatMap(subItem => subItem.content || []).filter(subItem => subItem.type === 'ruleset');
91
+ const rulesetsContent = [...rulesetChildren, ...rulesetDescendants].flatMap(item => item.content || []);
92
+ const extensions = rulesetsContent.filter(item => item.type === 'selector').flatMap(item => item.content || []).filter(selectorItem => selectorItem.type === 'parentSelectorExtension').flatMap(selectorItem => selectorItem.content || []).filter(identItem => identItem.type === 'ident').map(identItem => identItem.content);
93
+ if (!extensions.length) return [];
94
+ const nestedExtensions = getExtensions(rulesetsContent);
95
+ const result = extensions;
96
+ if (nestedExtensions.length) {
97
+ for (const nestedExt of nestedExtensions) {
98
+ extensions.forEach(ext => {
99
+ result.push(ext + nestedExt);
100
+ });
101
+ }
102
+ }
103
+ return result;
104
+ };
105
+ ast.traverseByType('ruleset', node => {
106
+ const classNames = (node.content || []).filter(item => item.type === 'selector').flatMap(item => item.content || []).filter(item => item.type === 'class').flatMap(item => item.content || []).filter(item => item.type === 'ident' && item.content).map(item => item.content);
107
+ if (!classNames.length) return;
108
+ const extensions = getExtensions(node.content);
109
+ if (!extensions.length) return;
110
+ classNames.forEach(className => {
111
+ extensions.forEach(ext => {
112
+ classesMap[className + ext] = false;
113
+ });
114
+
115
+ // Ignore the base class if it only exists for nesting parent selectors
116
+ const hasDeclarations = node.content?.some(item => item.type === 'block' && item.content?.some(subItem => subItem.type === 'declaration'));
117
+ if (!hasDeclarations) classesMap[className] = true;
118
+ });
119
+ });
120
+ return classesMap;
121
+ };
122
+
123
+ /**
124
+ * Mutates the AST by removing `:global` instances.
125
+ *
126
+ * For the AST structure:
127
+ * @see https://github.com/css/gonzales/blob/master/doc/AST.CSSP.en.md
128
+ */
129
+ export const eliminateGlobals = ast => {
130
+ // Remove all :global/:global(...) in selectors
131
+ ast.traverseByType('selector', selectorNode => {
132
+ const selectorContent = selectorNode.content;
133
+ let hasGlobalWithNoArgs = false;
134
+ let i = 0;
135
+ let currNode = selectorContent[i];
136
+ while (currNode) {
137
+ if (currNode.is('pseudoClass')) {
138
+ // Remove all :global/:global(...) and trailing space
139
+ const identifierNode = currNode.content[0];
140
+ if (identifierNode && identifierNode.content === 'global') {
141
+ if (currNode.content.length === 1) hasGlobalWithNoArgs = true;
142
+ selectorNode.removeChild(i);
143
+ if (selectorContent[i] && selectorContent[i].is('space')) {
144
+ selectorNode.removeChild(i);
145
+ }
146
+ } else {
147
+ i++;
148
+ }
149
+ } else if (currNode.is('class') && hasGlobalWithNoArgs) {
150
+ // Remove all class after :global and their trailing space
151
+ selectorNode.removeChild(i);
152
+ if (selectorContent[i] && selectorContent[i].is('space')) {
153
+ selectorNode.removeChild(i);
154
+ }
155
+ } else {
156
+ i++;
157
+ }
158
+ currNode = selectorContent[i];
159
+ }
160
+ });
161
+
162
+ // Remove all ruleset with no selectors
163
+ ast.traverseByType('ruleset', (node, index, parent) => {
164
+ const rulesetContent = node.content;
165
+
166
+ // Remove empty selectors and trailing deliminator and space
167
+ let i = 0;
168
+ let currNode = rulesetContent[i];
169
+ while (currNode) {
170
+ if (currNode.is('selector') && currNode.content.length === 0) {
171
+ node.removeChild(i);
172
+ if (rulesetContent[i].is('delimiter')) node.removeChild(i);
173
+ if (rulesetContent[i].is('space')) node.removeChild(i);
174
+ } else {
175
+ i++;
176
+ }
177
+ currNode = rulesetContent[i];
178
+ }
179
+
180
+ // Remove the ruleset if no selectors
181
+ if (rulesetContent.filter(node => node.is('selector')).length === 0) {
182
+ parent.removeChild(index);
183
+ }
184
+ });
185
+ };
186
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJnZXRJQ1NTRXhwb3J0UHJvcHNNYXAiLCJhc3QiLCJydWxlU2V0cyIsInRyYXZlcnNlQnlUeXBlIiwibm9kZSIsInB1c2giLCJmaWx0ZXIiLCJydWxlU2V0IiwiY29udGVudCIsInNvbWUiLCJpdGVtIiwidHlwZSIsInNlbGVjdG9ySXRlbSIsInBzZXVkb0l0ZW0iLCJyZWR1Y2UiLCJyZXN1bHQiLCJkZWNsYXJhdGlvbnMiLCJmbGF0TWFwIiwiYmxvY2siLCJkZWNsYXJhdGlvbiIsInByb3BlcnR5IiwiZmluZCIsInByb3BOYW1lIiwiZ2V0UmVndWxhckNsYXNzZXNNYXAiLCJzZWxlY3RvcnMiLCJzZWxlY3RvciIsImNsYXNzZXMiLCJjbGFzc05vZGUiLCJpZGVudCIsImdldENvbXBvc2VzQ2xhc3Nlc01hcCIsImhhc0NvbXBvc2VzIiwidmFsdWUiLCJ2YWx1ZUNvbnRlbnQiLCJjb21wb3NlZENsYXNzZXMiLCJnZXRFeHRlbmRDbGFzc2VzTWFwIiwiZXh0ZW5kTm9kZXMiLCJleHRlbmROb2RlIiwiY2xhc3NOYW1lIiwiZ2V0UGFyZW50U2VsZWN0b3JDbGFzc2VzTWFwIiwiY2xhc3Nlc01hcCIsImdldEV4dGVuc2lvbnMiLCJub2RlQ29udGVudCIsImJsb2NrQ29udGVudCIsInJ1bGVzZXRDaGlsZHJlbiIsInJ1bGVzZXREZXNjZW5kYW50cyIsInN1Ykl0ZW0iLCJydWxlc2V0c0NvbnRlbnQiLCJleHRlbnNpb25zIiwiaWRlbnRJdGVtIiwibWFwIiwibGVuZ3RoIiwibmVzdGVkRXh0ZW5zaW9ucyIsIm5lc3RlZEV4dCIsImZvckVhY2giLCJleHQiLCJjbGFzc05hbWVzIiwiaGFzRGVjbGFyYXRpb25zIiwiZWxpbWluYXRlR2xvYmFscyIsInNlbGVjdG9yTm9kZSIsInNlbGVjdG9yQ29udGVudCIsImhhc0dsb2JhbFdpdGhOb0FyZ3MiLCJpIiwiY3Vyck5vZGUiLCJpcyIsImlkZW50aWZpZXJOb2RlIiwicmVtb3ZlQ2hpbGQiLCJpbmRleCIsInBhcmVudCIsInJ1bGVzZXRDb250ZW50Il0sInNvdXJjZXMiOlsiLi4vLi4vbGliL2NvcmUvdHJhdmVyc2FsVXRpbHMuanMiXSwic291cmNlc0NvbnRlbnQiOlsiLy8gQGZsb3dcbi8qIGVzbGludC1kaXNhYmxlIG5vLXBhcmFtLXJlYXNzaWduICovXG5cbmltcG9ydCB0eXBlIHsgZ0FTVE5vZGUgfSBmcm9tICcuLi90eXBlcy9pbmRleC5qcyc7XG5cbnR5cGUgY2xhc3NNYXBUeXBlID0ge1xuICBba2V5OiBzdHJpbmddOiBib29sZWFuLFxufVxuXG5leHBvcnQgY29uc3QgZ2V0SUNTU0V4cG9ydFByb3BzTWFwID0gKGFzdDogZ0FTVE5vZGUpOiBjbGFzc01hcFR5cGUgPT4ge1xuICBjb25zdCBydWxlU2V0czogQXJyYXk8Z0FTVE5vZGU+ID0gW107XG4gIGFzdC50cmF2ZXJzZUJ5VHlwZSgncnVsZXNldCcsIG5vZGUgPT4gcnVsZVNldHMucHVzaChub2RlKSk7XG5cbiAgcmV0dXJuIHJ1bGVTZXRzXG4gICAgLmZpbHRlcihydWxlU2V0ID0+IHtcbiAgICAgIGNvbnN0IGNvbnRlbnQgPSBydWxlU2V0LmNvbnRlbnQgfHwgW107XG4gICAgICByZXR1cm4gY29udGVudC5zb21lKGl0ZW0gPT5cbiAgICAgICAgaXRlbS50eXBlID09PSAnc2VsZWN0b3InICYmXG4gICAgICAgIGl0ZW0uY29udGVudD8uc29tZShzZWxlY3Rvckl0ZW0gPT5cbiAgICAgICAgICBzZWxlY3Rvckl0ZW0udHlwZSA9PT0gJ3BzZXVkb0NsYXNzJyAmJlxuICAgICAgICAgIHNlbGVjdG9ySXRlbS5jb250ZW50Py5zb21lKHBzZXVkb0l0ZW0gPT5cbiAgICAgICAgICAgIHBzZXVkb0l0ZW0udHlwZSA9PT0gJ2lkZW50JyAmJiBwc2V1ZG9JdGVtLmNvbnRlbnQgPT09ICdleHBvcnQnXG4gICAgICAgICAgKVxuICAgICAgICApXG4gICAgICApO1xuICAgIH0pXG4gICAgLnJlZHVjZSgocmVzdWx0LCBydWxlU2V0KSA9PiB7XG4gICAgICBjb25zdCBkZWNsYXJhdGlvbnMgPSAocnVsZVNldC5jb250ZW50IHx8IFtdKVxuICAgICAgICAuZmlsdGVyKGl0ZW0gPT4gaXRlbS50eXBlID09PSAnYmxvY2snKVxuICAgICAgICAuZmxhdE1hcChibG9jayA9PiAoYmxvY2suY29udGVudCB8fCBbXSkpXG4gICAgICAgIC5maWx0ZXIoaXRlbSA9PiBpdGVtLnR5cGUgPT09ICdkZWNsYXJhdGlvbicpO1xuXG4gICAgICBmb3IgKGNvbnN0IGRlY2xhcmF0aW9uIG9mIGRlY2xhcmF0aW9ucykge1xuICAgICAgICBjb25zdCBwcm9wZXJ0eSA9IChkZWNsYXJhdGlvbi5jb250ZW50IHx8IFtdKS5maW5kKGl0ZW0gPT4gaXRlbS50eXBlID09PSAncHJvcGVydHknKTtcbiAgICAgICAgY29uc3QgcHJvcE5hbWUgPSAocHJvcGVydHk/LmNvbnRlbnQgfHwgW10pWzBdPy5jb250ZW50O1xuICAgICAgICBpZiAocHJvcE5hbWUpIHtcbiAgICAgICAgICByZXN1bHRbcHJvcE5hbWVdID0gcHJvcE5hbWU7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9LCB7fSk7XG59O1xuXG5leHBvcnQgY29uc3QgZ2V0UmVndWxhckNsYXNzZXNNYXAgPSAoYXN0OiBnQVNUTm9kZSk6IGNsYXNzTWFwVHlwZSA9PiB7XG4gIGNvbnN0IHJ1bGVTZXRzOiBBcnJheTxnQVNUTm9kZT4gPSBbXTtcbiAgYXN0LnRyYXZlcnNlQnlUeXBlKCdydWxlc2V0Jywgbm9kZSA9PiBydWxlU2V0cy5wdXNoKG5vZGUpKTtcblxuICByZXR1cm4gcnVsZVNldHNcbiAgICAucmVkdWNlKChyZXN1bHQsIHJ1bGVTZXQpID0+IHtcbiAgICAgIGNvbnN0IHNlbGVjdG9ycyA9IHJ1bGVTZXQuY29udGVudD8uZmlsdGVyKGl0ZW0gPT4gaXRlbS50eXBlID09PSAnc2VsZWN0b3InKSA/PyBbXTtcbiAgICAgIGZvciAoY29uc3Qgc2VsZWN0b3Igb2Ygc2VsZWN0b3JzKSB7XG4gICAgICAgIGNvbnN0IGNsYXNzZXMgPSBzZWxlY3Rvci5jb250ZW50Py5maWx0ZXIoaXRlbSA9PiBpdGVtLnR5cGUgPT09ICdjbGFzcycpID8/IFtdO1xuICAgICAgICBmb3IgKGNvbnN0IGNsYXNzTm9kZSBvZiBjbGFzc2VzKSB7XG4gICAgICAgICAgY29uc3QgaWRlbnQgPSBjbGFzc05vZGUuY29udGVudD8uZmluZChpdGVtID0+IGl0ZW0udHlwZSA9PT0gJ2lkZW50Jyk7XG4gICAgICAgICAgaWYgKGlkZW50Py5jb250ZW50KSB7XG4gICAgICAgICAgICByZXN1bHRbaWRlbnQuY29udGVudF0gPSBmYWxzZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfSwge30pO1xufTtcblxuZXhwb3J0IGNvbnN0IGdldENvbXBvc2VzQ2xhc3Nlc01hcCA9IChhc3Q6IGdBU1ROb2RlKTogY2xhc3NNYXBUeXBlID0+IHtcbiAgY29uc3QgZGVjbGFyYXRpb25zID0gW107XG4gIGFzdC50cmF2ZXJzZUJ5VHlwZSgnZGVjbGFyYXRpb24nLCBub2RlID0+IGRlY2xhcmF0aW9ucy5wdXNoKG5vZGUpKTtcblxuICByZXR1cm4gZGVjbGFyYXRpb25zXG4gICAgLnJlZHVjZSgocmVzdWx0LCBkZWNsYXJhdGlvbikgPT4ge1xuICAgICAgY29uc3QgY29udGVudCA9IGRlY2xhcmF0aW9uLmNvbnRlbnQ7XG4gICAgICBjb25zdCBwcm9wZXJ0eSA9IGNvbnRlbnQ/LmZpbmQoaXRlbSA9PiBpdGVtLnR5cGUgPT09ICdwcm9wZXJ0eScpO1xuICAgICAgY29uc3QgaGFzQ29tcG9zZXMgPSBwcm9wZXJ0eT8uY29udGVudD8uc29tZShpdGVtID0+XG4gICAgICAgIGl0ZW0udHlwZSA9PT0gJ2lkZW50JyAmJiBpdGVtLmNvbnRlbnQgPT09ICdjb21wb3NlcydcbiAgICAgICk7XG5cbiAgICAgIGlmICghaGFzQ29tcG9zZXMpIHJldHVybiByZXN1bHQ7XG5cbiAgICAgIGNvbnN0IHZhbHVlID0gY29udGVudD8uZmluZChpdGVtID0+IGl0ZW0udHlwZSA9PT0gJ3ZhbHVlJyk7XG4gICAgICBjb25zdCB2YWx1ZUNvbnRlbnQgPSB2YWx1ZT8uY29udGVudDtcblxuICAgICAgLy8gUmVqZWN0IGNsYXNzZXMgY29tcG9zaW5nIGZyb20gb3RoZXIgZmlsZXMsIGUuZy4gYGNvbXBvc2VzOiBmb28gZnJvbSAnLi9vdGhlci5jc3MnYFxuICAgICAgaWYgKHZhbHVlQ29udGVudD8uc29tZShpdGVtID0+IGl0ZW0udHlwZSA9PT0gJ2lkZW50JyAmJiBpdGVtLmNvbnRlbnQgPT09ICdmcm9tJykpIHtcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgIH1cblxuICAgICAgLy8gRXh0cmFjdCBhbmQgbWFyayBjb21wb3NlZCBjbGFzc2VzXG4gICAgICBjb25zdCBjb21wb3NlZENsYXNzZXMgPSB2YWx1ZUNvbnRlbnQ/LmZpbHRlcihpdGVtID0+IGl0ZW0udHlwZSA9PT0gJ2lkZW50JyAmJiBpdGVtLmNvbnRlbnQpID8/IFtdO1xuICAgICAgZm9yIChjb25zdCBpdGVtIG9mIGNvbXBvc2VkQ2xhc3Nlcykge1xuICAgICAgICByZXN1bHRbaXRlbS5jb250ZW50XSA9IHRydWU7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfSwge30pO1xufTtcblxuZXhwb3J0IGNvbnN0IGdldEV4dGVuZENsYXNzZXNNYXAgPSAoYXN0OiBnQVNUTm9kZSk6IGNsYXNzTWFwVHlwZSA9PiB7XG4gIGNvbnN0IGV4dGVuZE5vZGVzID0gW107XG4gIGFzdC50cmF2ZXJzZUJ5VHlwZSgnZXh0ZW5kJywgbm9kZSA9PiBleHRlbmROb2Rlcy5wdXNoKG5vZGUpKTtcblxuICByZXR1cm4gZXh0ZW5kTm9kZXMucmVkdWNlKChyZXN1bHQsIGV4dGVuZE5vZGUpID0+IHtcbiAgICBjb25zdCBzZWxlY3RvciA9IGV4dGVuZE5vZGUuY29udGVudD8uZmluZChpdGVtID0+IGl0ZW0udHlwZSA9PT0gJ3NlbGVjdG9yJyk7XG4gICAgY29uc3QgY2xhc3NOb2RlID0gc2VsZWN0b3I/LmNvbnRlbnQ/LmZpbmQoaXRlbSA9PiBpdGVtLnR5cGUgPT09ICdjbGFzcycpO1xuICAgIGNvbnN0IGlkZW50ID0gY2xhc3NOb2RlPy5jb250ZW50Py5maW5kKGl0ZW0gPT4gaXRlbS50eXBlID09PSAnaWRlbnQnKTtcbiAgICBjb25zdCBjbGFzc05hbWUgPSBpZGVudD8uY29udGVudDtcblxuICAgIGlmIChjbGFzc05hbWUpIHtcbiAgICAgIHJlc3VsdFtjbGFzc05hbWVdID0gdHJ1ZTsgLy8gbWFyayBleHRlbmQgY2xhc3NlcyBhcyB0cnVlXG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfSwge30pO1xufTtcblxuLyoqXG4gKiBSZXNvbHZlcyBwYXJlbnQgc2VsZWN0b3JzIHRvIHRoZWlyIGZ1bGwgY2xhc3MgbmFtZXMuXG4gKlxuICogRS5nLiBgLmZvbyB7ICZfYmFyIHtjb2xvcjogYmx1ZSB9IH1gIHRvIGAuZm9vX2JhcmAuXG4gKi9cbmV4cG9ydCBjb25zdCBnZXRQYXJlbnRTZWxlY3RvckNsYXNzZXNNYXAgPSAoYXN0OiBnQVNUTm9kZSk6IGNsYXNzTWFwVHlwZSA9PiB7XG4gIGNvbnN0IGNsYXNzZXNNYXA6IGNsYXNzTWFwVHlwZSA9IHt9O1xuXG4gIC8vIFJlY3Vyc2l2ZWx5IHRyYXZlcnNlcyBkb3duIHRoZSB0cmVlIGxvb2tpbmcgZm9yIHBhcmVudCBzZWxlY3RvclxuICAvLyBleHRlbnNpb25zLiBSZWN1cnNpb24gaXMgbmVjZXNzYXJ5IGFzIHRoZXNlIHNlbGVjdG9ycyBjYW4gYmUgbmVzdGVkLlxuICBjb25zdCBnZXRFeHRlbnNpb25zID0gbm9kZUNvbnRlbnQgPT4ge1xuICAgIGNvbnN0IGJsb2NrQ29udGVudCA9IG5vZGVDb250ZW50XG4gICAgICAuZmlsdGVyKGl0ZW0gPT4gaXRlbS50eXBlID09PSAnYmxvY2snKVxuICAgICAgLmZsYXRNYXAoaXRlbSA9PiBpdGVtLmNvbnRlbnQgfHwgW10pO1xuXG4gICAgY29uc3QgcnVsZXNldENoaWxkcmVuID0gYmxvY2tDb250ZW50LmZpbHRlcihpdGVtID0+IGl0ZW0udHlwZSA9PT0gJ3J1bGVzZXQnKTtcblxuICAgIGNvbnN0IHJ1bGVzZXREZXNjZW5kYW50cyA9IGJsb2NrQ29udGVudFxuICAgICAgLmZpbHRlcihpdGVtID0+IGl0ZW0udHlwZSA9PT0gJ2luY2x1ZGUnKVxuICAgICAgLmZsYXRNYXAoaXRlbSA9PiBpdGVtLmNvbnRlbnQgfHwgW10pXG4gICAgICAuZmlsdGVyKHN1Ykl0ZW0gPT4gc3ViSXRlbS50eXBlID09PSAnYmxvY2snKVxuICAgICAgLmZsYXRNYXAoc3ViSXRlbSA9PiBzdWJJdGVtLmNvbnRlbnQgfHwgW10pXG4gICAgICAuZmlsdGVyKHN1Ykl0ZW0gPT4gc3ViSXRlbS50eXBlID09PSAncnVsZXNldCcpO1xuXG4gICAgY29uc3QgcnVsZXNldHNDb250ZW50ID0gWy4uLnJ1bGVzZXRDaGlsZHJlbiwgLi4ucnVsZXNldERlc2NlbmRhbnRzXVxuICAgICAgLmZsYXRNYXAoaXRlbSA9PiBpdGVtLmNvbnRlbnQgfHwgW10pO1xuXG4gICAgY29uc3QgZXh0ZW5zaW9ucyA9IHJ1bGVzZXRzQ29udGVudFxuICAgICAgLmZpbHRlcihpdGVtID0+IGl0ZW0udHlwZSA9PT0gJ3NlbGVjdG9yJylcbiAgICAgIC5mbGF0TWFwKGl0ZW0gPT4gaXRlbS5jb250ZW50IHx8IFtdKVxuICAgICAgLmZpbHRlcihzZWxlY3Rvckl0ZW0gPT4gc2VsZWN0b3JJdGVtLnR5cGUgPT09ICdwYXJlbnRTZWxlY3RvckV4dGVuc2lvbicpXG4gICAgICAuZmxhdE1hcChzZWxlY3Rvckl0ZW0gPT4gc2VsZWN0b3JJdGVtLmNvbnRlbnQgfHwgW10pXG4gICAgICAuZmlsdGVyKGlkZW50SXRlbSA9PiBpZGVudEl0ZW0udHlwZSA9PT0gJ2lkZW50JylcbiAgICAgIC5tYXAoaWRlbnRJdGVtID0+IGlkZW50SXRlbS5jb250ZW50KTtcblxuICAgIGlmICghZXh0ZW5zaW9ucy5sZW5ndGgpIHJldHVybiBbXTtcblxuICAgIGNvbnN0IG5lc3RlZEV4dGVuc2lvbnMgPSBnZXRFeHRlbnNpb25zKHJ1bGVzZXRzQ29udGVudCk7XG4gICAgY29uc3QgcmVzdWx0ID0gZXh0ZW5zaW9ucztcbiAgICBpZiAobmVzdGVkRXh0ZW5zaW9ucy5sZW5ndGgpIHtcbiAgICAgIGZvciAoY29uc3QgbmVzdGVkRXh0IG9mIG5lc3RlZEV4dGVuc2lvbnMpIHtcbiAgICAgICAgZXh0ZW5zaW9ucy5mb3JFYWNoKGV4dCA9PiB7XG4gICAgICAgICAgcmVzdWx0LnB1c2goZXh0ICsgbmVzdGVkRXh0KTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfTtcblxuICBhc3QudHJhdmVyc2VCeVR5cGUoJ3J1bGVzZXQnLCBub2RlID0+IHtcbiAgICBjb25zdCBjbGFzc05hbWVzID0gKG5vZGUuY29udGVudCB8fCBbXSlcbiAgICAgIC5maWx0ZXIoaXRlbSA9PiBpdGVtLnR5cGUgPT09ICdzZWxlY3RvcicpXG4gICAgICAuZmxhdE1hcChpdGVtID0+IGl0ZW0uY29udGVudCB8fCBbXSlcbiAgICAgIC5maWx0ZXIoaXRlbSA9PiBpdGVtLnR5cGUgPT09ICdjbGFzcycpXG4gICAgICAuZmxhdE1hcChpdGVtID0+IGl0ZW0uY29udGVudCB8fCBbXSlcbiAgICAgIC5maWx0ZXIoaXRlbSA9PiBpdGVtLnR5cGUgPT09ICdpZGVudCcgJiYgaXRlbS5jb250ZW50KVxuICAgICAgLm1hcChpdGVtID0+IGl0ZW0uY29udGVudCk7XG5cbiAgICBpZiAoIWNsYXNzTmFtZXMubGVuZ3RoKSByZXR1cm47XG5cbiAgICBjb25zdCBleHRlbnNpb25zID0gZ2V0RXh0ZW5zaW9ucyhub2RlLmNvbnRlbnQpO1xuICAgIGlmICghZXh0ZW5zaW9ucy5sZW5ndGgpIHJldHVybjtcblxuICAgIGNsYXNzTmFtZXMuZm9yRWFjaChjbGFzc05hbWUgPT4ge1xuICAgICAgZXh0ZW5zaW9ucy5mb3JFYWNoKGV4dCA9PiB7XG4gICAgICAgIGNsYXNzZXNNYXBbY2xhc3NOYW1lICsgZXh0XSA9IGZhbHNlO1xuICAgICAgfSk7XG5cbiAgICAgIC8vIElnbm9yZSB0aGUgYmFzZSBjbGFzcyBpZiBpdCBvbmx5IGV4aXN0cyBmb3IgbmVzdGluZyBwYXJlbnQgc2VsZWN0b3JzXG4gICAgICBjb25zdCBoYXNEZWNsYXJhdGlvbnMgPSBub2RlLmNvbnRlbnQ/LnNvbWUoaXRlbSA9PiBpdGVtLnR5cGUgPT09ICdibG9jaycgJiZcbiAgICAgICAgICBpdGVtLmNvbnRlbnQ/LnNvbWUoc3ViSXRlbSA9PiBzdWJJdGVtLnR5cGUgPT09ICdkZWNsYXJhdGlvbicpKTtcbiAgICAgIGlmICghaGFzRGVjbGFyYXRpb25zKSBjbGFzc2VzTWFwW2NsYXNzTmFtZV0gPSB0cnVlO1xuICAgIH0pO1xuICB9KTtcblxuICByZXR1cm4gY2xhc3Nlc01hcDtcbn07XG5cbi8qKlxuICogTXV0YXRlcyB0aGUgQVNUIGJ5IHJlbW92aW5nIGA6Z2xvYmFsYCBpbnN0YW5jZXMuXG4gKlxuICogRm9yIHRoZSBBU1Qgc3RydWN0dXJlOlxuICogQHNlZSBodHRwczovL2dpdGh1Yi5jb20vY3NzL2dvbnphbGVzL2Jsb2IvbWFzdGVyL2RvYy9BU1QuQ1NTUC5lbi5tZFxuICovXG5leHBvcnQgY29uc3QgZWxpbWluYXRlR2xvYmFscyA9IChhc3Q6IGdBU1ROb2RlKSA9PiB7XG4gIC8vIFJlbW92ZSBhbGwgOmdsb2JhbC86Z2xvYmFsKC4uLikgaW4gc2VsZWN0b3JzXG4gIGFzdC50cmF2ZXJzZUJ5VHlwZSgnc2VsZWN0b3InLCAoc2VsZWN0b3JOb2RlKSA9PiB7XG4gICAgY29uc3Qgc2VsZWN0b3JDb250ZW50ID0gc2VsZWN0b3JOb2RlLmNvbnRlbnQ7XG4gICAgbGV0IGhhc0dsb2JhbFdpdGhOb0FyZ3MgPSBmYWxzZTtcbiAgICBsZXQgaSA9IDA7XG4gICAgbGV0IGN1cnJOb2RlID0gc2VsZWN0b3JDb250ZW50W2ldO1xuICAgIHdoaWxlIChjdXJyTm9kZSkge1xuICAgICAgaWYgKGN1cnJOb2RlLmlzKCdwc2V1ZG9DbGFzcycpKSB7XG4gICAgICAgIC8vIFJlbW92ZSBhbGwgOmdsb2JhbC86Z2xvYmFsKC4uLikgYW5kIHRyYWlsaW5nIHNwYWNlXG4gICAgICAgIGNvbnN0IGlkZW50aWZpZXJOb2RlID0gY3Vyck5vZGUuY29udGVudFswXTtcbiAgICAgICAgaWYgKGlkZW50aWZpZXJOb2RlICYmIGlkZW50aWZpZXJOb2RlLmNvbnRlbnQgPT09ICdnbG9iYWwnKSB7XG4gICAgICAgICAgaWYgKGN1cnJOb2RlLmNvbnRlbnQubGVuZ3RoID09PSAxKSBoYXNHbG9iYWxXaXRoTm9BcmdzID0gdHJ1ZTtcbiAgICAgICAgICBzZWxlY3Rvck5vZGUucmVtb3ZlQ2hpbGQoaSk7XG4gICAgICAgICAgaWYgKHNlbGVjdG9yQ29udGVudFtpXSAmJiBzZWxlY3RvckNvbnRlbnRbaV0uaXMoJ3NwYWNlJykpIHtcbiAgICAgICAgICAgIHNlbGVjdG9yTm9kZS5yZW1vdmVDaGlsZChpKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgaSsrO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKGN1cnJOb2RlLmlzKCdjbGFzcycpICYmIGhhc0dsb2JhbFdpdGhOb0FyZ3MpIHtcbiAgICAgICAgLy8gUmVtb3ZlIGFsbCBjbGFzcyBhZnRlciA6Z2xvYmFsIGFuZCB0aGVpciB0cmFpbGluZyBzcGFjZVxuICAgICAgICBzZWxlY3Rvck5vZGUucmVtb3ZlQ2hpbGQoaSk7XG4gICAgICAgIGlmIChzZWxlY3RvckNvbnRlbnRbaV0gJiYgc2VsZWN0b3JDb250ZW50W2ldLmlzKCdzcGFjZScpKSB7XG4gICAgICAgICAgc2VsZWN0b3JOb2RlLnJlbW92ZUNoaWxkKGkpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBpKys7XG4gICAgICB9XG5cbiAgICAgIGN1cnJOb2RlID0gc2VsZWN0b3JDb250ZW50W2ldO1xuICAgIH1cbiAgfSk7XG5cbiAgLy8gUmVtb3ZlIGFsbCBydWxlc2V0IHdpdGggbm8gc2VsZWN0b3JzXG4gIGFzdC50cmF2ZXJzZUJ5VHlwZSgncnVsZXNldCcsIChub2RlLCBpbmRleCwgcGFyZW50KSA9PiB7XG4gICAgY29uc3QgcnVsZXNldENvbnRlbnQgPSBub2RlLmNvbnRlbnQ7XG5cbiAgICAvLyBSZW1vdmUgZW1wdHkgc2VsZWN0b3JzIGFuZCB0cmFpbGluZyBkZWxpbWluYXRvciBhbmQgc3BhY2VcbiAgICBsZXQgaSA9IDA7XG4gICAgbGV0IGN1cnJOb2RlID0gcnVsZXNldENvbnRlbnRbaV07XG4gICAgd2hpbGUgKGN1cnJOb2RlKSB7XG4gICAgICBpZiAoY3Vyck5vZGUuaXMoJ3NlbGVjdG9yJykgJiYgY3Vyck5vZGUuY29udGVudC5sZW5ndGggPT09IDApIHtcbiAgICAgICAgbm9kZS5yZW1vdmVDaGlsZChpKTtcbiAgICAgICAgaWYgKHJ1bGVzZXRDb250ZW50W2ldLmlzKCdkZWxpbWl0ZXInKSkgbm9kZS5yZW1vdmVDaGlsZChpKTtcbiAgICAgICAgaWYgKHJ1bGVzZXRDb250ZW50W2ldLmlzKCdzcGFjZScpKSBub2RlLnJlbW92ZUNoaWxkKGkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaSsrO1xuICAgICAgfVxuICAgICAgY3Vyck5vZGUgPSBydWxlc2V0Q29udGVudFtpXTtcbiAgICB9XG5cbiAgICAvLyBSZW1vdmUgdGhlIHJ1bGVzZXQgaWYgbm8gc2VsZWN0b3JzXG4gICAgaWYgKHJ1bGVzZXRDb250ZW50LmZpbHRlcigobm9kZSkgPT4gbm9kZS5pcygnc2VsZWN0b3InKSkubGVuZ3RoID09PSAwKSB7XG4gICAgICBwYXJlbnQucmVtb3ZlQ2hpbGQoaW5kZXgpO1xuICAgIH1cbiAgfSk7XG59O1xuIl0sIm1hcHBpbmdzIjoiQUFDQTtBQVFBLE9BQU8sTUFBTUEscUJBQXFCLEdBQUlDLEdBQWEsSUFBbUI7RUFDcEUsTUFBTUMsUUFBeUIsR0FBRyxFQUFFO0VBQ3BDRCxHQUFHLENBQUNFLGNBQWMs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
package/build/index.js ADDED
@@ -0,0 +1,27 @@
1
+ import fs from 'node:fs';
2
+ import rules from './rules/index.js';
3
+ const pkg = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
4
+ const plugin = {
5
+ meta: {
6
+ name: pkg.name,
7
+ version: pkg.version,
8
+ namespace: 'css-modules'
9
+ },
10
+ configs: {},
11
+ rules
12
+ };
13
+ Object.assign(plugin.configs, {
14
+ recommended: [{
15
+ plugins: {
16
+ 'css-modules': plugin
17
+ },
18
+ rules: {
19
+ 'css-modules/no-unused-class': 2,
20
+ // error
21
+ 'css-modules/no-undef-class': 2 // error
22
+ }
23
+ }]
24
+ });
25
+
26
+ export default plugin;
27
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJmcyIsInJ1bGVzIiwicGtnIiwiSlNPTiIsInBhcnNlIiwicmVhZEZpbGVTeW5jIiwiVVJMIiwiaW1wb3J0IiwibWV0YSIsInVybCIsInBsdWdpbiIsIm5hbWUiLCJ2ZXJzaW9uIiwibmFtZXNwYWNlIiwiY29uZmlncyIsIk9iamVjdCIsImFzc2lnbiIsInJlY29tbWVuZGVkIiwicGx1Z2lucyJdLCJzb3VyY2VzIjpbIi4uL2xpYi9pbmRleC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgZnMgZnJvbSAnbm9kZTpmcyc7XG5pbXBvcnQgcnVsZXMgZnJvbSAnLi9ydWxlcy9pbmRleC5qcyc7XG5cbmNvbnN0IHBrZyA9IEpTT04ucGFyc2UoXG4gIGZzLnJlYWRGaWxlU3luYyhuZXcgVVJMKCcuLi9wYWNrYWdlLmpzb24nLCBpbXBvcnQubWV0YS51cmwpLCAndXRmOCcpLFxuKTtcblxuY29uc3QgcGx1Z2luID0ge1xuICBtZXRhOiB7XG4gICAgbmFtZTogcGtnLm5hbWUsXG4gICAgdmVyc2lvbjogcGtnLnZlcnNpb24sXG4gICAgbmFtZXNwYWNlOiAnY3NzLW1vZHVsZXMnLFxuICB9LFxuICBjb25maWdzOiB7fSxcbiAgcnVsZXMsXG59O1xuXG5PYmplY3QuYXNzaWduKHBsdWdpbi5jb25maWdzLCB7XG4gIHJlY29tbWVuZGVkOiBbXG4gICAge1xuICAgICAgcGx1Z2luczoge1xuICAgICAgICAnY3NzLW1vZHVsZXMnOiBwbHVnaW4sXG4gICAgICB9LFxuICAgICAgcnVsZXM6IHtcbiAgICAgICAgJ2Nzcy1tb2R1bGVzL25vLXVudXNlZC1jbGFzcyc6IDIsIC8vIGVycm9yXG4gICAgICAgICdjc3MtbW9kdWxlcy9uby11bmRlZi1jbGFzcyc6IDIsIC8vIGVycm9yXG4gICAgICB9LFxuICAgIH0sXG4gIF0sXG59KTtcblxuZXhwb3J0IGRlZmF1bHQgcGx1Z2luO1xuIl0sIm1hcHBpbmdzIjoiQUFBQSxPQUFPQSxFQUFFLE1BQU0sU0FBUztBQUN4QixPQUFPQyxLQUFLLE1BQU0sa0JBQWtCO0FBRXBDLE1BQU1DLEdBQUcsR0FBR0MsSUFBSSxDQUFDQyxLQUFLLENBQ3BCSixFQUFFLENBQUNLLFlBQVksQ0FBQyxJQUFJQyxHQUFHLENBQUMsaUJBQWlCLEVBQUVDLE1BQU0sQ0FBQ0MsSUFBSSxDQUFDQyxHQUFHLENBQUMsRUFBRSxNQUFNLENBQ3JFLENBQUM7QUFFRCxNQUFNQyxNQUFNLEdBQUc7RUFDYkYsSUFBSSxFQUFFO0lBQ0pHLElBQUksRUFBRVQsR0FBRyxDQUFDUyxJQUFJO0lBQ2RDLE9BQU8sRUFBRVYsR0FBRyxDQUFDVSxPQUFPO0lBQ3BCQyxTQUFTLEVBQUU7RUFDYixDQUFDO0VBQ0RDLE9BQU8sRUFBRSxDQUFDLENBQUM7RUFDWGI7QUFDRixDQUFDO0FBRURjLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDTixNQUFNLENBQUNJLE9BQU8sRUFBRTtFQUM1QkcsV0FBVyxFQUFFLENBQ1g7SUFDRUMsT0FBTyxFQUFFO01BQ1AsYUFBYSxFQUFFUjtJQUNqQixDQUFDO0lBQ0RULEtBQUssRUFBRTtNQUNMLDZCQUE2QixFQUFFLENBQUM7TUFBRTtNQUNsQyw0QkFBNEIsRUFBRSxDQUFDLENBQUU7SUFDbkM7RUFDRixDQUFDO0FBRUwsQ0FBQyxDQUFDOztBQUVGLGVBQWVTLE1BQU0ifQ==
@@ -0,0 +1,7 @@
1
+ import noUnusedClass from './no-unused-class.js';
2
+ import noUndefClass from './no-undef-class.js';
3
+ export default {
4
+ 'no-unused-class': noUnusedClass,
5
+ 'no-undef-class': noUndefClass
6
+ };
7
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJub1VudXNlZENsYXNzIiwibm9VbmRlZkNsYXNzIl0sInNvdXJjZXMiOlsiLi4vLi4vbGliL3J1bGVzL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBub1VudXNlZENsYXNzIGZyb20gJy4vbm8tdW51c2VkLWNsYXNzLmpzJztcbmltcG9ydCBub1VuZGVmQ2xhc3MgZnJvbSAnLi9uby11bmRlZi1jbGFzcy5qcyc7XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgJ25vLXVudXNlZC1jbGFzcyc6IG5vVW51c2VkQ2xhc3MsXG4gICduby11bmRlZi1jbGFzcyc6IG5vVW5kZWZDbGFzcyxcbn07XG4iXSwibWFwcGluZ3MiOiJBQUFBLE9BQU9BLGFBQWEsTUFBTSxzQkFBc0I7QUFDaEQsT0FBT0MsWUFBWSxNQUFNLHFCQUFxQjtBQUU5QyxlQUFlO0VBQ2IsaUJBQWlCLEVBQUVELGFBQWE7RUFDaEMsZ0JBQWdCLEVBQUVDO0FBQ3BCLENBQUMifQ==
@@ -0,0 +1,86 @@
1
+ import { getStyleImportNodeData, getAST, fileExists, getStyleClasses, getPropertyName, getClassesMap, getExportPropsMap, getFilePath } from '../core/index.js';
2
+ export default {
3
+ meta: {
4
+ docs: {
5
+ description: 'Checks that you are using the existent css/scss/less classes',
6
+ recommended: true
7
+ },
8
+ schema: [{
9
+ type: 'object',
10
+ properties: {
11
+ camelCase: {
12
+ enum: [true, 'dashes', 'only', 'dashes-only']
13
+ }
14
+ }
15
+ }]
16
+ },
17
+ create(context) {
18
+ const camelCase = context?.options[0]?.camelCase;
19
+
20
+ /*
21
+ maps variable name to property Object
22
+ map = {
23
+ [variableName]: {
24
+ classesMap: { foo: 'foo', fooBar: 'foo-bar', 'foo-bar': 'foo-bar' },
25
+ node: {...}
26
+ }
27
+ }
28
+ example:
29
+ import s from './foo.scss';
30
+ s is variable name
31
+ property Object has two keys
32
+ 1. classesMap: an object with propertyName as key and its className as value
33
+ 2. node: node that correspond to s (see example above)
34
+ */
35
+ const map = {};
36
+ return {
37
+ ImportDeclaration(node) {
38
+ const styleImportNodeData = getStyleImportNodeData(node);
39
+ if (!styleImportNodeData) {
40
+ return;
41
+ }
42
+ const {
43
+ importName,
44
+ styleFilePath,
45
+ importNode
46
+ } = styleImportNodeData;
47
+ const styleFileAbsolutePath = getFilePath(context, styleFilePath);
48
+ let classesMap = {};
49
+ let exportPropsMap = {};
50
+ if (fileExists(styleFileAbsolutePath)) {
51
+ const ast = getAST(styleFileAbsolutePath);
52
+ const classes = ast && getStyleClasses(ast);
53
+ classesMap = classes && getClassesMap(classes, camelCase);
54
+ exportPropsMap = ast && getExportPropsMap(ast);
55
+ }
56
+ map[importName] ??= {};
57
+
58
+ // this will be used to check if classes are defined
59
+ map[importName].classesMap = classesMap;
60
+
61
+ // this will be used to check if :export properties are defined
62
+ map[importName].exportPropsMap = exportPropsMap;
63
+
64
+ // save node for reporting unused styles
65
+ map[importName].node = importNode;
66
+ },
67
+ MemberExpression: node => {
68
+ /*
69
+ Check if property exists in css/scss file as class
70
+ */
71
+
72
+ const objectName = node.object.name;
73
+ const propertyName = getPropertyName(node, camelCase);
74
+ if (!propertyName) {
75
+ return;
76
+ }
77
+ const classesMap = map[objectName]?.classesMap;
78
+ const exportPropsMap = map[objectName]?.exportPropsMap;
79
+ if (classesMap && classesMap[propertyName] == null && exportPropsMap && exportPropsMap[propertyName] == null) {
80
+ context.report(node.property, `Class or exported property '${propertyName}' not found`);
81
+ }
82
+ }
83
+ };
84
+ }
85
+ };
86
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJnZXRTdHlsZUltcG9ydE5vZGVEYXRhIiwiZ2V0QVNUIiwiZmlsZUV4aXN0cyIsImdldFN0eWxlQ2xhc3NlcyIsImdldFByb3BlcnR5TmFtZSIsImdldENsYXNzZXNNYXAiLCJnZXRFeHBvcnRQcm9wc01hcCIsImdldEZpbGVQYXRoIiwibWV0YSIsImRvY3MiLCJkZXNjcmlwdGlvbiIsInJlY29tbWVuZGVkIiwic2NoZW1hIiwidHlwZSIsInByb3BlcnRpZXMiLCJjYW1lbENhc2UiLCJlbnVtIiwiY3JlYXRlIiwiY29udGV4dCIsIm9wdGlvbnMiLCJtYXAiLCJJbXBvcnREZWNsYXJhdGlvbiIsIm5vZGUiLCJzdHlsZUltcG9ydE5vZGVEYXRhIiwiaW1wb3J0TmFtZSIsInN0eWxlRmlsZVBhdGgiLCJpbXBvcnROb2RlIiwic3R5bGVGaWxlQWJzb2x1dGVQYXRoIiwiY2xhc3Nlc01hcCIsImV4cG9ydFByb3BzTWFwIiwiYXN0IiwiY2xhc3NlcyIsIk1lbWJlckV4cHJlc3Npb24iLCJvYmplY3ROYW1lIiwib2JqZWN0IiwibmFtZSIsInByb3BlcnR5TmFtZSIsInJlcG9ydCIsInByb3BlcnR5Il0sInNvdXJjZXMiOlsiLi4vLi4vbGliL3J1bGVzL25vLXVuZGVmLWNsYXNzLmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qIEBmbG93ICovXG5pbXBvcnQge1xuICBnZXRTdHlsZUltcG9ydE5vZGVEYXRhLFxuICBnZXRBU1QsXG4gIGZpbGVFeGlzdHMsXG4gIGdldFN0eWxlQ2xhc3NlcyxcbiAgZ2V0UHJvcGVydHlOYW1lLFxuICBnZXRDbGFzc2VzTWFwLFxuICBnZXRFeHBvcnRQcm9wc01hcCxcbiAgZ2V0RmlsZVBhdGgsXG59IGZyb20gJy4uL2NvcmUvaW5kZXguanMnO1xuXG5pbXBvcnQgdHlwZSB7IEpzTm9kZSB9IGZyb20gJy4uL3R5cGVzL2luZGV4LmpzJztcblxuZXhwb3J0IGRlZmF1bHQge1xuICBtZXRhOiB7XG4gICAgZG9jczoge1xuICAgICAgZGVzY3JpcHRpb246ICdDaGVja3MgdGhhdCB5b3UgYXJlIHVzaW5nIHRoZSBleGlzdGVudCBjc3Mvc2Nzcy9sZXNzIGNsYXNzZXMnLFxuICAgICAgcmVjb21tZW5kZWQ6IHRydWUsXG4gICAgfSxcbiAgICBzY2hlbWE6IFtcbiAgICAgIHtcbiAgICAgICAgdHlwZTogJ29iamVjdCcsXG4gICAgICAgIHByb3BlcnRpZXM6IHtcbiAgICAgICAgICBjYW1lbENhc2U6IHsgZW51bTogW3RydWUsICdkYXNoZXMnLCAnb25seScsICdkYXNoZXMtb25seSddIH1cbiAgICAgICAgfSxcbiAgICAgIH1cbiAgICBdLFxuICB9LFxuICBjcmVhdGUgKGNvbnRleHQ6IE9iamVjdCkge1xuICAgIGNvbnN0IGNhbWVsQ2FzZSA9IGNvbnRleHQ/Lm9wdGlvbnNbMF0/LmNhbWVsQ2FzZTtcblxuICAgIC8qXG4gICAgICAgbWFwcyB2YXJpYWJsZSBuYW1lIHRvIHByb3BlcnR5IE9iamVjdFxuICAgICAgIG1hcCA9IHtcbiAgICAgICAgIFt2YXJpYWJsZU5hbWVdOiB7XG4gICAgICAgICAgIGNsYXNzZXNNYXA6IHsgZm9vOiAnZm9vJywgZm9vQmFyOiAnZm9vLWJhcicsICdmb28tYmFyJzogJ2Zvby1iYXInIH0sXG4gICAgICAgICAgIG5vZGU6IHsuLi59XG4gICAgICAgICB9XG4gICAgICAgfVxuXG4gICAgICAgZXhhbXBsZTpcbiAgICAgICBpbXBvcnQgcyBmcm9tICcuL2Zvby5zY3NzJztcbiAgICAgICBzIGlzIHZhcmlhYmxlIG5hbWVcblxuICAgICAgIHByb3BlcnR5IE9iamVjdCBoYXMgdHdvIGtleXNcbiAgICAgICAxLiBjbGFzc2VzTWFwOiBhbiBvYmplY3Qgd2l0aCBwcm9wZXJ0eU5hbWUgYXMga2V5IGFuZCBpdHMgY2xhc3NOYW1lIGFzIHZhbHVlXG4gICAgICAgMi4gbm9kZTogbm9kZSB0aGF0IGNvcnJlc3BvbmQgdG8gcyAoc2VlIGV4YW1wbGUgYWJvdmUpXG4gICAgICovXG4gICAgY29uc3QgbWFwID0ge307XG5cbiAgICByZXR1cm4ge1xuICAgICAgSW1wb3J0RGVjbGFyYXRpb24gKG5vZGU6IEpzTm9kZSkge1xuICAgICAgICBjb25zdCBzdHlsZUltcG9ydE5vZGVEYXRhID0gZ2V0U3R5bGVJbXBvcnROb2RlRGF0YShub2RlKTtcblxuICAgICAgICBpZiAoIXN0eWxlSW1wb3J0Tm9kZURhdGEpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgaW1wb3J0TmFtZSxcbiAgICAgICAgICBzdHlsZUZpbGVQYXRoLFxuICAgICAgICAgIGltcG9ydE5vZGUsXG4gICAgICAgIH0gPSBzdHlsZUltcG9ydE5vZGVEYXRhO1xuXG4gICAgICAgIGNvbnN0IHN0eWxlRmlsZUFic29sdXRlUGF0aCA9IGdldEZpbGVQYXRoKGNvbnRleHQsIHN0eWxlRmlsZVBhdGgpO1xuICAgICAgICBsZXQgY2xhc3Nlc01hcCA9IHt9O1xuICAgICAgICBsZXQgZXhwb3J0UHJvcHNNYXAgPSB7fTtcblxuICAgICAgICBpZiAoZmlsZUV4aXN0cyhzdHlsZUZpbGVBYnNvbHV0ZVBhdGgpKSB7XG4gICAgICAgICAgY29uc3QgYXN0ID0gZ2V0QVNUKHN0eWxlRmlsZUFic29sdXRlUGF0aCk7XG4gICAgICAgICAgY29uc3QgY2xhc3NlcyA9IGFzdCAmJiBnZXRTdHlsZUNsYXNzZXMoYXN0KTtcblxuICAgICAgICAgIGNsYXNzZXNNYXAgPSBjbGFzc2VzICYmIGdldENsYXNzZXNNYXAoY2xhc3NlcywgY2FtZWxDYXNlKTtcbiAgICAgICAgICBleHBvcnRQcm9wc01hcCA9IGFzdCAmJiBnZXRFeHBvcnRQcm9wc01hcChhc3QpO1xuICAgICAgICB9XG5cbiAgICAgICAgbWFwW2ltcG9ydE5hbWVdID8/PSB7fTtcblxuICAgICAgICAvLyB0aGlzIHdpbGwgYmUgdXNlZCB0byBjaGVjayBpZiBjbGFzc2VzIGFyZSBkZWZpbmVkXG4gICAgICAgIG1hcFtpbXBvcnROYW1lXS5jbGFzc2VzTWFwID0gY2xhc3Nlc01hcDtcblxuICAgICAgICAvLyB0aGlzIHdpbGwgYmUgdXNlZCB0byBjaGVjayBpZiA6ZXhwb3J0IHByb3BlcnRpZXMgYXJlIGRlZmluZWRcbiAgICAgICAgbWFwW2ltcG9ydE5hbWVdLmV4cG9ydFByb3BzTWFwID0gZXhwb3J0UHJvcHNNYXA7XG5cbiAgICAgICAgLy8gc2F2ZSBub2RlIGZvciByZXBvcnRpbmcgdW51c2VkIHN0eWxlc1xuICAgICAgICBtYXBbaW1wb3J0TmFtZV0ubm9kZSA9IGltcG9ydE5vZGU7XG4gICAgICB9LFxuICAgICAgTWVtYmVyRXhwcmVzc2lvbjogKG5vZGU6IEpzTm9kZSkgPT4ge1xuICAgICAgICAvKlxuICAgICAgICAgICBDaGVjayBpZiBwcm9wZXJ0eSBleGlzdHMgaW4gY3NzL3Njc3MgZmlsZSBhcyBjbGFzc1xuICAgICAgICAgKi9cblxuICAgICAgICBjb25zdCBvYmplY3ROYW1lID0gbm9kZS5vYmplY3QubmFtZTtcblxuICAgICAgICBjb25zdCBwcm9wZXJ0eU5hbWUgPSBnZXRQcm9wZXJ0eU5hbWUobm9kZSwgY2FtZWxDYXNlKTtcblxuICAgICAgICBpZiAoIXByb3BlcnR5TmFtZSkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGNsYXNzZXNNYXAgPSBtYXBbb2JqZWN0TmFtZV0/LmNsYXNzZXNNYXA7XG4gICAgICAgIGNvbnN0IGV4cG9ydFByb3BzTWFwID0gbWFwW29iamVjdE5hbWVdPy5leHBvcnRQcm9wc01hcDtcblxuICAgICAgICBpZiAoY2xhc3Nlc01hcCAmJiBjbGFzc2VzTWFwW3Byb3BlcnR5TmFtZV0gPT0gbnVsbCAmJlxuICAgICAgICAgICAgZXhwb3J0UHJvcHNNYXAgJiYgZXhwb3J0UHJvcHNNYXBbcHJvcGVydHlOYW1lXSA9PSBudWxsKSB7XG4gICAgICAgICAgY29udGV4dC5yZXBvcnQobm9kZS5wcm9wZXJ0eSwgYENsYXNzIG9yIGV4cG9ydGVkIHByb3BlcnR5ICcke3Byb3BlcnR5TmFt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
@@ -0,0 +1,132 @@
1
+ import path from 'node:path';
2
+ import { getStyleImportNodeData, getStyleClasses, getPropertyName, getClassesMap, getFilePath, getAST, fileExists } from '../core/index.js';
3
+ export default {
4
+ meta: {
5
+ docs: {
6
+ description: 'Checks that you are using all css/scss/less classes',
7
+ recommended: true
8
+ },
9
+ schema: [{
10
+ type: 'object',
11
+ properties: {
12
+ camelCase: {
13
+ enum: [true, 'dashes', 'only', 'dashes-only']
14
+ },
15
+ markAsUsed: {
16
+ type: 'array'
17
+ }
18
+ }
19
+ }]
20
+ },
21
+ create(context) {
22
+ const markAsUsed = context?.options?.[0]?.markAsUsed;
23
+ const camelCase = context?.options?.[0]?.camelCase;
24
+
25
+ /*
26
+ maps variable name to property Object
27
+ map = {
28
+ [variableName]: {
29
+ classes: { foo: false, 'foo-bar': false },
30
+ classesMap: { foo: 'foo', fooBar: 'foo-bar', 'foo-bar': 'foo-bar' },
31
+ node: {...}
32
+ }
33
+ }
34
+ example:
35
+ import s from './foo.scss';
36
+ s is variable name
37
+ property Object has two keys
38
+ 1. classes: an object with className as key and a boolean as value. The boolean is marked if it is used in file
39
+ 2. classesMap: an object with propertyName as key and its className as value
40
+ 3. node: node that correspond to s (see example above)
41
+ */
42
+ const map = {};
43
+ return {
44
+ ImportDeclaration(node) {
45
+ const styleImportNodeData = getStyleImportNodeData(node);
46
+ if (!styleImportNodeData) {
47
+ return;
48
+ }
49
+ const {
50
+ importName,
51
+ styleFilePath,
52
+ importNode
53
+ } = styleImportNodeData;
54
+ const styleFileAbsolutePath = getFilePath(context, styleFilePath);
55
+ let classes = {};
56
+ let classesMap = {};
57
+ if (fileExists(styleFileAbsolutePath)) {
58
+ // this will be used to mark s.foo as used in MemberExpression
59
+ const ast = getAST(styleFileAbsolutePath);
60
+ classes = ast && getStyleClasses(ast);
61
+ classesMap = classes && getClassesMap(classes, camelCase);
62
+ }
63
+ map[importName] ??= {};
64
+ map[importName].classes = classes;
65
+ map[importName].classesMap = classesMap;
66
+
67
+ // save node for reporting unused styles
68
+ map[importName].node = importNode;
69
+
70
+ // save file path for reporting unused styles
71
+ map[importName].filePath = styleFilePath;
72
+ },
73
+ MemberExpression: node => {
74
+ /*
75
+ Check if property exists in css/scss file as class
76
+ */
77
+
78
+ const objectName = node.object.name;
79
+ const propertyName = getPropertyName(node, camelCase);
80
+ if (!propertyName) {
81
+ return;
82
+ }
83
+ const className = map[objectName]?.classesMap?.[propertyName];
84
+ if (className == null) {
85
+ return;
86
+ }
87
+
88
+ // mark this property has used
89
+ (map[objectName] ??= {
90
+ classes: {}
91
+ }).classes[className] = true;
92
+ },
93
+ 'Program:exit'() {
94
+ /*
95
+ Check if all classes defined in css/scss file are used
96
+ */
97
+
98
+ /*
99
+ we are looping over each import style node in program
100
+ example:
101
+ ```
102
+ import s from './foo.css';
103
+ import x from './bar.scss';
104
+ ```
105
+ then the loop will be run 2 times
106
+ */
107
+ for (const o of Object.values(map)) {
108
+ const {
109
+ classes,
110
+ node,
111
+ filePath
112
+ } = o;
113
+
114
+ /*
115
+ if option is passed to mark a class as used, example:
116
+ eslint css-modules/no-unused-class: [2, { markAsUsed: ['container'] }]
117
+ */
118
+ for (const usedClass of markAsUsed ?? []) {
119
+ classes[usedClass] = true;
120
+ }
121
+
122
+ // classNames not marked as true are unused
123
+ const unusedClasses = classes ? Object.entries(classes).filter(([_k, v]) => !v).map(([k, _v]) => k) : [];
124
+ if (unusedClasses.length > 0) {
125
+ context.report(node, `Unused classes found in ${path.basename(filePath)}: ${unusedClasses.join(', ')}`);
126
+ }
127
+ }
128
+ }
129
+ };
130
+ }
131
+ };
132
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJwYXRoIiwiZ2V0U3R5bGVJbXBvcnROb2RlRGF0YSIsImdldFN0eWxlQ2xhc3NlcyIsImdldFByb3BlcnR5TmFtZSIsImdldENsYXNzZXNNYXAiLCJnZXRGaWxlUGF0aCIsImdldEFTVCIsImZpbGVFeGlzdHMiLCJtZXRhIiwiZG9jcyIsImRlc2NyaXB0aW9uIiwicmVjb21tZW5kZWQiLCJzY2hlbWEiLCJ0eXBlIiwicHJvcGVydGllcyIsImNhbWVsQ2FzZSIsImVudW0iLCJtYXJrQXNVc2VkIiwiY3JlYXRlIiwiY29udGV4dCIsIm9wdGlvbnMiLCJtYXAiLCJJbXBvcnREZWNsYXJhdGlvbiIsIm5vZGUiLCJzdHlsZUltcG9ydE5vZGVEYXRhIiwiaW1wb3J0TmFtZSIsInN0eWxlRmlsZVBhdGgiLCJpbXBvcnROb2RlIiwic3R5bGVGaWxlQWJzb2x1dGVQYXRoIiwiY2xhc3NlcyIsImNsYXNzZXNNYXAiLCJhc3QiLCJmaWxlUGF0aCIsIk1lbWJlckV4cHJlc3Npb24iLCJvYmplY3ROYW1lIiwib2JqZWN0IiwibmFtZSIsInByb3BlcnR5TmFtZSIsImNsYXNzTmFtZSIsIlByb2dyYW06ZXhpdCIsIm8iLCJPYmplY3QiLCJ2YWx1ZXMiLCJ1c2VkQ2xhc3MiLCJ1bnVzZWRDbGFzc2VzIiwiZW50cmllcyIsImZpbHRlciIsIl9rIiwidiIsImsiLCJfdiIsImxlbmd0aCIsInJlcG9ydCIsImJhc2VuYW1lIiwiam9pbiJdLCJzb3VyY2VzIjpbIi4uLy4uL2xpYi9ydWxlcy9uby11bnVzZWQtY2xhc3MuanMiXSwic291cmNlc0NvbnRlbnQiOlsiLyogQGZsb3cgKi9cbmltcG9ydCBwYXRoIGZyb20gJ25vZGU6cGF0aCc7XG5cbmltcG9ydCB7XG4gIGdldFN0eWxlSW1wb3J0Tm9kZURhdGEsXG4gIGdldFN0eWxlQ2xhc3NlcyxcbiAgZ2V0UHJvcGVydHlOYW1lLFxuICBnZXRDbGFzc2VzTWFwLFxuICBnZXRGaWxlUGF0aCxcbiAgZ2V0QVNULFxuICBmaWxlRXhpc3RzLFxufSBmcm9tICcuLi9jb3JlL2luZGV4LmpzJztcblxuaW1wb3J0IHR5cGUgeyBKc05vZGUgfSBmcm9tICcuLi90eXBlcy9pbmRleC5qcyc7XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgbWV0YToge1xuICAgIGRvY3M6IHtcbiAgICAgIGRlc2NyaXB0aW9uOiAnQ2hlY2tzIHRoYXQgeW91IGFyZSB1c2luZyBhbGwgY3NzL3Njc3MvbGVzcyBjbGFzc2VzJyxcbiAgICAgIHJlY29tbWVuZGVkOiB0cnVlLFxuICAgIH0sXG4gICAgc2NoZW1hOiBbXG4gICAgICB7XG4gICAgICAgIHR5cGU6ICdvYmplY3QnLFxuICAgICAgICBwcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgY2FtZWxDYXNlOiB7IGVudW06IFt0cnVlLCAnZGFzaGVzJywgJ29ubHknLCAnZGFzaGVzLW9ubHknXSB9LFxuICAgICAgICAgIG1hcmtBc1VzZWQ6IHsgdHlwZTogJ2FycmF5JyB9LFxuICAgICAgICB9LFxuICAgICAgfVxuICAgIF0sXG4gIH0sXG4gIGNyZWF0ZSAoY29udGV4dDogT2JqZWN0KSB7XG4gICAgY29uc3QgbWFya0FzVXNlZCA9IGNvbnRleHQ/Lm9wdGlvbnM/LlswXT8ubWFya0FzVXNlZDtcbiAgICBjb25zdCBjYW1lbENhc2UgPSBjb250ZXh0Py5vcHRpb25zPy5bMF0/LmNhbWVsQ2FzZTtcblxuICAgIC8qXG4gICAgICAgbWFwcyB2YXJpYWJsZSBuYW1lIHRvIHByb3BlcnR5IE9iamVjdFxuICAgICAgIG1hcCA9IHtcbiAgICAgICAgIFt2YXJpYWJsZU5hbWVdOiB7XG4gICAgICAgICAgIGNsYXNzZXM6IHsgZm9vOiBmYWxzZSwgJ2Zvby1iYXInOiBmYWxzZSB9LFxuICAgICAgICAgICBjbGFzc2VzTWFwOiB7IGZvbzogJ2ZvbycsIGZvb0JhcjogJ2Zvby1iYXInLCAnZm9vLWJhcic6ICdmb28tYmFyJyB9LFxuICAgICAgICAgICBub2RlOiB7Li4ufVxuICAgICAgICAgfVxuICAgICAgIH1cblxuICAgICAgIGV4YW1wbGU6XG4gICAgICAgaW1wb3J0IHMgZnJvbSAnLi9mb28uc2Nzcyc7XG4gICAgICAgcyBpcyB2YXJpYWJsZSBuYW1lXG5cbiAgICAgICBwcm9wZXJ0eSBPYmplY3QgaGFzIHR3byBrZXlzXG4gICAgICAgMS4gY2xhc3NlczogYW4gb2JqZWN0IHdpdGggY2xhc3NOYW1lIGFzIGtleSBhbmQgYSBib29sZWFuIGFzIHZhbHVlLiBUaGUgYm9vbGVhbiBpcyBtYXJrZWQgaWYgaXQgaXMgdXNlZCBpbiBmaWxlXG4gICAgICAgMi4gY2xhc3Nlc01hcDogYW4gb2JqZWN0IHdpdGggcHJvcGVydHlOYW1lIGFzIGtleSBhbmQgaXRzIGNsYXNzTmFtZSBhcyB2YWx1ZVxuICAgICAgIDMuIG5vZGU6IG5vZGUgdGhhdCBjb3JyZXNwb25kIHRvIHMgKHNlZSBleGFtcGxlIGFib3ZlKVxuICAgICAqL1xuICAgIGNvbnN0IG1hcCA9IHt9O1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIEltcG9ydERlY2xhcmF0aW9uIChub2RlOiBKc05vZGUpIHtcbiAgICAgICAgY29uc3Qgc3R5bGVJbXBvcnROb2RlRGF0YSA9IGdldFN0eWxlSW1wb3J0Tm9kZURhdGEobm9kZSk7XG5cbiAgICAgICAgaWYgKCFzdHlsZUltcG9ydE5vZGVEYXRhKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIGltcG9ydE5hbWUsXG4gICAgICAgICAgc3R5bGVGaWxlUGF0aCxcbiAgICAgICAgICBpbXBvcnROb2RlLFxuICAgICAgICB9ID0gc3R5bGVJbXBvcnROb2RlRGF0YTtcblxuICAgICAgICBjb25zdCBzdHlsZUZpbGVBYnNvbHV0ZVBhdGggPSBnZXRGaWxlUGF0aChjb250ZXh0LCBzdHlsZUZpbGVQYXRoKTtcblxuICAgICAgICBsZXQgY2xhc3NlcyA9IHt9O1xuICAgICAgICBsZXQgY2xhc3Nlc01hcCA9IHt9O1xuXG4gICAgICAgIGlmIChmaWxlRXhpc3RzKHN0eWxlRmlsZUFic29sdXRlUGF0aCkpIHtcbiAgICAgICAgICAvLyB0aGlzIHdpbGwgYmUgdXNlZCB0byBtYXJrIHMuZm9vIGFzIHVzZWQgaW4gTWVtYmVyRXhwcmVzc2lvblxuICAgICAgICAgIGNvbnN0IGFzdCA9IGdldEFTVChzdHlsZUZpbGVBYnNvbHV0ZVBhdGgpO1xuICAgICAgICAgIGNsYXNzZXMgPSBhc3QgJiYgZ2V0U3R5bGVDbGFzc2VzKGFzdCk7XG4gICAgICAgICAgY2xhc3Nlc01hcCA9IGNsYXNzZXMgJiYgZ2V0Q2xhc3Nlc01hcChjbGFzc2VzLCBjYW1lbENhc2UpO1xuICAgICAgICB9XG5cbiAgICAgICAgbWFwW2ltcG9ydE5hbWVdID8/PSB7fTtcblxuICAgICAgICBtYXBbaW1wb3J0TmFtZV0uY2xhc3NlcyA9IGNsYXNzZXM7XG4gICAgICAgIG1hcFtpbXBvcnROYW1lXS5jbGFzc2VzTWFwID0gY2xhc3Nlc01hcDtcblxuICAgICAgICAvLyBzYXZlIG5vZGUgZm9yIHJlcG9ydGluZyB1bnVzZWQgc3R5bGVzXG4gICAgICAgIG1hcFtpbXBvcnROYW1lXS5ub2RlID0gaW1wb3J0Tm9kZTtcblxuICAgICAgICAvLyBzYXZlIGZpbGUgcGF0aCBmb3IgcmVwb3J0aW5nIHVudXNlZCBzdHlsZXNcbiAgICAgICAgbWFwW2ltcG9ydE5hbWVdLmZpbGVQYXRoID0gc3R5bGVGaWxlUGF0aDtcbiAgICAgIH0sXG4gICAgICBNZW1iZXJFeHByZXNzaW9uOiAobm9kZTogSnNOb2RlKSA9PiB7XG4gICAgICAgIC8qXG4gICAgICAgICAgIENoZWNrIGlmIHByb3BlcnR5IGV4aXN0cyBpbiBjc3Mvc2NzcyBmaWxlIGFzIGNsYXNzXG4gICAgICAgICAqL1xuXG4gICAgICAgIGNvbnN0IG9iamVjdE5hbWUgPSBub2RlLm9iamVjdC5uYW1lO1xuICAgICAgICBjb25zdCBwcm9wZXJ0eU5hbWUgPSBnZXRQcm9wZXJ0eU5hbWUobm9kZSwgY2FtZWxDYXNlKTtcblxuICAgICAgICBpZiAoIXByb3BlcnR5TmFtZSkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGNsYXNzTmFtZSA9IG1hcFtvYmplY3ROYW1lXT8uY2xhc3Nlc01hcD8uW3Byb3BlcnR5TmFtZV07XG5cbiAgICAgICAgaWYgKGNsYXNzTmFtZSA9PSBudWxsKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gbWFyayB0aGlzIHByb3BlcnR5IGhhcyB1c2VkXG4gICAgICAgIChtYXBbb2JqZWN0TmFtZV0gPz89IHsgY2xhc3Nlczoge30gfSkuY2xhc3Nlc1tjbGFzc05hbWVdID0gdHJ1ZTtcbiAgICAgIH0sXG4gICAgICAnUHJvZ3JhbTpleGl0JyAoKSB7XG4gICAgICAgIC8qXG4gICAgICAgICAgIENoZWNrIGlmIGFsbCBjbGFzc2VzIGRlZmluZWQgaW4gY3NzL3Njc3MgZmlsZSBhcmUgdXNlZFxuICAgICAgICAgKi9cblxuICAgICAgICAvKlxuICAgICAgICAgICB3ZSBhcmUgbG9vcGluZyBvdmVyIGVhY2ggaW1wb3J0IHN0eWxlIG5vZGUgaW4gcHJvZ3JhbVxuICAgICAgICAgICBleGFtcGxlOlxuICAgICAgICAgICBgYGBcbiAgICAgICAgICAgICBpbXBvcnQgcyBmcm9tICcuL2Zvby5jc3MnO1xuICAgICAgICAgICAgIGltcG9ydCB4IGZyb20gJy4vYmFyLnNjc3MnO1xuICAgICAgICAgICBgYGBcbiAgICAgICAgICAgdGhlbiB0aGUgbG9vcCB3aWxsIGJlIHJ1biAyIHRpbWVzXG4gICAgICAgICAqL1xuICAgICAgICBmb3IgKGNvbnN0IG8gb2YgT2JqZWN0LnZhbHVlcyhtYXApKSB7XG4gICAgICAgICAgY29uc3QgeyBjbGFzc2VzLCBub2RlLCBmaWxlUGF0aCB9ID0gbztcblxuICAgICAgICAgIC8qXG4gICAgICAgICAgICAgaWYgb3B0aW9uIGlzIHBhc3NlZCB0byBtYXJrIGEgY2xhc3MgYXMgdXNlZCwgZXhhbXBsZTpcbiAgICAgICAgICAgICBlc2xpbnQgY3NzLW1vZHVsZXMvbm8tdW51c2VkLWNsYXNzOiBbMiwgeyBtYXJrQXNVc2VkOiBbJ2NvbnRhaW5lciddIH1dXG4gICAgICAgICAgICovXG4gICAgICAgICAgZm9yIChjb25zdCB1c2VkQ2xhc3Mgb2YgbWFya0FzVXNlZCA/PyBbXSkge1xuICAgICAgICAgICAgY2xhc3Nlc1t1c2VkQ2xhc3NdID0gdHJ1ZTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBjbGFzc05hbWVzIG5vdCBtYXJrZWQgYXMgdHJ1ZSBhcmUgdW51c2VkXG4gICAgICAgICAgY29uc3QgdW51c2VkQ2xhc3NlcyA9IGNsYXNzZXMgPyBPYmplY3QuZW50cmllcyhjbGFzc2VzKS5maWx0ZXIoKFtfaywgdl0pID0+ICF2KS5tYXAoKFtrLCBfdl0pID0+IGspIDogW107XG5cbiAgICAgICAgICBpZiAodW51c2VkQ2xhc3Nlcy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBjb250ZXh0LnJlcG9ydChub2RlLCBgVW51c2VkIGNsYXNzZXMgZm91bmQgaW4gJHtwYXRoLmJhc2VuYW1lKGZpbGVQYXRoKX06ICR7dW51c2VkQ2xhc3Nlcy5qb2luKCcsICcpfWApO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG4gIH1cbn07XG4iXSwibWFwcGluZ3MiOiJBQUNBLE9BQU9BLElBQUksTUFBTSxXQUFXO0FBRTVCLFNBQ0VDLHNCQUFzQixFQUN0QkMsZUFBZSxFQUNmQyxlQUFlLEVBQ2ZDLGFBQWEsRUFDYkMsV0FBVyxFQUNYQyxNQUFNLEVBQ05DLFVBQVUsUUFDTCxrQkFBa0I7QUFJekIsZUFBZTtFQUNiQyxJQUFJLEVBQUU7SUFDSkMsSUFBSSxFQUFFO01BQ0pDLFdBQVcsRUFBRSxxREFBcUQ7TUFDbEVDLFdBQVcsRUFBRTtJQUNmLENBQUM7SUFDREMsTUFBTSxFQUFFLENBQ047TUFDRUMsSUFBSSxFQUFFLFFBQVE7TUFDZEMsVUFBVSxFQUFFO1FBQ1ZDLFNBQVMsRUFBRTtVQUFFQyxJQUFJLEVBQUUsQ0FBQyxJQUFJLEVBQUUsUUFBUSxF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
@@ -0,0 +1,2 @@
1
+
2
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vbGliL3R5cGVzL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8vIGpzIE5vZGVcbmV4cG9ydCB0eXBlIFBvc2l0aW9uID0ge1xuICBsaW5lOiBudW1iZXIsIC8vIDEgaW5kZXhlZFxuICBjb2x1bW46IG51bWJlciwgLy8gMCBpbmRleGVkXG59O1xuXG5leHBvcnQgdHlwZSBTb3VyY2VMb2NhdGlvbiA9IHtcbiAgc3RhcnQ6IFBvc2l0aW9uLFxuICBlbmQ6IFBvc2l0aW9uLFxuICBpZGVudGlmaWVyTmFtZT86IHN0cmluZyxcbn07XG5cbmV4cG9ydCB0eXBlIEpzTm9kZSA9IHtcbiAgdHlwZTogJ0ltcG9ydERlY2xhcmF0aW9uJyB8ICdJbXBvcnREZWZhdWx0U3BlY2lmaWVyJyxcbiAgc3RhcnQ6IG51bWJlcixcbiAgZW5kOiBudW1iZXIsXG4gIGxvYzogSnNOb2RlLFxuICBsb2NhbD86IEpzTm9kZSxcbiAgbmFtZT86IHN0cmluZyxcbiAgdmFsdWU/OiBzdHJpbmcsXG4gIHNwZWNpZmllcnM/OiBBcnJheTxKc05vZGU+LFxuICBpbXBvcnRLaW5kPzogJ3ZhbHVlJyxcbiAgZXh0cmE/OiB7XG4gICAgcmF3VmFsdWU6IHN0cmluZyxcbiAgICByYXc6IHN0cmluZyxcbiAgfSxcbiAgc291cmNlOiBKc05vZGUsXG4gIHJhbmdlOiBBcnJheTxudW1iZXI+LCAvLyBtb3N0IHByb2JhYmx5IGFycmF5IG9mIDIgbnVtYmVycyA/LFxuICBfYmFiZWxUeXBlOiBzdHJpbmcsXG4gIHBhcmVudDogSnNOb2RlLFxufTtcblxuLy8gZ29uemFsZXMgQVNUIE5vZGUgVHlwZVxuZXhwb3J0IHR5cGUgZ0FTVE5vZGUgPSB7XG4gIHRyYXZlcnNlQnlUeXBlOiBGdW5jdGlvbixcblxuICB0eXBlOiAnc3R5bGVzaGVldCdcbiAgICAgIHwgJ2lkZW50J1xuICAgICAgfCAnY2xhc3MnXG4gICAgICB8ICdzZWxlY3RvcidcbiAgICAgIHwgJ3ZhbHVlJ1xuICAgICAgfCAncHJvcGVydHknXG4gICAgICB8ICdydWxlc2V0J1xuICAgICAgfCAnZXh0ZW5kJ1xuICAgICAgfCAnZGVjbGFyYXRpb24nLFxuICBjb250ZW50OiBzdHJpbmcgfCBBcnJheTxnQVNUTm9kZT4sXG4gIHN5bnRheDogJ2NzcycgfCAnc2NzcycgfCAnbGVzcycsXG59O1xuIl0sIm1hcHBpbmdzIjoiIn0=
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@bhollis/eslint-plugin-css-modules",
3
+ "version": "1.0.0",
4
+ "description": "Checks that you are using the existent css/scss/less classes, no more no less",
5
+ "main": "build/index.js",
6
+ "files": [
7
+ "build",
8
+ "packages"
9
+ ],
10
+ "type": "module",
11
+ "scripts": {
12
+ "watch": "babel lib -d build --watch",
13
+ "build": "rm -rf build && babel lib -d build",
14
+ "lint": "eslint lib test",
15
+ "test": "npm run build && rm -rf test-out && babel test -d test-out && cp -r test/files test-out/ && node --test test-out/**/*.test.js",
16
+ "my-pre-publish": "npm run test && npm run build",
17
+ "my-publish": "npm run my-pre-publish && yarn publish"
18
+ },
19
+ "engines": {
20
+ "node": ">=20.0.0"
21
+ },
22
+ "keywords": [
23
+ "eslint",
24
+ "eslintplugin",
25
+ "eslint-plugin",
26
+ "css-modules"
27
+ ],
28
+ "author": {
29
+ "name": "Atif Afzal",
30
+ "email": "atif5801@gmail.com",
31
+ "url": "http://atfzl.me"
32
+ },
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git://github.com/bhollis/eslint-plugin-css-modules.git"
36
+ },
37
+ "license": "MIT",
38
+ "bugs": {
39
+ "url": "https://github.com/bhollis/eslint-plugin-css-modules/issues"
40
+ },
41
+ "homepage": "https://github.com/bhollis/eslint-plugin-css-modules#readme",
42
+ "peerDependencies": {
43
+ "eslint": ">=2.0.0"
44
+ },
45
+ "devDependencies": {
46
+ "@babel/cli": "^7.23.0",
47
+ "@babel/core": "^7.23.0",
48
+ "@babel/eslint-parser": "^7.22.15",
49
+ "@babel/plugin-proposal-export-default-from": "^7.22.17",
50
+ "@babel/plugin-syntax-flow": "^7.22.5",
51
+ "@babel/plugin-transform-flow-strip-types": "^7.22.5",
52
+ "@babel/preset-env": "^7.22.20",
53
+ "@babel/register": "^7.22.15",
54
+ "eslint": "^8.50.0",
55
+ "eslint-config-standard": "^17.1.0",
56
+ "eslint-plugin-import": "^2.28.1",
57
+ "eslint-plugin-n": "^16.1.0",
58
+ "eslint-plugin-promise": "^6.1.1",
59
+ "flow-bin": "^0.36.0",
60
+ "nodemon": "^3.0.1"
61
+ },
62
+ "dependencies": {
63
+ "es-toolkit": "^1.42.0",
64
+ "gonzales-pe": "^4.3.0"
65
+ }
66
+ }