Skip to content

Commit

Permalink
Allow preprocessing of value declarations (#30)
Browse files Browse the repository at this point in the history
* Added support for css-loader ~ syntax of module imports

* Add config, remove plugins after current.

* Update readme

* Revert breaking url resolution change

* Add importsAsModuleRequests option

Co-authored-by: Shipov Mikhail <mshipov@yandex.ru>
  • Loading branch information
ackwell and SkReD committed Mar 2, 2021
1 parent 198b0d4 commit abb832c
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 5 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
[postcss-calc]: https://github.com/postcss/postcss-calc
[postcss-cssnext]: https://github.com/MoOx/postcss-cssnext
[postcss-color-function]: https://github.com/postcss/postcss-color-function
[postcss-modules-tilda]: https://github.com/princed/postcss-modules-tilda
[postcss-modules-values]: https://github.com/css-modules/postcss-modules-values
[modules-values-extract]: https://github.com/alexhisen/modules-values-extract
[enhanced-resolve]: https://github.com/webpack/enhanced-resolve/#contributing
Expand Down Expand Up @@ -109,6 +110,15 @@ body { background: myBrandColor }
body { background: blue }
```

#### preprocessValues `boolean`

When enabled, permit plugins defined earlier in the PostCSS pipeline to modify `@value` declarations before they are recorded by this plugin.

#### importsAsModuleRequests `boolean`

When enabled, value imports will be resolved as module requests, in line with `css-loader`'s resolution logic [as of 2.0.0](https://github.com/webpack-contrib/css-loader/blob/master/CHANGELOG.md#200-2018-12-07).
If your code is written with pre-2.0 import syntax, and utilises [postcss-modules-tilda] for compatibility, this option is not required.

### calc() and @value

To enable calculations *inside* **@value**, enable media queries support in [postcss-calc]:
Expand Down
20 changes: 18 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const path = require('path');
const promisify = require('es6-promisify');
const { CachedInputFileSystem, NodeJsInputFileSystem, ResolverFactory } = require('enhanced-resolve');
const valuesParser = require('postcss-values-parser');
const { urlToRequest } = require('loader-utils');

const matchImports = /^(.+?|\([\s\S]+?\))\s+from\s+("[^"]*"|'[^']*'|[\w-]+)$/;
const matchValueDefinition = /(?:\s+|^)([\w-]+)(:?\s+)(.+?)(\s*)$/g;
Expand Down Expand Up @@ -136,6 +137,8 @@ const factory = ({
fs = nodeFs,
noEmitExports = false,
resolve: resolveOptions = {},
preprocessValues = false,
importsAsModuleRequests = false,
} = {}) => async (root, rootResult) => {
const resolver = ResolverFactory.createResolver(Object.assign(
{ fileSystem: fs },
Expand All @@ -144,10 +147,23 @@ const factory = ({
const resolve = promisify(resolver.resolve, resolver);
const readFile = promisify(fs.readFile, fs);

let preprocessPlugins = [];
if (preprocessValues) {
const rootPlugins = rootResult.processor.plugins;
const oursPluginIndex = rootPlugins
.findIndex(plugin => plugin.postcssPlugin === PLUGIN);
preprocessPlugins = rootPlugins.slice(0, oursPluginIndex);
}

async function walkFile(from, dir, requiredDefinitions) {
const resolvedFrom = await resolve(concordContext, dir, from);
const request = importsAsModuleRequests ? urlToRequest(from) : from;
const resolvedFrom = await resolve(concordContext, dir, request);
const content = await readFile(resolvedFrom);
const result = await postcss([walkerPlugin(walk, requiredDefinitions, walkFile)])
const plugins = [
...preprocessPlugins,
walkerPlugin(walk, requiredDefinitions, walkFile),
];
const result = await postcss(plugins)
.process(content, { from: resolvedFrom });

return result.messages[0].value;
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
"dependencies": {
"enhanced-resolve": "^3.1.0",
"es6-promisify": "^5.0.0",
"postcss": "^6.0.1",
"loader-utils": "^2.0.0",
"postcss": "^7.0.0",
"postcss-values-parser": "^1.3.1"
},
"devDependencies": {
Expand Down
36 changes: 34 additions & 2 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,26 @@ const parserOpts = {
to: resolve(__dirname, 'fixtures/to.css'),
};

function run(t, input, output, opts = {}) {
return postcss([plugin(opts)]).process(input, parserOpts).then((result) => {
function run(t, input, output, opts = {}, extraPlugins = []) {
return postcss([
...extraPlugins,
plugin(opts),
]).process(input, parserOpts).then((result) => {
t.is(result.css, output);
t.is(result.warnings().length, 0);
});
}

// Simple plugin that replaces "black" with "purple" within @value declarations,
// used to test preprocess value transformation
const blackToPurplePlugin = postcss.plugin('testBlackToPurple', () => (root) => {
root.walkAtRules('value', (atRule) => {
atRule.replaceWith(atRule.clone({
params: atRule.params.replace('black', 'purple'),
}));
});
});

test('should pass through an empty string', async (t) => {
await run(t, '', '');
});
Expand Down Expand Up @@ -373,6 +386,16 @@ test('should replace an import from modules', async (t) => {
);
});

test('should apply extra plugins to inner processing', async (t) => {
await run(
t,
'@value module from "module/module.css";\n.a { color: module; }',
'@value module from "module/module.css";\n.a { color: purple; }',
{ preprocessValues: true },
[blackToPurplePlugin()],
);
});

test('should replace an import from main file of module', async (t) => {
await run(
t,
Expand All @@ -389,6 +412,15 @@ test('should replace an import from scoped modules', async (t) => {
);
});

test('should resolve imports as module requests', async (t) => {
await run(
t,
'@value scoped-module from "~@scope/module/module.css";\n@value base from "level1.css";\n.a { color: scoped-module; width: base; }',
'@value scoped-module from "~@scope/module/module.css";\n@value base from "level1.css";\n.a { color: purple; width: 10px; }',
{ importsAsModuleRequests: true },
);
});

test('variables are also present in messages', async (t) => {
const input = '@value myColor: blue; @value myColor2: myColor';
const processor = postcss([plugin]);
Expand Down

0 comments on commit abb832c

Please sign in to comment.