[6a3a178] | 1 | "use strict";
|
---|
| 2 |
|
---|
| 3 | const ICSSUtils = require("icss-utils");
|
---|
| 4 |
|
---|
| 5 | const matchImports = /^(.+?|\([\s\S]+?\))\s+from\s+("[^"]*"|'[^']*'|[\w-]+)$/;
|
---|
| 6 | const matchValueDefinition = /(?:\s+|^)([\w-]+):?(.*?)$/;
|
---|
| 7 | const matchImport = /^([\w-]+)(?:\s+as\s+([\w-]+))?/;
|
---|
| 8 |
|
---|
| 9 | module.exports = (options) => {
|
---|
| 10 | let importIndex = 0;
|
---|
| 11 | const createImportedName =
|
---|
| 12 | (options && options.createImportedName) ||
|
---|
| 13 | ((importName /*, path*/) =>
|
---|
| 14 | `i__const_${importName.replace(/\W/g, "_")}_${importIndex++}`);
|
---|
| 15 |
|
---|
| 16 | return {
|
---|
| 17 | postcssPlugin: "postcss-modules-values",
|
---|
| 18 | prepare(result) {
|
---|
| 19 | const importAliases = [];
|
---|
| 20 | const definitions = {};
|
---|
| 21 |
|
---|
| 22 | return {
|
---|
| 23 | Once(root, postcss) {
|
---|
| 24 | root.walkAtRules(/value/i, (atRule) => {
|
---|
| 25 | const matches = atRule.params.match(matchImports);
|
---|
| 26 |
|
---|
| 27 | if (matches) {
|
---|
| 28 | let [, /*match*/ aliases, path] = matches;
|
---|
| 29 |
|
---|
| 30 | // We can use constants for path names
|
---|
| 31 | if (definitions[path]) {
|
---|
| 32 | path = definitions[path];
|
---|
| 33 | }
|
---|
| 34 |
|
---|
| 35 | const imports = aliases
|
---|
| 36 | .replace(/^\(\s*([\s\S]+)\s*\)$/, "$1")
|
---|
| 37 | .split(/\s*,\s*/)
|
---|
| 38 | .map((alias) => {
|
---|
| 39 | const tokens = matchImport.exec(alias);
|
---|
| 40 |
|
---|
| 41 | if (tokens) {
|
---|
| 42 | const [, /*match*/ theirName, myName = theirName] = tokens;
|
---|
| 43 | const importedName = createImportedName(myName);
|
---|
| 44 | definitions[myName] = importedName;
|
---|
| 45 | return { theirName, importedName };
|
---|
| 46 | } else {
|
---|
| 47 | throw new Error(`@import statement "${alias}" is invalid!`);
|
---|
| 48 | }
|
---|
| 49 | });
|
---|
| 50 |
|
---|
| 51 | importAliases.push({ path, imports });
|
---|
| 52 |
|
---|
| 53 | atRule.remove();
|
---|
| 54 |
|
---|
| 55 | return;
|
---|
| 56 | }
|
---|
| 57 |
|
---|
| 58 | if (atRule.params.indexOf("@value") !== -1) {
|
---|
| 59 | result.warn("Invalid value definition: " + atRule.params);
|
---|
| 60 | }
|
---|
| 61 |
|
---|
| 62 | let [, key, value] = `${atRule.params}${atRule.raws.between}`.match(
|
---|
| 63 | matchValueDefinition
|
---|
| 64 | );
|
---|
| 65 |
|
---|
| 66 | const normalizedValue = value.replace(/\/\*((?!\*\/).*?)\*\//g, "");
|
---|
| 67 |
|
---|
| 68 | if (normalizedValue.length === 0) {
|
---|
| 69 | result.warn("Invalid value definition: " + atRule.params);
|
---|
| 70 | atRule.remove();
|
---|
| 71 |
|
---|
| 72 | return;
|
---|
| 73 | }
|
---|
| 74 |
|
---|
| 75 | let isOnlySpace = /^\s+$/.test(normalizedValue);
|
---|
| 76 |
|
---|
| 77 | if (!isOnlySpace) {
|
---|
| 78 | value = value.trim();
|
---|
| 79 | }
|
---|
| 80 |
|
---|
| 81 | // Add to the definitions, knowing that values can refer to each other
|
---|
| 82 | definitions[key] = ICSSUtils.replaceValueSymbols(
|
---|
| 83 | value,
|
---|
| 84 | definitions
|
---|
| 85 | );
|
---|
| 86 |
|
---|
| 87 | atRule.remove();
|
---|
| 88 | });
|
---|
| 89 |
|
---|
| 90 | /* If we have no definitions, don't continue */
|
---|
| 91 | if (!Object.keys(definitions).length) {
|
---|
| 92 | return;
|
---|
| 93 | }
|
---|
| 94 |
|
---|
| 95 | /* Perform replacements */
|
---|
| 96 | ICSSUtils.replaceSymbols(root, definitions);
|
---|
| 97 |
|
---|
| 98 | /* We want to export anything defined by now, but don't add it to the CSS yet or it well get picked up by the replacement stuff */
|
---|
| 99 | const exportDeclarations = Object.keys(definitions).map((key) =>
|
---|
| 100 | postcss.decl({
|
---|
| 101 | value: definitions[key],
|
---|
| 102 | prop: key,
|
---|
| 103 | raws: { before: "\n " },
|
---|
| 104 | })
|
---|
| 105 | );
|
---|
| 106 |
|
---|
| 107 | /* Add export rules if any */
|
---|
| 108 | if (exportDeclarations.length > 0) {
|
---|
| 109 | const exportRule = postcss.rule({
|
---|
| 110 | selector: ":export",
|
---|
| 111 | raws: { after: "\n" },
|
---|
| 112 | });
|
---|
| 113 |
|
---|
| 114 | exportRule.append(exportDeclarations);
|
---|
| 115 |
|
---|
| 116 | root.prepend(exportRule);
|
---|
| 117 | }
|
---|
| 118 |
|
---|
| 119 | /* Add import rules */
|
---|
| 120 | importAliases.reverse().forEach(({ path, imports }) => {
|
---|
| 121 | const importRule = postcss.rule({
|
---|
| 122 | selector: `:import(${path})`,
|
---|
| 123 | raws: { after: "\n" },
|
---|
| 124 | });
|
---|
| 125 |
|
---|
| 126 | imports.forEach(({ theirName, importedName }) => {
|
---|
| 127 | importRule.append({
|
---|
| 128 | value: theirName,
|
---|
| 129 | prop: importedName,
|
---|
| 130 | raws: { before: "\n " },
|
---|
| 131 | });
|
---|
| 132 | });
|
---|
| 133 |
|
---|
| 134 | root.prepend(importRule);
|
---|
| 135 | });
|
---|
| 136 | },
|
---|
| 137 | };
|
---|
| 138 | },
|
---|
| 139 | };
|
---|
| 140 | };
|
---|
| 141 |
|
---|
| 142 | module.exports.postcss = true;
|
---|