diff --git a/package-lock.json b/package-lock.json index 99c47da..9ceab2d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "auto-changelog": "^2.2.1", "css-loader": "*", "css-loader3": "npm:css-loader@^3.1.0", + "css-loader6": "npm:css-loader@^6.11.0", "eslint": "8.32.0", "eslint-config-prettier": "^8.6.0", "jest": "^29.3.1", @@ -2729,31 +2730,73 @@ } }, "node_modules/css-loader": { - "version": "6.7.3", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz", - "integrity": "sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.1.tgz", + "integrity": "sha512-OxIR5P2mjO1PSXk44bWuQ8XtMK4dpEqpIyERCx3ewOo3I8EmbcxMPUc5ScLtQfgXtOojoMv57So4V/C02HQLsw==", "dev": true, "dependencies": { "icss-utils": "^5.1.0", - "postcss": "^8.4.19", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", - "postcss-modules-scope": "^3.0.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", "postcss-modules-values": "^4.0.0", "postcss-value-parser": "^4.2.0", - "semver": "^7.3.8" + "semver": "^7.5.4" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^5.0.0" + "@rspack/core": "0.x || 1.x", + "webpack": "^5.27.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } } }, + "node_modules/css-loader/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/css-loader/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/css-loader/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/css-loader3": { "name": "css-loader", "version": "3.6.0", @@ -2880,6 +2923,75 @@ "semver": "bin/semver.js" } }, + "node_modules/css-loader6": { + "name": "css-loader", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", + "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-loader6/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/css-loader6/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/css-loader6/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -6205,10 +6317,16 @@ "dev": true }, "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -6823,9 +6941,9 @@ } }, "node_modules/postcss": { - "version": "8.4.21", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", - "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", "dev": true, "funding": [ { @@ -6835,21 +6953,25 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "source-map-js": "^1.2.0" }, "engines": { "node": "^10 || ^12 || >=14" } }, "node_modules/postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", "dev": true, "engines": { "node": "^10 || ^12 || >= 14" @@ -6859,9 +6981,9 @@ } }, "node_modules/postcss-modules-local-by-default": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", - "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", + "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", "dev": true, "dependencies": { "icss-utils": "^5.0.0", @@ -6876,9 +6998,9 @@ } }, "node_modules/postcss-modules-scope": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", + "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", "dev": true, "dependencies": { "postcss-selector-parser": "^6.0.4" @@ -7854,9 +7976,9 @@ } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -11091,19 +11213,45 @@ } }, "css-loader": { - "version": "6.7.3", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz", - "integrity": "sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.1.tgz", + "integrity": "sha512-OxIR5P2mjO1PSXk44bWuQ8XtMK4dpEqpIyERCx3ewOo3I8EmbcxMPUc5ScLtQfgXtOojoMv57So4V/C02HQLsw==", "dev": true, "requires": { "icss-utils": "^5.1.0", - "postcss": "^8.4.19", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", - "postcss-modules-scope": "^3.0.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", "postcss-modules-values": "^4.0.0", "postcss-value-parser": "^4.2.0", - "semver": "^7.3.8" + "semver": "^7.5.4" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } } }, "css-loader3": { @@ -11201,6 +11349,48 @@ } } }, + "css-loader6": { + "version": "npm:css-loader@6.11.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", + "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", + "dev": true, + "requires": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, "cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -13615,9 +13805,9 @@ "dev": true }, "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true }, "natural-compare": { @@ -14038,27 +14228,27 @@ } }, "postcss": { - "version": "8.4.21", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", - "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", "dev": true, "requires": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "source-map-js": "^1.2.0" } }, "postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", "dev": true, "requires": {} }, "postcss-modules-local-by-default": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", - "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", + "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", "dev": true, "requires": { "icss-utils": "^5.0.0", @@ -14067,9 +14257,9 @@ } }, "postcss-modules-scope": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", + "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", "dev": true, "requires": { "postcss-selector-parser": "^6.0.4" @@ -14743,9 +14933,9 @@ "dev": true }, "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", "dev": true }, "source-map-support": { diff --git a/package.json b/package.json index a299a5b..2167e4d 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "@types/jest": "^29.2.6", "auto-changelog": "^2.2.1", "css-loader": "*", + "css-loader6": "npm:css-loader@^6.11.0", "css-loader3": "npm:css-loader@^3.1.0", "eslint": "8.32.0", "eslint-config-prettier": "^8.6.0", diff --git a/src/index.js b/src/index.js index 04b6b99..425f553 100644 --- a/src/index.js +++ b/src/index.js @@ -61,13 +61,7 @@ module.exports = function (content, ...args) { this.cacheable(); } - // let's only check `exports.locals` for keys to avoid getting keys from the sourcemap when it's enabled - // if we cannot find locals, then the module only contains global styles - const indexOfLocals = content.indexOf(".locals"); - const cssModuleKeys = - indexOfLocals === -1 - ? [] - : getCssModuleKeys(content.substring(indexOfLocals)); + const cssModuleKeys = getCssModuleKeys(content); /** @type {any} */ const callback = this.async(); diff --git a/src/utils.js b/src/utils.js index 8cc032c..1746459 100644 --- a/src/utils.js +++ b/src/utils.js @@ -7,6 +7,42 @@ const camelCase = require("camelcase"); * @returns {string[]} */ const getCssModuleKeys = (content) => { + const indexOfLocals = content.indexOf(".locals"); + if (indexOfLocals >= 0) { + // let's only check `exports.locals` for keys to avoid getting keys from the sourcemap when it's enabled + // if we cannot find locals, then the module only contains global styles + return getCssModuleKeysFromLocalsLiteral(content.substring(indexOfLocals)); + } else { + return getCssModuleKeysFromESMExports(content); + } +}; + +/** + * @param {string} content + * @returns {string[]} + */ +const getCssModuleKeysFromESMExports = (content) => { + // extract from either `export var foo = "..."` or `export { _1 as "foo-bar" }` + const keyRegex = + /export (?:(?:const|var|let) ([^ \n=]+)\s*=|\{ \w+ as "([^"\n]+)" \})/g; + let match; + const cssModuleKeys = []; + + while ((match = keyRegex.exec(content))) { + let exportName = match[1] || match[2]; + if (cssModuleKeys.indexOf(exportName) < 0) { + cssModuleKeys.push(exportName); + } + } + return cssModuleKeys; +}; + +/** + * @param {string} content + * @returns {string[]} + */ +const getCssModuleKeysFromLocalsLiteral = (content) => { + // extract from ` ___CSS_LOADER_EXPORT___.locals = { foo: "bar" }` const keyRegex = /"([^"\n]+)":/g; let match; const cssModuleKeys = []; diff --git a/test/__snapshots__/index.test.js.snap b/test/__snapshots__/index.test.js.snap index 010eb04..4a430cf 100644 --- a/test/__snapshots__/index.test.js.snap +++ b/test/__snapshots__/index.test.js.snap @@ -142,6 +142,148 @@ export = ExampleCssModule; " `; +exports[`css-loader@6 default options 1`] = ` +"declare namespace ExampleCssNamespace { + export interface IExampleCss { + "bar-baz": string; + composed: string; + foo: string; + } +} + +declare const ExampleCssModule: ExampleCssNamespace.IExampleCss & { + /** WARNING: Only available when \`css-loader\` is used without \`style-loader\` or \`mini-css-extract-plugin\` */ + locals: ExampleCssNamespace.IExampleCss; +}; + +export = ExampleCssModule; +" +`; + +exports[`css-loader@6 localsConvention asIs 1`] = ` +"declare namespace ExampleCssNamespace { + export interface IExampleCss { + "bar-baz": string; + composed: string; + foo: string; + } +} + +declare const ExampleCssModule: ExampleCssNamespace.IExampleCss & { + /** WARNING: Only available when \`css-loader\` is used without \`style-loader\` or \`mini-css-extract-plugin\` */ + locals: ExampleCssNamespace.IExampleCss; +}; + +export = ExampleCssModule; +" +`; + +exports[`css-loader@6 localsConvention camelCase 1`] = ` +"declare namespace ExampleCssNamespace { + export interface IExampleCss { + "bar-baz": string; + barBaz: string; + composed: string; + foo: string; + } +} + +declare const ExampleCssModule: ExampleCssNamespace.IExampleCss & { + /** WARNING: Only available when \`css-loader\` is used without \`style-loader\` or \`mini-css-extract-plugin\` */ + locals: ExampleCssNamespace.IExampleCss; +}; + +export = ExampleCssModule; +" +`; + +exports[`css-loader@6 with banner 1`] = ` +"// autogenerated by typings-for-css-modules-loader +declare namespace ExampleCssNamespace { + export interface IExampleCss { + "bar-baz": string; + composed: string; + foo: string; + } +} + +declare const ExampleCssModule: ExampleCssNamespace.IExampleCss & { + /** WARNING: Only available when \`css-loader\` is used without \`style-loader\` or \`mini-css-extract-plugin\` */ + locals: ExampleCssNamespace.IExampleCss; +}; + +export = ExampleCssModule; +" +`; + +exports[`css-loader@6 with locals export disabled 1`] = ` +"declare namespace ExampleCssNamespace { + export interface IExampleCss { + "bar-baz": string; + composed: string; + foo: string; + } +} + +declare const ExampleCssModule: ExampleCssNamespace.IExampleCss; + +export = ExampleCssModule; +" +`; + +exports[`css-loader@6 with no formatter 1`] = ` +"declare namespace ExampleCssNamespace { + export interface IExampleCss { + 'bar-baz': string; + 'composed': string; + 'foo': string; + } +} + +declare const ExampleCssModule: ExampleCssNamespace.IExampleCss & { + /** WARNING: Only available when \`css-loader\` is used without \`style-loader\` or \`mini-css-extract-plugin\` */ + locals: ExampleCssNamespace.IExampleCss; +}; + +export = ExampleCssModule;" +`; + +exports[`css-loader@6 with prettier 1`] = ` +"declare namespace ExampleCssNamespace { + export interface IExampleCss { + "bar-baz": string; + composed: string; + foo: string; + } +} + +declare const ExampleCssModule: ExampleCssNamespace.IExampleCss & { + /** WARNING: Only available when \`css-loader\` is used without \`style-loader\` or \`mini-css-extract-plugin\` */ + locals: ExampleCssNamespace.IExampleCss; +}; + +export = ExampleCssModule; +" +`; + +exports[`css-loader@6 with sourcemap 1`] = ` +"declare namespace ExampleCssNamespace { + export interface IExampleCss { + "bar-baz": string; + composed: string; + foo: string; + } +} + +declare const ExampleCssModule: ExampleCssNamespace.IExampleCss & { + /** WARNING: Only available when \`css-loader\` is used without \`style-loader\` or \`mini-css-extract-plugin\` */ + locals: ExampleCssNamespace.IExampleCss; +}; + +export = ExampleCssModule; +" +`; + exports[`css-loader@latest default options 1`] = ` "declare namespace ExampleCssNamespace { export interface IExampleCss { diff --git a/test/index.test.js b/test/index.test.js index 9d252ef..c3503e7 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -149,6 +149,146 @@ describe("css-loader@latest", () => { }); }); +describe("css-loader@6", () => { + const runTest = createTestRunner("css-loader6"); + + it("default options", async () => { + await runTest(); + + const persistMock = jest.requireMock("../src/persist"); + expect(persistMock).toBeCalledTimes(1); + expect(persistMock.mock.calls[0][1]).toMatchSnapshot(); + + const verifyMock = jest.requireMock("../src/verify"); + expect(verifyMock).toBeCalledTimes(0); + }); + + it("with sourcemap", async () => { + await runTest({ + cssLoaderOptions: { + sourceMap: true, + }, + }); + + const persistMock = jest.requireMock("../src/persist"); + expect(persistMock).toBeCalledTimes(1); + expect(persistMock.mock.calls[0][1]).toMatchSnapshot(); + }); + + it("no locals in output", async () => { + await runTest({ + fileName: "./example-no-locals.css", + cssLoaderOptions: { + sourceMap: true, + }, + }); + + const persistMock = jest.requireMock("../src/persist"); + expect(persistMock).toBeCalledTimes(0); + }); + + it("no modules", async () => { + await runTest({ + cssLoaderOptions: { + modules: false, + }, + }); + + const persistMock = jest.requireMock("../src/persist"); + expect(persistMock).toBeCalledTimes(0); + }); + + it("localsConvention asIs", async () => { + await runTest({ + cssLoaderOptions: { + modules: { + exportLocalsConvention: "asIs", + }, + }, + }); + + const persistMock = jest.requireMock("../src/persist"); + expect(persistMock).toBeCalledTimes(1); + expect(persistMock.mock.calls[0][1]).toMatchSnapshot(); + }); + + it("localsConvention camelCase", async () => { + await runTest({ + cssLoaderOptions: { + modules: { + exportLocalsConvention: "camelCase", + }, + }, + }); + + const persistMock = jest.requireMock("../src/persist"); + expect(persistMock).toBeCalledTimes(1); + expect(persistMock.mock.calls[0][1]).toMatchSnapshot(); + }); + + it("with prettier", async () => { + await runTest({ + options: { + formatter: "prettier", + }, + }); + + const persistMock = jest.requireMock("../src/persist"); + expect(persistMock).toBeCalledTimes(1); + expect(persistMock.mock.calls[0][1]).toMatchSnapshot(); + }); + + it("with no formatter", async () => { + await runTest({ + options: { + formatter: "none", + }, + }); + + const persistMock = jest.requireMock("../src/persist"); + expect(persistMock).toBeCalledTimes(1); + expect(persistMock.mock.calls[0][1]).toMatchSnapshot(); + }); + + it("with banner", async () => { + await runTest({ + options: { + banner: "// autogenerated by typings-for-css-modules-loader", + }, + }); + + const persistMock = jest.requireMock("../src/persist"); + expect(persistMock).toBeCalledTimes(1); + expect(persistMock.mock.calls[0][1]).toMatchSnapshot(); + }); + + it("with locals export disabled", async () => { + await runTest({ + options: { + disableLocalsExport: true, + }, + }); + + const persistMock = jest.requireMock("../src/persist"); + expect(persistMock).toBeCalledTimes(1); + expect(persistMock.mock.calls[0][1]).toMatchSnapshot(); + }); + + it("with verify only", async () => { + await runTest({ + options: { + verifyOnly: true, + }, + }); + + const persistMock = jest.requireMock("../src/persist"); + expect(persistMock).toBeCalledTimes(0); + + const verifyMock = jest.requireMock("../src/verify"); + expect(verifyMock).toBeCalledTimes(1); + }); +}); + describe("css-loader@3", () => { const runTest = createTestRunner("css-loader3"); diff --git a/test/utils.test.js b/test/utils.test.js index 2daa072..95aa5b9 100644 --- a/test/utils.test.js +++ b/test/utils.test.js @@ -34,7 +34,7 @@ describe("getCssModuleKeys", () => { expect(actual).toEqual([]); }); - it("CSS module with one class", () => { + it("CJS CSS module with one class", () => { const content = `exports.locals = { "test": "test" };`; @@ -42,7 +42,13 @@ describe("getCssModuleKeys", () => { expect(actual).toEqual(["test"]); }); - it("CSS module with multiple classes", () => { + it("ESM CSS module with one class", () => { + const content = `export var test = "test";`; + const actual = getCssModuleKeys(content); + expect(actual).toEqual(["test"]); + }); + + it("CJS CSS module with multiple classes", () => { const content = `exports.locals = { "test1": "test1", "test2": "test2" @@ -51,6 +57,15 @@ describe("getCssModuleKeys", () => { expect(actual).toEqual(["test1", "test2"]); }); + it("ESM CSS module with multiple classes", () => { + const content = ` + export var test1 = "test1"; + export var test2 = "test2"; + `; + const actual = getCssModuleKeys(content); + expect(actual).toEqual(["test1", "test2"]); + }); + it("CSS module with :root pseudo-class only", () => { const content = ` exports = module.exports = require("../node_modules/css-loader/dist/runtime/api.js")(false); @@ -61,7 +76,7 @@ describe("getCssModuleKeys", () => { expect(actual).toEqual([]); }); - it("CSS module with special class names", () => { + it("CJS CSS module with special class names", () => { const content = `.locals = { "øæå": "nordic", "+~@": "special", @@ -71,6 +86,19 @@ describe("getCssModuleKeys", () => { expect(actual).toEqual(["øæå", "+~@", "f\\'o\\'o"]); }); + it("ESM CSS module with special class names", () => { + const content = ` + var _1 = "nordic"; + export { _1 as "øæå" }; + var _2 = "special"; + export { _2 as "+~@" }; + var _3 = "escaped"; + export { _3 as "f\\'o\\'o" }; + };`; + const actual = getCssModuleKeys(content); + expect(actual).toEqual(["øæå", "+~@", "f\\'o\\'o"]); + }); + it("CSS module with newline in class names should be ignored", () => { const content = `.locals = { "line1