Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(#13): add custom lookup path option #126

Merged
merged 2 commits into from
Jul 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,24 @@ Style of exported classnames, the keys in your json.

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.
It's useful when you need to resolve custom path alias.

```js
postcss([
require("postcss-modules")({
resolve: function (file) {
return file.replace(/^@/, process.cwd());
},
}),
]);
```

`resolve` may also return a `Promise<string>`.


## Integration with templates

The plugin only transforms CSS classes to CSS modules.
Expand Down
2 changes: 2 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ declare interface Options {
root?: string;

Loader?: typeof Loader;

resolve?: (file: string) => string | Promise<string>;
}

declare interface PostcssModulesPlugin {
Expand Down
10 changes: 9 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,15 @@ module.exports = (opts = {}) => {
const earlierPlugins = result.processor.plugins.slice(0, resultPluginIndex);
const loaderPlugins = [...earlierPlugins, ...pluginList];
const loader = getLoader(opts, loaderPlugins);
const parser = new Parser(loader.fetch.bind(loader));
const fetcher = ((file, relativeTo, depTrace) => {
const resolvedResult = (typeof opts.resolve === 'function' && opts.resolve(file));
const resolvedFile = resolvedResult instanceof Promise ? resolvedResult : Promise.resolve(resolvedResult);

return resolvedFile.then((f = file) => {
return loader.fetch.call(loader, f || file, relativeTo, depTrace);
});
});
const parser = new Parser(fetcher);

await postcss([...pluginList, parser.plugin()]).process(css, {
from: inputFile,
Expand Down
13 changes: 13 additions & 0 deletions test/__snapshots__/test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,19 @@ exports[`processes globalModulePaths option: processes globalModulePaths option

exports[`processes hashPrefix option: processes hashPrefix option 1`] = `"._8xPWf {}"`;

exports[`processes resolve option: processes resolve option 1`] = `
"._composes_a_another-mixin {
display: flex;
height: 100px;
width: 200px;
}._composes_a_hello {
foo: bar;
}._compose_resolve_figure {
display: flex;
}
"
`;

exports[`processes values: processes values - CSS 1`] = `
"

Expand Down
4 changes: 4 additions & 0 deletions test/fixtures/in/compose.resolve.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.figure {
composes: hello from "test-fixture-in/composes.a.css";
display: flex;
}
82 changes: 53 additions & 29 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ const fixturesPath = path.resolve(__dirname, "./fixtures");
function createPlugin(name, processor) {
const plugin = () => ({
postcssPlugin: name,
Once: processor
})
plugin.postcss = true
return plugin
Once: processor,
});
plugin.postcss = true;
return plugin;
}

const cases = {
Expand Down Expand Up @@ -74,33 +74,35 @@ Object.keys(cases).forEach((name) => {

const plugins = [
autoprefixer,
createPlugin(
'validator-1',
(root) => {
if (rootsSeenBeforePlugin.has(root)) {
throw new Error('Plugin before ours was called multiple times.')
}
rootsSeenBeforePlugin.add(root);
root.prepend(`/* validator-1-start (${path.basename(root.source.input.file)}) */`);
root.append(`/* validator-1-end (${path.basename(root.source.input.file)}) */`);
createPlugin("validator-1", (root) => {
if (rootsSeenBeforePlugin.has(root)) {
throw new Error("Plugin before ours was called multiple times.");
}
),
rootsSeenBeforePlugin.add(root);
root.prepend(
`/* validator-1-start (${path.basename(root.source.input.file)}) */`
);
root.append(
`/* validator-1-end (${path.basename(root.source.input.file)}) */`
);
}),
plugin({
scopeBehaviour,
generateScopedName: scopedNameGenerator,
getJSON: () => {},
}),
createPlugin(
'validator-2',
(root) => {
if (rootsSeenAfterPlugin.has(root)) {
throw new Error('Plugin after ours was called multiple times.')
}
rootsSeenAfterPlugin.add(root);
root.prepend(`/* validator-2-start (${path.basename(root.source.input.file)}) */`);
root.append(`/* validator-2-end (${path.basename(root.source.input.file)}) */`);
createPlugin("validator-2", (root) => {
if (rootsSeenAfterPlugin.has(root)) {
throw new Error("Plugin after ours was called multiple times.");
}
),
rootsSeenAfterPlugin.add(root);
root.prepend(
`/* validator-2-start (${path.basename(root.source.input.file)}) */`
);
root.append(
`/* validator-2-end (${path.basename(root.source.input.file)}) */`
);
}),
];

const result = await postcss(plugins).process(source, { from: sourceFile });
Expand Down Expand Up @@ -252,7 +254,6 @@ it("processes localsConvention with dashes option", async () => {
});
});


it("processes localsConvention with function option", async () => {
const sourceFile = path.join(fixturesPath, "in", "camelCase.css");
const source = fs.readFileSync(sourceFile).toString();
Expand All @@ -261,17 +262,20 @@ it("processes localsConvention with function option", async () => {
if (fs.existsSync(jsonFile)) fs.unlinkSync(jsonFile);

await postcss([
plugin({ generateScopedName, localsConvention: (className) => {
return className.replace('camel-case', 'cc');
} }),
plugin({
generateScopedName,
localsConvention: (className) => {
return className.replace("camel-case", "cc");
},
}),
]).process(source, { from: sourceFile });

const json = fs.readFileSync(jsonFile).toString();
fs.unlinkSync(jsonFile);

expect(JSON.parse(json)).toMatchObject({
cc: "_camelCase_camel-case",
'cc-extra': "_camelCase_camel-case-extra",
"cc-extra": "_camelCase_camel-case-extra",
FooBar: "_camelCase_FooBar",
});
});
Expand Down Expand Up @@ -383,3 +387,23 @@ it("processes exportGlobals option", async () => {
article: "_classes_article",
});
});

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).toMatchObject({"figure": "_compose_resolve_figure _composes_a_hello"});
});