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

Postcss 8 #10

Merged
merged 4 commits into from
Sep 16, 2020
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
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