Skip to content

chore(deps): update #2

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

Merged
merged 1 commit into from
Nov 23, 2018
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
21 changes: 3 additions & 18 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,25 +1,10 @@
{
"parser": "babel-eslint",
"parserOptions": {
"ecmaVersion": 2018
},
"env": {
"node": true
},
"ecmaFeatures": {
"arrowFunctions": true,
"blockBindings": true,
"classes": true,
"defaultParams": true,
"destructuring": true,
"forOf": true,
"modules": true,
"objectLiteralComputedProperties": true,
"objectLiteralShorthandMethods": true,
"objectLiteralShorthandProperties": true,
"spread": true,
"superInFunctions": true,
"templateStrings": true,
"unicodeCodePointEscapes": true,
"jsx": true
},
"rules": {
"quotes": [2, "single"]
}
Expand Down
8 changes: 3 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
language: node_js
node_js:
- "4"
- "6"
- "node"
- "8"
- "10"
- "11"
script: npm run travis

before_install:
- '[ "${TRAVIS_NODE_VERSION}" != "0.10" ] || npm install -g npm'

after_success:
- cat ./coverage/lcov.info | node_modules/.bin/coveralls --verbose
- cat ./coverage/coverage.json | node_modules/codecov.io/bin/codecov.io.js
Expand Down
40 changes: 19 additions & 21 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
{
"name": "postcss-modules-scope",
"version": "1.1.0",
"version": "2.0.0",
"description": "A CSS Modules transform to extract export statements from local-scope classes",
"main": "lib/index.js",
"main": "src/index.js",
"engines": {
"node": ">= 6"
},
"scripts": {
"lint": "eslint src",
"build": "babel --out-dir lib src",
"watch": "chokidar src -c 'npm run build'",
"test": "mocha --compilers js:babel/register",
"posttest": "npm run lint && npm run build",
"autotest": "chokidar src test -c 'npm test'",
"precover": "npm run lint && npm run build",
"cover": "babel-istanbul cover node_modules/.bin/_mocha",
"travis": "npm run cover -- --report lcovonly",
"prepublish": "npm run build"
"lint": "eslint src test",
"pretest": "yarn lint",
"test": "mocha",
"autotest": "chokidar src test -c 'yarn test'",
"precover": "yarn lint",
"cover": "nyc mocha",
"travis": "yarn cover",
"prepublish": "yarn run test"
},
"repository": {
"type": "git",
Expand All @@ -25,7 +26,7 @@
"plugin"
],
"files": [
"lib"
"src"
],
"author": "Glen Maddern",
"license": "ISC",
Expand All @@ -35,18 +36,15 @@
"homepage": "https://github.com/css-modules/postcss-modules-scope",
"dependencies": {
"css-selector-tokenizer": "^0.7.0",
"postcss": "^6.0.1"
"postcss": "^7.0.6"
},
"devDependencies": {
"babel": "^5.4.7",
"babel-eslint": "^6.1.2",
"babel-istanbul": "^0.4.0",
"babelify": "^7.1.0",
"chokidar-cli": "^1.0.1",
"codecov.io": "^0.1.2",
"coveralls": "^2.11.2",
"coveralls": "^3.0.2",
"css-selector-parser": "^1.0.4",
"eslint": "^1.5.0",
"mocha": "^3.0.1"
"eslint": "^5.9.0",
"nyc": "^13.1.0",
"mocha": "^5.2.0"
}
}
161 changes: 103 additions & 58 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,86 +1,122 @@
import postcss from 'postcss';
import Tokenizer from 'css-selector-tokenizer';
'use strict';

let hasOwnProperty = Object.prototype.hasOwnProperty;
const postcss = require('postcss');
const Tokenizer = require('css-selector-tokenizer');

const hasOwnProperty = Object.prototype.hasOwnProperty;

function getSingleLocalNamesForComposes(selectors) {
return selectors.nodes.map((node) => {
if(node.type !== 'selector' || node.nodes.length !== 1) {
throw new Error('composition is only allowed when selector is single :local class name not in "' +
Tokenizer.stringify(selectors) + '"');
return selectors.nodes.map(node => {
if (node.type !== 'selector' || node.nodes.length !== 1) {
throw new Error(
'composition is only allowed when selector is single :local class name not in "' +
Tokenizer.stringify(selectors) +
'"'
);
}
node = node.nodes[0];
if(node.type !== 'nested-pseudo-class' || node.name !== 'local' || node.nodes.length !== 1) {
throw new Error('composition is only allowed when selector is single :local class name not in "' +
Tokenizer.stringify(selectors) + '", "' + Tokenizer.stringify(node) + '" is weird');
if (
node.type !== 'nested-pseudo-class' ||
node.name !== 'local' ||
node.nodes.length !== 1
) {
throw new Error(
'composition is only allowed when selector is single :local class name not in "' +
Tokenizer.stringify(selectors) +
'", "' +
Tokenizer.stringify(node) +
'" is weird'
);
}
node = node.nodes[0];
if(node.type !== 'selector' || node.nodes.length !== 1) {
throw new Error('composition is only allowed when selector is single :local class name not in "' +
Tokenizer.stringify(selectors) + '", "' + Tokenizer.stringify(node) + '" is weird');
if (node.type !== 'selector' || node.nodes.length !== 1) {
throw new Error(
'composition is only allowed when selector is single :local class name not in "' +
Tokenizer.stringify(selectors) +
'", "' +
Tokenizer.stringify(node) +
'" is weird'
);
}
node = node.nodes[0];
if(node.type !== 'class') { // 'id' is not possible, because you can't compose ids
throw new Error('composition is only allowed when selector is single :local class name not in "' +
Tokenizer.stringify(selectors) + '", "' + Tokenizer.stringify(node) + '" is weird');
if (node.type !== 'class') {
// 'id' is not possible, because you can't compose ids
throw new Error(
'composition is only allowed when selector is single :local class name not in "' +
Tokenizer.stringify(selectors) +
'", "' +
Tokenizer.stringify(node) +
'" is weird'
);
}
return node.name;
});
}

const processor = postcss.plugin('postcss-modules-scope', function(options) {
return (css) => {
let generateScopedName = options && options.generateScopedName || processor.generateScopedName;
return css => {
const generateScopedName =
(options && options.generateScopedName) || processor.generateScopedName;

let exports = {};
const exports = {};

function exportScopedName(name) {
let scopedName = generateScopedName(name, css.source.input.from, css.source.input.css);
const scopedName = generateScopedName(
name,
css.source.input.from,
css.source.input.css
);
exports[name] = exports[name] || [];
if(exports[name].indexOf(scopedName) < 0) {
if (exports[name].indexOf(scopedName) < 0) {
exports[name].push(scopedName);
}
return scopedName;
}

function localizeNode(node) {
let newNode = Object.create(node);
switch(node.type) {
const newNode = Object.create(node);
switch (node.type) {
case 'selector':
newNode.nodes = node.nodes.map(localizeNode);
return newNode;
case 'class':
case 'id':
let scopedName = exportScopedName(node.name);
newNode.name = scopedName;
case 'id': {
newNode.name = exportScopedName(node.name);
return newNode;
}
}
throw new Error(node.type + ' ("' + Tokenizer.stringify(node) + '") is not allowed in a :local block');
throw new Error(
node.type +
' ("' +
Tokenizer.stringify(node) +
'") is not allowed in a :local block'
);
}

function traverseNode(node) {
switch(node.type) {
switch (node.type) {
case 'nested-pseudo-class':
if(node.name === 'local') {
if(node.nodes.length !== 1) {
if (node.name === 'local') {
if (node.nodes.length !== 1) {
throw new Error('Unexpected comma (",") in :local block');
}
return localizeNode(node.nodes[0]);
}
/* falls through */
/* falls through */
case 'selectors':
case 'selector':
let newNode = Object.create(node);
case 'selector': {
const newNode = Object.create(node);
newNode.nodes = node.nodes.map(traverseNode);
return newNode;
}
}
return node;
}

// Find any :import and remember imported names
let importedNames = {};
const importedNames = {};
css.walkRules(rule => {
if(/^:import\(.+\)$/.test(rule.selector)) {
if (/^:import\(.+\)$/.test(rule.selector)) {
rule.walkDecls(decl => {
importedNames[decl.prop] = true;
});
Expand All @@ -89,30 +125,32 @@ const processor = postcss.plugin('postcss-modules-scope', function(options) {

// Find any :local classes
css.walkRules(rule => {
let selector = Tokenizer.parse(rule.selector);
let newSelector = traverseNode(selector);
const selector = Tokenizer.parse(rule.selector);
const newSelector = traverseNode(selector);
rule.selector = Tokenizer.stringify(newSelector);
rule.walkDecls(/composes|compose-with/, decl => {
let localNames = getSingleLocalNamesForComposes(selector);
let classes = decl.value.split(/\s+/);
classes.forEach((className) => {
let global = /^global\(([^\)]+)\)$/.exec(className);
const localNames = getSingleLocalNamesForComposes(selector);
const classes = decl.value.split(/\s+/);
classes.forEach(className => {
const global = /^global\(([^\)]+)\)$/.exec(className);
if (global) {
localNames.forEach((exportedName) => {
localNames.forEach(exportedName => {
exports[exportedName].push(global[1]);
})
});
} else if (hasOwnProperty.call(importedNames, className)) {
localNames.forEach((exportedName) => {
localNames.forEach(exportedName => {
exports[exportedName].push(className);
});
} else if (hasOwnProperty.call(exports, className)) {
localNames.forEach((exportedName) => {
exports[className].forEach((item) => {
localNames.forEach(exportedName => {
exports[className].forEach(item => {
exports[exportedName].push(item);
});
});
} else {
throw decl.error(`referenced class name "${className}" in ${decl.prop} not found`);
throw decl.error(
`referenced class name "${className}" in ${decl.prop} not found`
);
}
});
decl.remove();
Expand All @@ -121,10 +159,14 @@ const processor = postcss.plugin('postcss-modules-scope', function(options) {
rule.walkDecls(decl => {
var tokens = decl.value.split(/(,|'[^']*'|"[^"]*")/);
tokens = tokens.map((token, idx) => {
if(idx === 0 || tokens[idx - 1] === ',') {
let localMatch = /^(\s*):local\s*\((.+?)\)/.exec(token);
if(localMatch) {
return localMatch[1] + exportScopedName(localMatch[2]) + token.substr(localMatch[0].length);
if (idx === 0 || tokens[idx - 1] === ',') {
const localMatch = /^(\s*):local\s*\((.+?)\)/.exec(token);
if (localMatch) {
return (
localMatch[1] +
exportScopedName(localMatch[2]) +
token.substr(localMatch[0].length)
);
} else {
return token;
}
Expand All @@ -138,19 +180,19 @@ const processor = postcss.plugin('postcss-modules-scope', function(options) {

// Find any :local keyframes
css.walkAtRules(atrule => {
if(/keyframes$/.test(atrule.name)) {
if (/keyframes$/i.test(atrule.name)) {
var localMatch = /^\s*:local\s*\((.+?)\)\s*$/.exec(atrule.params);
if(localMatch) {
if (localMatch) {
atrule.params = exportScopedName(localMatch[1]);
}
}
});

// If we found any :locals, insert an :export rule
let exportedNames = Object.keys(exports);
const exportedNames = Object.keys(exports);
if (exportedNames.length > 0) {
let exportRule = postcss.rule({selector: `:export`});
exportedNames.forEach(exportedName =>
const exportRule = postcss.rule({ selector: ':export' });
exportedNames.forEach(exportedName =>
exportRule.append({
prop: exportedName,
value: exports[exportedName].join(' '),
Expand All @@ -163,8 +205,11 @@ const processor = postcss.plugin('postcss-modules-scope', function(options) {
});

processor.generateScopedName = function(exportedName, path) {
let sanitisedPath = path.replace(/\.[^\.\/\\]+$/, '').replace(/[\W_]+/g, '_').replace(/^_|_$/g, '');
const sanitisedPath = path
.replace(/\.[^\.\/\\]+$/, '')
.replace(/[\W_]+/g, '_')
.replace(/^_|_$/g, '');
return `_${sanitisedPath}__${exportedName}`;
};

export default processor;
module.exports = processor;
Loading