From 6afaf50336459860d8b0bfaa438c017392663076 Mon Sep 17 00:00:00 2001 From: Alexander Madyankin Date: Fri, 4 Nov 2022 11:17:32 +0300 Subject: [PATCH] Drop the old `resolve` option's implementation --- CHANGELOG.md | 32 ++++++ README.md | 144 ++++++++++++++------------ index.d.ts | 4 +- src/index.js | 56 ++++------ test/__snapshots__/test.js.snap | 47 +++------ test/fixtures/in/deepCompose.css.json | 1 + test/test.js | 52 +--------- 7 files changed, 146 insertions(+), 190 deletions(-) create mode 100644 test/fixtures/in/deepCompose.css.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 20e57a4..170f821 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,37 @@ # Changelog +## 6.0.0 + +### Breaking +The `resolve` option has two parameters now and can return `null`. Thanks to Rene Haas (@KingSora) +https://github.com/madyankin/postcss-modules/commit/86d8135cb5014d0b2848ef395608ee74d82bd179 + +Parameters: +- `file` — a module we want to resolve +- `importer` — the file that imports the module we want to resolve + +Return value: `string | null | Promise` + +```js +postcss([ + require("postcss-modules")({ + resolve: function (file, importer) { + return path.resolve( + path.dirname(importer), + file.replace(/^@/, process.cwd() + ); + }, + }), +]); +``` + +### Fixed +- #140 "'Failed to obtain root' error on Windows" fixed by Pierre LeMoine (@DrInfiniteExplorer) https://github.com/madyankin/postcss-modules/pull/144 + +## Improved +- `icss-replace-symbols` replaced with with `icss-utils` by Jason Quense (@jquense). The updated replacer works better and will replace values in selectors, which didn't work until now. https://github.com/madyankin/postcss-modules/pull/145 + + ## 5.0.0 - Fixed `composes` on Windows by @sapphi-red https://github.com/madyankin/postcss-modules/pull/135 diff --git a/README.md b/README.md index 02dbf4b..cb55dad 100644 --- a/README.md +++ b/README.md @@ -12,26 +12,26 @@ For example, you have the following CSS: ```css /* styles.css */ :global .page { - padding: 20px; + padding: 20px; } .title { - composes: title from "./mixins.css"; - color: green; + composes: title from "./mixins.css"; + color: green; } .article { - font-size: 16px; + font-size: 16px; } /* mixins.css */ .title { - color: black; - font-size: 40px; + color: black; + font-size: 40px; } .title:hover { - color: red; + color: red; } ``` @@ -39,24 +39,24 @@ After the transformation it will become like this: ```css ._title_116zl_1 { - color: black; - font-size: 40px; + color: black; + font-size: 40px; } ._title_116zl_1:hover { - color: red; + color: red; } .page { - padding: 20px; + padding: 20px; } ._title_xkpkl_5 { - color: green; + color: green; } ._article_xkpkl_10 { - font-size: 16px; + font-size: 16px; } ``` @@ -64,8 +64,8 @@ And the plugin will give you a JSON object for transformed classes: ```json { - "title": "_title_xkpkl_5 _title_116zl_1", - "article": "_article_xkpkl_10" + "title": "_title_xkpkl_5 _title_116zl_1", + "article": "_article_xkpkl_10" } ``` @@ -79,14 +79,14 @@ use the `getJSON` callback. For example, save data about classes into a correspo ```js postcss([ - require("postcss-modules")({ - getJSON: function (cssFileName, json, outputFileName) { - var path = require("path"); - var cssName = path.basename(cssFileName, ".css"); - var jsonFileName = path.resolve("./build/" + cssName + ".json"); - fs.writeFileSync(jsonFileName, JSON.stringify(json)); - }, - }), + require("postcss-modules")({ + getJSON: function (cssFileName, json, outputFileName) { + var path = require("path"); + var cssName = path.basename(cssFileName, ".css"); + var jsonFileName = path.resolve("./build/" + cssName + ".json"); + fs.writeFileSync(jsonFileName, JSON.stringify(json)); + }, + }), ]); ``` @@ -99,9 +99,9 @@ this behaviour using the `scopeBehaviour` option: ```js postcss([ - require("postcss-modules")({ - scopeBehaviour: "global", // can be 'global' or 'local', - }), + require("postcss-modules")({ + scopeBehaviour: "global", // can be 'global' or 'local', + }), ]); ``` @@ -120,16 +120,16 @@ To generate custom classes, use the `generateScopedName` callback: ```js postcss([ - require("postcss-modules")({ - generateScopedName: function (name, filename, css) { - var path = require("path"); - var i = css.indexOf("." + name); - var line = css.substr(0, i).split(/[\r\n]/).length; - var file = path.basename(filename, ".css"); - - return "_" + file + "_" + line + "_" + name; - }, - }), + require("postcss-modules")({ + generateScopedName: function (name, filename, css) { + var path = require("path"); + var i = css.indexOf("." + name); + var line = css.substr(0, i).split(/[\r\n]/).length; + var file = path.basename(filename, ".css"); + + return "_" + file + "_" + line + "_" + name; + }, + }), ]); ``` @@ -138,9 +138,9 @@ Or just pass an interpolated string to the `generateScopedName` option ```js postcss([ - require("postcss-modules")({ - generateScopedName: "[name]__[local]___[hash:base64:5]", - }), + require("postcss-modules")({ + generateScopedName: "[name]__[local]___[hash:base64:5]", + }), ]); ``` @@ -148,10 +148,10 @@ It's possible to add custom hash to generate more unique classes using the `hash ```js postcss([ - require("postcss-modules")({ - generateScopedName: "[name]__[local]___[hash:base64:5]", - hashPrefix: "prefix", - }), + require("postcss-modules")({ + generateScopedName: "[name]__[local]___[hash:base64:5]", + hashPrefix: "prefix", + }), ]); ``` @@ -161,9 +161,9 @@ If you need to export global names via the JSON object along with the local ones ```js postcss([ - require("postcss-modules")({ - exportGlobals: true, - }), + require("postcss-modules")({ + exportGlobals: true, + }), ]); ``` @@ -173,9 +173,9 @@ If you need, you can pass a custom loader (see [FileSystemLoader] for example): ```js postcss([ - require("postcss-modules")({ - Loader: CustomLoader, - }), + require("postcss-modules")({ + Loader: CustomLoader, + }), ]); ``` @@ -207,22 +207,28 @@ In lieu of a string, a custom function can generate the exported class names. ### Resolve path alias -You can rewrite paths for `composes/from` by using `resolve` options. +You can rewrite paths for `composes/from` by using the `resolve` option. It's useful when you need to resolve custom path alias. +Parameters: +- `file` — a module we want to resolve +- `importer` — the file that imports the module we want to resolve + +Return value: `string | null | Promise` + ```js postcss([ - require("postcss-modules")({ - resolve: function (file) { - return file.replace(/^@/, process.cwd()); - }, - }), + require("postcss-modules")({ + resolve: function (file, importer) { + return path.resolve( + path.dirname(importer), + file.replace(/^@/, process.cwd() + ); + }, + }), ]); ``` -`resolve` may also return a `Promise`. - - ## Integration with templates The plugin only transforms CSS classes to CSS modules. @@ -233,8 +239,8 @@ Assume you've saved project's CSS modules in `cssModules.json`: ```json { - "title": "_title_xkpkl_5 _title_116zl_1", - "article": "_article_xkpkl_10" + "title": "_title_xkpkl_5 _title_116zl_1", + "article": "_article_xkpkl_10" } ``` @@ -261,7 +267,7 @@ And you'll get the following HTML: ```html

postcss-modules

- A PostCSS plugin to use CSS Modules everywhere + A PostCSS plugin to use CSS Modules everywhere
``` @@ -278,7 +284,7 @@ Here is our template `about.html`: ```html

postcss-modules

- A PostCSS plugin to use CSS Modules everywhere + A PostCSS plugin to use CSS Modules everywhere
``` @@ -291,10 +297,10 @@ var posthtmlCssModules = require("posthtml-css-modules"); var template = fs.readFileSync("./about.html", "utf8"); posthtml([posthtmlCssModules("./cssModules.json")]) - .process(template) - .then(function (result) { - console.log(result.html); - }); + .process(template) + .then(function (result) { + console.log(result.html); + }); ``` (for using other build systems please check [the documentation of PostHTML](https://github.com/posthtml/posthtml/blob/master/readme.md)) @@ -304,7 +310,7 @@ And you'll get the following HTML: ```html

postcss-modules

- A PostCSS plugin to use CSS Modules everywhere + A PostCSS plugin to use CSS Modules everywhere
``` @@ -320,6 +326,6 @@ npm install --save-dev postcss postcss-modules [filesystemloader]: https://github.com/css-modules/css-modules-loader-core/blob/master/src/file-system-loader.js - ## Sponsors -- Dmitry Olyenyov + +- Dmitry Olyenyov diff --git a/index.d.ts b/index.d.ts index 497dfd3..487ef66 100644 --- a/index.d.ts +++ b/index.d.ts @@ -49,9 +49,7 @@ declare interface Options { Loader?: typeof Loader; - resolve?: (file: string) => string | Promise; - - fileResolve?: ( + resolve?: ( file: string, importer: string ) => string | null | Promise; diff --git a/src/index.js b/src/index.js index fc9c65f..041a454 100644 --- a/src/index.js +++ b/src/index.js @@ -33,8 +33,8 @@ function getScopedNameGenerator(opts) { function getLoader(opts, plugins) { const root = typeof opts.root === "undefined" ? "/" : opts.root; return typeof opts.Loader === "function" - ? new opts.Loader(root, plugins, opts.fileResolve) - : new FileSystemLoader(root, plugins, opts.fileResolve); + ? new opts.Loader(root, plugins, opts.resolve) + : new FileSystemLoader(root, plugins, opts.resolve); } function isGlobalModule(globalModules, inputFile) { @@ -85,39 +85,23 @@ module.exports = (opts = {}) => { if (resultPluginIndex === -1) { throw new Error("Plugin missing from options."); } - // resolve and fileResolve can't be used together - if ( - typeof opts.resolve === "function" && - typeof opts.fileResolve == "function" - ) { - throw new Error( - 'Please use either the "resolve" or the "fileResolve" option.' - ); - } + const earlierPlugins = result.processor.plugins.slice( 0, resultPluginIndex ); const loaderPlugins = [...earlierPlugins, ...pluginList]; const loader = getLoader(opts, loaderPlugins); - const fetcher = (file, relativeTo, depTrace) => { + + const fetcher = async (file, relativeTo, depTrace) => { const unquoteFile = unquote(file); - const resolvedResult = - typeof opts.resolve === "function" && - opts.resolve(unquoteFile); - const resolvedFile = - resolvedResult instanceof Promise - ? resolvedResult - : Promise.resolve(resolvedResult); - - return resolvedFile.then((f) => { - return loader.fetch.call( - loader, - `"${f || unquoteFile}"`, - relativeTo, - depTrace - ); - }); + + return loader.fetch.call( + loader, + unquoteFile, + relativeTo, + depTrace + ); }; const parser = new Parser(fetcher); @@ -135,9 +119,12 @@ module.exports = (opts = {}) => { parser.exportTokens ).reduce((tokens, [className, value]) => { if (isFunc) { - tokens[ - opts.localsConvention(className, value, inputFile) - ] = value; + const convention = opts.localsConvention( + className, + value, + inputFile + ); + tokens[convention] = value; return tokens; } @@ -146,20 +133,19 @@ module.exports = (opts = {}) => { case "camelCase": tokens[className] = value; tokens[camelCase(className)] = value; - break; + case "camelCaseOnly": tokens[camelCase(className)] = value; - break; + case "dashes": tokens[className] = value; tokens[dashesCamelCase(className)] = value; - break; + case "dashesOnly": tokens[dashesCamelCase(className)] = value; - break; } diff --git a/test/__snapshots__/test.js.snap b/test/__snapshots__/test.js.snap index f1fe87b..017bd22 100644 --- a/test/__snapshots__/test.js.snap +++ b/test/__snapshots__/test.js.snap @@ -328,31 +328,6 @@ Object { } `; -exports[`processes fileResolve option: processes fileResolve option 1`] = ` -"._composes_a_another-mixin { - display: flex; - height: 100px; - width: 200px; -}._composes_a_hello { - foo: bar; -}._composes_mixins_title { - color: black; - font-size: 40px; -}._composes_mixins_title:hover { - color: red; -}._composes_mixins_figure { - text-align: center -}._composes_mixins_title:focus, ._composes_mixins_figure:focus { - outline: none; - border: 1px solid red; -}._deepDeepCompose_deepDeepCompose { -}._deepDeepCompose_dotSlashRelativePath { -}._deepCompose_deepCompose { - content: \\"deepCompose\\"; -} -" -`; - exports[`processes globalModulePaths option: processes globalModulePaths option 1`] = ` ".page { padding: 20px; @@ -373,14 +348,20 @@ exports[`processes resolve option: processes resolve option 1`] = ` width: 200px; }._composes_a_hello { foo: bar; -} - -._compose_resolve_figure { - display: flex; -} - -._compose_resolve_figure-single-quote { - display: block; +}._composes_mixins_title { + color: black; + font-size: 40px; +}._composes_mixins_title:hover { + color: red; +}._composes_mixins_figure { + text-align: center +}._composes_mixins_title:focus, ._composes_mixins_figure:focus { + outline: none; + border: 1px solid red; +}._deepDeepCompose_deepDeepCompose { +}._deepDeepCompose_dotSlashRelativePath { +}._deepCompose_deepCompose { + content: \\"deepCompose\\"; } " `; diff --git a/test/fixtures/in/deepCompose.css.json b/test/fixtures/in/deepCompose.css.json new file mode 100644 index 0000000..5a7d86a --- /dev/null +++ b/test/fixtures/in/deepCompose.css.json @@ -0,0 +1 @@ +{"deepCompose":"_deepCompose_deepCompose _deepDeepCompose_deepDeepCompose _composes_mixins_title"} \ No newline at end of file diff --git a/test/test.js b/test/test.js index bccb616..60fd741 100644 --- a/test/test.js +++ b/test/test.js @@ -411,40 +411,13 @@ it("processes exportGlobals option", async () => { }); it("processes resolve option", async () => { - const sourceFile = path.join(fixturesPath, "in", "compose.resolve.css"); - const source = fs.readFileSync(sourceFile).toString(); - let json; - const result = await postcss([ - plugin({ - generateScopedName, - resolve: async (file) => { - return file.replace( - /^test-fixture-in/, - path.dirname(sourceFile) - ); - }, - getJSON: (_, result) => { - json = result; - }, - }), - ]).process(source, { from: sourceFile }); - - expect(result.css).toMatchSnapshot("processes resolve option"); - expect(json).toStrictEqual({ - figure: "_compose_resolve_figure _composes_a_hello", - "figure-single-quote": - "_compose_resolve_figure-single-quote _composes_a_hello", - }); -}); - -it("processes fileResolve option", async () => { const sourceFile = path.join(fixturesPath, "in", "deepCompose.css"); const source = fs.readFileSync(sourceFile).toString(); let json; const result = await postcss([ plugin({ generateScopedName, - fileResolve: async (file, importer) => { + resolve: async (file, importer) => { return path.resolve( path.dirname(importer), file.replace(/^test-fixture-in/, path.dirname(sourceFile)) @@ -456,30 +429,9 @@ it("processes fileResolve option", async () => { }), ]).process(source, { from: sourceFile }); - expect(result.css).toMatchSnapshot("processes fileResolve option"); + expect(result.css).toMatchSnapshot("processes resolve option"); expect(json).toStrictEqual({ deepCompose: "_deepCompose_deepCompose _deepDeepCompose_deepDeepCompose _composes_mixins_title", }); }); - -it("processes fileResolve and resolve option", async () => { - const sourceFile = path.join(fixturesPath, "in", "deepCompose.css"); - const source = fs.readFileSync(sourceFile).toString(); - const result = await postcss([ - plugin({ - generateScopedName, - resolve: (file) => file, - fileResolve: async (file, importer) => { - return path.resolve( - path.dirname(importer), - file.replace(/^test-fixture-in/, path.dirname(sourceFile)) - ); - }, - }), - ]) - .process(source, { from: sourceFile }) - .catch((error) => error); - - expect(result instanceof Error).toBe(true); -});