postcss-modules-scope
Advanced tools
Comparing version 0.0.5 to 0.0.6
181
lib/index.js
@@ -9,4 +9,2 @@ 'use strict'; | ||
function _slicedToArray(arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } } | ||
var _postcss = require('postcss'); | ||
@@ -16,64 +14,138 @@ | ||
var localRegexp = /^\:local\(\.?([\w-]+)\)(\:\w+)?$/; | ||
var _cssSelectorTokenizer = require('css-selector-tokenizer'); | ||
var processor = function processor(css) { | ||
var exports = {}; | ||
var _cssSelectorTokenizer2 = _interopRequireDefault(_cssSelectorTokenizer); | ||
// Find any :local classes | ||
css.eachRule(function (rule) { | ||
var match = rule.selector.match(localRegexp); | ||
if (match) { | ||
(function () { | ||
var _match = _slicedToArray(match, 3); | ||
function getSingleLocalNamesForComposes(selectors) { | ||
return selectors.nodes.map(function (node) { | ||
if (node.type !== 'selector' || node.nodes.length !== 1) { | ||
throw new Error('composes is only allowed when selector is single :local class name not in "' + _cssSelectorTokenizer2['default'].stringify(selectors) + '"'); | ||
} | ||
node = node.nodes[0]; | ||
if (node.type !== 'nested-pseudo-class' || node.name !== 'local' || node.nodes.length !== 1) { | ||
throw new Error('composes is only allowed when selector is single :local class name not in "' + _cssSelectorTokenizer2['default'].stringify(selectors) + '", "' + _cssSelectorTokenizer2['default'].stringify(node) + '" is weird'); | ||
} | ||
node = node.nodes[0]; | ||
if (node.type !== 'selector' || node.nodes.length !== 1) { | ||
throw new Error('composes is only allowed when selector is single :local class name not in "' + _cssSelectorTokenizer2['default'].stringify(selectors) + '", "' + _cssSelectorTokenizer2['default'].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('composes is only allowed when selector is single :local class name not in "' + _cssSelectorTokenizer2['default'].stringify(selectors) + '", "' + _cssSelectorTokenizer2['default'].stringify(node) + '" is weird'); | ||
} | ||
return node.name; | ||
}); | ||
} | ||
var exportedName = _match[1]; | ||
var pseudo = _match[2]; | ||
var processor = _postcss2['default'].plugin('postcss-modules-scope', function (options) { | ||
return function (css) { | ||
var generateScopedName = options && options.generateScopedName || processor.generateScopedName; | ||
var scopedName = processor.generateScopedName(css.source.input.from, exportedName); | ||
exports[exportedName] = exports[exportedName] || []; | ||
if (exports[exportedName].indexOf(scopedName) === -1) { | ||
exports[exportedName].push(scopedName); | ||
} | ||
rule.selector = '.' + scopedName + '' + (pseudo || ''); | ||
rule.eachDecl('composes', function (decl) { | ||
var classes = decl.value.split(/ from /)[0]; | ||
exports[exportedName].push(classes); | ||
decl.removeSelf(); | ||
}); | ||
})(); | ||
var exports = {}; | ||
function exportScopedName(name) { | ||
var scopedName = generateScopedName(name, css.source.input.from); | ||
exports[name] = exports[name] || []; | ||
if (exports[name].indexOf(scopedName) < 0) { | ||
exports[name].push(scopedName); | ||
} | ||
return scopedName; | ||
} | ||
}); | ||
// Find any :local keyframes | ||
css.eachAtRule('keyframes', function (atRule) { | ||
var match = atRule.params.match(localRegexp); | ||
if (match) { | ||
var _match2 = _slicedToArray(match, 2); | ||
function localizeNode(node) { | ||
var newNode = Object.create(node); | ||
switch (node.type) { | ||
case 'selector': | ||
newNode.nodes = node.nodes.map(localizeNode); | ||
return newNode; | ||
case 'class': | ||
case 'id': | ||
var scopedName = exportScopedName(node.name); | ||
newNode.name = scopedName; | ||
return newNode; | ||
} | ||
throw new Error(node.type + ' ("' + _cssSelectorTokenizer2['default'].stringify(node) + '") is not allowed in a :local block'); | ||
} | ||
var exportedName = _match2[1]; | ||
var scopedName = processor.generateScopedName(css.source.input.from, exportedName); | ||
exports[exportedName] = exports[exportedName] || []; | ||
exports[exportedName].push(scopedName); | ||
atRule.params = scopedName; | ||
function traverseNode(node) { | ||
switch (node.type) { | ||
case 'nested-pseudo-class': | ||
if (node.name === 'local') { | ||
if (node.nodes.length !== 1) { | ||
throw new Error('Unexpected comma (",") in :local block'); | ||
} | ||
return localizeNode(node.nodes[0]); | ||
} | ||
/* falls through */ | ||
case 'selectors': | ||
case 'selector': | ||
var newNode = Object.create(node); | ||
newNode.nodes = node.nodes.map(traverseNode); | ||
return newNode; | ||
} | ||
return node; | ||
} | ||
}); | ||
// If we found any :locals, insert an :export rule | ||
var exportedNames = Object.keys(exports); | ||
if (exportedNames.length > 0) { | ||
css.prepend(_postcss2['default'].rule({ | ||
selector: ':export', | ||
before: '\n', | ||
nodes: exportedNames.map(function (exportedName) { | ||
return _postcss2['default'].decl({ | ||
prop: exportedName, | ||
value: exports[exportedName].join(' '), | ||
before: '\n ' | ||
// Find any :local classes | ||
css.eachRule(function (rule) { | ||
var selector = _cssSelectorTokenizer2['default'].parse(rule.selector); | ||
var newSelector = traverseNode(selector); | ||
rule.selector = _cssSelectorTokenizer2['default'].stringify(newSelector); | ||
rule.eachDecl('composes', function (decl) { | ||
var localNames = getSingleLocalNamesForComposes(selector); | ||
var classes = decl.value.split(/\s+/); | ||
classes.forEach(function (className) { | ||
localNames.forEach(function (exportedName) { | ||
exports[exportedName].push(className); | ||
}); | ||
}); | ||
}) | ||
})); | ||
} | ||
}; | ||
decl.removeSelf(); | ||
}); | ||
rule.eachDecl(function (decl) { | ||
var tokens = decl.value.split(/(,|'[^']*'|"[^"]*")/); | ||
tokens = tokens.map(function (token, idx) { | ||
if (idx === 0 || tokens[idx - 1] === ',') { | ||
var localMatch = /^(\s*):local\s*\((.+?)\)/.exec(token); | ||
if (localMatch) { | ||
return localMatch[1] + exportScopedName(localMatch[2]) + token.substr(localMatch[0].length); | ||
} else { | ||
return token; | ||
} | ||
} else { | ||
return token; | ||
} | ||
}); | ||
decl.value = tokens.join(''); | ||
}); | ||
}); | ||
processor.generateScopedName = function (path, exportedName) { | ||
// Find any :local keyframes | ||
css.eachAtRule(function (atrule) { | ||
if (/keyframes$/.test(atrule.name)) { | ||
var localMatch = /^\s*:local\s*\((.+?)\)\s*$/.exec(atrule.params); | ||
if (localMatch) { | ||
atrule.params = exportScopedName(localMatch[1]); | ||
} | ||
} | ||
}); | ||
// If we found any :locals, insert an :export rule | ||
var exportedNames = Object.keys(exports); | ||
if (exportedNames.length > 0) { | ||
css.prepend(_postcss2['default'].rule({ | ||
selector: ':export', | ||
nodes: exportedNames.map(function (exportedName) { | ||
return _postcss2['default'].decl({ | ||
prop: exportedName, | ||
value: exports[exportedName].join(' '), | ||
before: '\n ' | ||
}); | ||
}) | ||
})); | ||
} | ||
}; | ||
}); | ||
processor.generateScopedName = function (exportedName, path) { | ||
var sanitisedPath = path.replace(/\.[^\.\/\\]+$/, '').replace(/[\W_]+/g, '_').replace(/^_|_$/g, ''); | ||
@@ -84,3 +156,2 @@ return '_' + sanitisedPath + '__' + exportedName; | ||
exports['default'] = processor; | ||
module.exports = exports['default']; | ||
/*match*/ /*match*/ | ||
module.exports = exports['default']; |
{ | ||
"name": "postcss-modules-scope", | ||
"version": "0.0.5", | ||
"version": "0.0.6", | ||
"description": "A CSS Modules transform to extract export statements from local-scope classes", | ||
@@ -37,2 +37,3 @@ "main": "lib/index.js", | ||
"dependencies": { | ||
"css-selector-tokenizer": "^0.3.1", | ||
"postcss": "^4.1.11" | ||
@@ -39,0 +40,0 @@ }, |
@@ -43,3 +43,3 @@ # CSS Modules: Scope Locals & Extend | ||
:local(.continueButton) { | ||
extends: globalButtonStyle; | ||
composes: globalButtonStyle; | ||
color: green; | ||
@@ -46,0 +46,0 @@ } |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
9277
136
2
+ Addedcss-selector-tokenizer@0.3.1(transitive)
+ Addedfastparse@1.1.2(transitive)