123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- 'use strict';
- const postcss = require('postcss');
- const ICSSUtils = require('icss-utils');
- const matchImports = /^(.+?|\([\s\S]+?\))\s+from\s+("[^"]*"|'[^']*'|[\w-]+)$/;
- const matchValueDefinition = /(?:\s+|^)([\w-]+):?\s+(.+?)\s*$/g;
- const matchImport = /^([\w-]+)(?:\s+as\s+([\w-]+))?/;
- let options = {};
- let importIndex = 0;
- let createImportedName =
- (options && options.createImportedName) ||
- ((importName /*, path*/) =>
- `i__const_${importName.replace(/\W/g, '_')}_${importIndex++}`);
- module.exports = postcss.plugin(
- 'postcss-modules-values',
- () => (css, result) => {
- const importAliases = [];
- const definitions = {};
- const addDefinition = atRule => {
- let matches;
- while ((matches = matchValueDefinition.exec(atRule.params))) {
- let [, /*match*/ key, value] = matches;
- // Add to the definitions, knowing that values can refer to each other
- definitions[key] = ICSSUtils.replaceValueSymbols(value, definitions);
- atRule.remove();
- }
- };
- const addImport = atRule => {
- const matches = matchImports.exec(atRule.params);
- if (matches) {
- let [, /*match*/ aliases, path] = matches;
- // We can use constants for path names
- if (definitions[path]) {
- path = definitions[path];
- }
- const imports = aliases
- .replace(/^\(\s*([\s\S]+)\s*\)$/, '$1')
- .split(/\s*,\s*/)
- .map(alias => {
- const tokens = matchImport.exec(alias);
- if (tokens) {
- const [, /*match*/ theirName, myName = theirName] = tokens;
- const importedName = createImportedName(myName);
- definitions[myName] = importedName;
- return { theirName, importedName };
- } else {
- throw new Error(`@import statement "${alias}" is invalid!`);
- }
- });
- importAliases.push({ path, imports });
- atRule.remove();
- }
- };
- /* Look at all the @value statements and treat them as locals or as imports */
- css.walkAtRules('value', atRule => {
- if (matchImports.exec(atRule.params)) {
- addImport(atRule);
- } else {
- if (atRule.params.indexOf('@value') !== -1) {
- result.warn('Invalid value definition: ' + atRule.params);
- }
- addDefinition(atRule);
- }
- });
- /* 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 */
- const exportDeclarations = Object.keys(definitions).map(key =>
- postcss.decl({
- value: definitions[key],
- prop: key,
- raws: { before: '\n ' }
- })
- );
- /* If we have no definitions, don't continue */
- if (!Object.keys(definitions).length) {
- return;
- }
- /* Perform replacements */
- ICSSUtils.replaceSymbols(css, definitions);
- /* Add export rules if any */
- if (exportDeclarations.length > 0) {
- const exportRule = postcss.rule({
- selector: ':export',
- raws: { after: '\n' }
- });
- exportRule.append(exportDeclarations);
- css.prepend(exportRule);
- }
- /* Add import rules */
- importAliases.reverse().forEach(({ path, imports }) => {
- const importRule = postcss.rule({
- selector: `:import(${path})`,
- raws: { after: '\n' }
- });
- imports.forEach(({ theirName, importedName }) => {
- importRule.append({
- value: theirName,
- prop: importedName,
- raws: { before: '\n ' }
- });
- });
- css.prepend(importRule);
- });
- }
- );
|