Skip to content

Commit

Permalink
feat: PostCSS 8 (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
evilebottnawi committed Sep 16, 2020
1 parent de45a53 commit 286ceba
Show file tree
Hide file tree
Showing 7 changed files with 1,504 additions and 2,141 deletions.
4 changes: 1 addition & 3 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,5 @@
"env": {
"node": true
},
"rules": {
"quotes": [2, "single"]
}
"extends": "eslint:recommended"
}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
.idea
.nyc_output
node_modules
lib/
7 changes: 4 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
language: node_js

node_js:
- "6"
- "8"
- "10"
- "12"
script: npm run travis
- "14"

script: yarn ci

after_success:
- cat ./coverage/lcov.info | node_modules/.bin/coveralls --verbose
Expand Down
32 changes: 20 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
{
"name": "postcss-modules-values",
"version": "3.0.0",
"version": "4.0.0",
"description": "PostCSS plugin for CSS Modules to pass arbitrary values between your module files",
"main": "src/index.js",
"files": [
"src"
],
"engines": {
"node": ">= 10.13.0 || >= 12.13.0 || >= 14"
},
"scripts": {
"lint": "eslint src test",
"pretest": "yarn lint",
"prettier": "prettier -l --ignore-path .gitignore .",
"eslint": "eslint --ignore-path .gitignore .",
"pretest": "yarn eslint && yarn prettier",
"test": "mocha",
"autotest": "chokidar src test -c 'npm test'",
"cover": "nyc mocha",
"travis": "yarn lint && yarn cover",
"ci": "yarn pretest && yarn cover",
"prepublishOnly": "yarn test"
},
"repository": {
Expand All @@ -31,15 +35,19 @@
},
"homepage": "https://github.com/css-modules/postcss-modules-values#readme",
"devDependencies": {
"chokidar-cli": "^1.0.1",
"codecov.io": "^0.1.2",
"coveralls": "^3.0.2",
"eslint": "^5.9.0",
"mocha": "^6.1.4",
"nyc": "^14.1.0"
"chokidar-cli": "^2.1.0",
"codecov.io": "^0.1.6",
"coveralls": "^3.1.0",
"eslint": "^7.9.0",
"mocha": "^8.1.3",
"nyc": "^15.1.0",
"postcss": "^8.0.3",
"prettier": "^2.1.2"
},
"dependencies": {
"icss-utils": "^4.0.0",
"postcss": "^7.0.6"
"icss-utils": "^4.1.1"
},
"peerDependencies": {
"postcss": "^8.0.3"
}
}
221 changes: 119 additions & 102 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';
"use strict";

const postcss = require('postcss');
const ICSSUtils = require('icss-utils');
const postcss = require("postcss");
const ICSSUtils = require("icss-utils");

const matchImports = /^(.+?|\([\s\S]+?\))\s+from\s+("[^"]*"|'[^']*'|[\w-]+)$/;
const matchValueDefinition = /(?:\s+|^)([\w-]+):?\s+(.+?)\s*$/g;
Expand All @@ -12,107 +12,124 @@ 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];
`i__const_${importName.replace(/\W/g, "_")}_${importIndex++}`);

module.exports = () => {
return {
postcssPlugin: "postcss-modules-values",
prepare(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 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 };
};
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();
}
};

return {
/* Look at all the @value statements and treat them as locals or as imports */
AtRule: {
value(atRule) {
if (matchImports.exec(atRule.params)) {
addImport(atRule);
} else {
throw new Error(`@import statement "${alias}" is invalid!`);
if (atRule.params.indexOf("@value") !== -1) {
result.warn("Invalid value definition: " + atRule.params);
}

addDefinition(atRule);
}
},
},
RootExit(root) {
/* 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(root, definitions);

/* Add export rules if any */
if (exportDeclarations.length > 0) {
const exportRule = postcss.rule({
selector: ":export",
raws: { after: "\n" },
});

exportRule.append(exportDeclarations);

root.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 " },
});
});

root.prepend(importRule);
});
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);
});
}
);
module.exports.postcss = true;
Loading

0 comments on commit 286ceba

Please sign in to comment.