postcss-modules-local-by-default
Advanced tools
Comparing version 2.0.0 to 2.0.1
@@ -5,2 +5,6 @@ # Change Log | ||
## [2.0.1] - 2018-11-23 | ||
### Changed | ||
- Handle uppercase `keyframes` at rule. | ||
## [2.0.0] - 2018-11-23 | ||
@@ -76,1 +80,3 @@ ### Changed | ||
[0.0.11]: https://github.com/postcss-modules-local-by-default/compare/v0.0.10...v0.0.11 | ||
[2.0.0]: https://github.com/postcss-modules-local-by-default/compare/v1.3.1...v2.0.0 | ||
[2.0.1]: https://github.com/postcss-modules-local-by-default/compare/v2.0.0...v2.0.1 |
242
index.js
@@ -1,16 +0,19 @@ | ||
var postcss = require('postcss'); | ||
var Tokenizer = require('css-selector-tokenizer'); | ||
'use strict'; | ||
const postcss = require('postcss'); | ||
const Tokenizer = require('css-selector-tokenizer'); | ||
function normalizeNodeArray(nodes) { | ||
var array = []; | ||
const array = []; | ||
nodes.forEach(function(x) { | ||
if(Array.isArray(x)) { | ||
if (Array.isArray(x)) { | ||
normalizeNodeArray(x).forEach(function(item) { | ||
array.push(item); | ||
}); | ||
} else if(x) { | ||
} else if (x) { | ||
array.push(x); | ||
} | ||
}); | ||
if(array.length > 0 && array[array.length - 1].type === 'spacing') { | ||
if (array.length > 0 && array[array.length - 1].type === 'spacing') { | ||
array.pop(); | ||
@@ -22,16 +25,16 @@ } | ||
function localizeNode(node, context) { | ||
if(context.ignoreNextSpacing && node.type !== 'spacing') { | ||
if (context.ignoreNextSpacing && node.type !== 'spacing') { | ||
throw new Error('Missing whitespace after :' + context.ignoreNextSpacing); | ||
} | ||
if(context.enforceNoSpacing && node.type === 'spacing') { | ||
if (context.enforceNoSpacing && node.type === 'spacing') { | ||
throw new Error('Missing whitespace before :' + context.enforceNoSpacing); | ||
} | ||
var newNodes; | ||
switch(node.type) { | ||
let newNodes; | ||
switch (node.type) { | ||
case 'selectors': | ||
var resultingGlobal; | ||
let resultingGlobal; | ||
context.hasPureGlobals = false; | ||
newNodes = node.nodes.map(function(n) { | ||
var nContext = { | ||
const nContext = { | ||
global: context.global, | ||
@@ -43,9 +46,12 @@ lastWasSpacing: true, | ||
n = localizeNode(n, nContext); | ||
if(typeof resultingGlobal === 'undefined') { | ||
if (typeof resultingGlobal === 'undefined') { | ||
resultingGlobal = nContext.global; | ||
} else if(resultingGlobal !== nContext.global) { | ||
throw new Error('Inconsistent rule global/local result in rule "' + | ||
Tokenizer.stringify(node) + '" (multiple selectors must result in the same mode for the rule)'); | ||
} else if (resultingGlobal !== nContext.global) { | ||
throw new Error( | ||
'Inconsistent rule global/local result in rule "' + | ||
Tokenizer.stringify(node) + | ||
'" (multiple selectors must result in the same mode for the rule)' | ||
); | ||
} | ||
if(!nContext.hasLocals) { | ||
if (!nContext.hasLocals) { | ||
context.hasPureGlobals = true; | ||
@@ -69,3 +75,3 @@ } | ||
case 'spacing': | ||
if(context.ignoreNextSpacing) { | ||
if (context.ignoreNextSpacing) { | ||
context.ignoreNextSpacing = false; | ||
@@ -80,9 +86,15 @@ context.lastWasSpacing = false; | ||
case 'pseudo-class': | ||
if(node.name === 'local' || node.name === 'global') { | ||
if(context.inside) { | ||
throw new Error('A :' + node.name + ' is not allowed inside of a :' + context.inside + '(...)'); | ||
if (node.name === 'local' || node.name === 'global') { | ||
if (context.inside) { | ||
throw new Error( | ||
'A :' + | ||
node.name + | ||
' is not allowed inside of a :' + | ||
context.inside + | ||
'(...)' | ||
); | ||
} | ||
context.ignoreNextSpacing = context.lastWasSpacing ? node.name : false; | ||
context.enforceNoSpacing = context.lastWasSpacing ? false : node.name; | ||
context.global = (node.name === 'global'); | ||
context.global = node.name === 'global'; | ||
context.explicit = true; | ||
@@ -94,9 +106,15 @@ return null; | ||
case 'nested-pseudo-class': | ||
var subContext; | ||
if(node.name === 'local' || node.name === 'global') { | ||
if(context.inside) { | ||
throw new Error('A :' + node.name + '(...) is not allowed inside of a :' + context.inside + '(...)'); | ||
let subContext; | ||
if (node.name === 'local' || node.name === 'global') { | ||
if (context.inside) { | ||
throw new Error( | ||
'A :' + | ||
node.name + | ||
'(...) is not allowed inside of a :' + | ||
context.inside + | ||
'(...)' | ||
); | ||
} | ||
subContext = { | ||
global: (node.name === 'global'), | ||
global: node.name === 'global', | ||
inside: node.name, | ||
@@ -126,3 +144,3 @@ hasLocals: false, | ||
} | ||
if(subContext.hasLocals) { | ||
if (subContext.hasLocals) { | ||
context.hasLocals = true; | ||
@@ -134,3 +152,3 @@ } | ||
case 'class': | ||
if(!context.global) { | ||
if (!context.global) { | ||
node = { | ||
@@ -154,6 +172,6 @@ type: 'nested-pseudo-class', | ||
function localizeDeclNode(node, context) { | ||
var newNode; | ||
switch(node.type) { | ||
let newNode; | ||
switch (node.type) { | ||
case 'item': | ||
if(context.localizeNextItem) { | ||
if (context.localizeNextItem) { | ||
newNode = Object.create(node); | ||
@@ -167,3 +185,3 @@ newNode.name = ':local(' + newNode.name + ')'; | ||
case 'nested-item': | ||
var newNodes = node.nodes.map(function(n) { | ||
const newNodes = node.nodes.map(function(n) { | ||
return localizeDeclValue(n, context); | ||
@@ -176,3 +194,3 @@ }); | ||
case 'url': | ||
if(context.options && context.options.rewriteUrl) { | ||
if (context.options && context.options.rewriteUrl) { | ||
newNode = Object.create(node); | ||
@@ -188,3 +206,3 @@ newNode.url = context.options.rewriteUrl(context.global, node.url); | ||
function localizeDeclValue(valueNode, context) { | ||
var newValueNode = Object.create(valueNode); | ||
const newValueNode = Object.create(valueNode); | ||
newValueNode.nodes = valueNode.nodes.map(function(node) { | ||
@@ -197,3 +215,3 @@ return localizeDeclNode(node, context); | ||
function localizeAnimationShorthandDeclValueNodes(nodes, context) { | ||
var validIdent = validIdent = /^-?[_a-z][_a-z0-9-]*$/i; | ||
const validIdent = /^-?[_a-z][_a-z0-9-]*$/i; | ||
@@ -211,42 +229,44 @@ /* | ||
*/ | ||
var animationKeywords = { | ||
'$alternate': 1, | ||
const animationKeywords = { | ||
$alternate: 1, | ||
'$alternate-reverse': 1, | ||
'$backwards': 1, | ||
'$both': 1, | ||
'$ease': 1, | ||
$backwards: 1, | ||
$both: 1, | ||
$ease: 1, | ||
'$ease-in': 1, | ||
'$ease-in-out': 1, | ||
'$ease-out': 1, | ||
'$forwards': 1, | ||
'$infinite': 1, | ||
'$linear': 1, | ||
'$none': Infinity, // No matter how many times you write none, it will never be an animation name | ||
'$normal': 1, | ||
'$paused': 1, | ||
'$reverse': 1, | ||
'$running': 1, | ||
$forwards: 1, | ||
$infinite: 1, | ||
$linear: 1, | ||
$none: Infinity, // No matter how many times you write none, it will never be an animation name | ||
$normal: 1, | ||
$paused: 1, | ||
$reverse: 1, | ||
$running: 1, | ||
'$step-end': 1, | ||
'$step-start': 1, | ||
'$initial': Infinity, | ||
'$inherit': Infinity, | ||
'$unset': Infinity, | ||
$initial: Infinity, | ||
$inherit: Infinity, | ||
$unset: Infinity | ||
}; | ||
var didParseAnimationName = false; | ||
var parsedAnimationKeywords = {}; | ||
const didParseAnimationName = false; | ||
const parsedAnimationKeywords = {}; | ||
return nodes.map(function(valueNode) { | ||
var value = valueNode.type === 'item' | ||
? valueNode.name.toLowerCase() | ||
: null; | ||
const value = | ||
valueNode.type === 'item' ? valueNode.name.toLowerCase() : null; | ||
var shouldParseAnimationName = false; | ||
let shouldParseAnimationName = false; | ||
if (!didParseAnimationName && value && validIdent.test(value)) { | ||
if ('$' + value in animationKeywords) { | ||
parsedAnimationKeywords['$' + value] = ('$' + value in parsedAnimationKeywords) | ||
? (parsedAnimationKeywords['$' + value] + 1) | ||
: 0; | ||
parsedAnimationKeywords['$' + value] = | ||
'$' + value in parsedAnimationKeywords | ||
? parsedAnimationKeywords['$' + value] + 1 | ||
: 0; | ||
shouldParseAnimationName = (parsedAnimationKeywords['$' + value] >= animationKeywords['$' + value]); | ||
shouldParseAnimationName = | ||
parsedAnimationKeywords['$' + value] >= | ||
animationKeywords['$' + value]; | ||
} else { | ||
@@ -257,3 +277,3 @@ shouldParseAnimationName = true; | ||
var subContext = { | ||
const subContext = { | ||
options: context.options, | ||
@@ -268,6 +288,9 @@ global: context.global, | ||
function localizeAnimationShorthandDeclValues(valuesNode, decl, context) { | ||
var newValuesNode = Object.create(valuesNode); | ||
const newValuesNode = Object.create(valuesNode); | ||
newValuesNode.nodes = valuesNode.nodes.map(function(valueNode, index) { | ||
var newValueNode = Object.create(valueNode); | ||
newValueNode.nodes = localizeAnimationShorthandDeclValueNodes(valueNode.nodes, context); | ||
const newValueNode = Object.create(valueNode); | ||
newValueNode.nodes = localizeAnimationShorthandDeclValueNodes( | ||
valueNode.nodes, | ||
context | ||
); | ||
return newValueNode; | ||
@@ -279,5 +302,5 @@ }); | ||
function localizeDeclValues(localize, valuesNode, decl, context) { | ||
var newValuesNode = Object.create(valuesNode); | ||
const newValuesNode = Object.create(valuesNode); | ||
newValuesNode.nodes = valuesNode.nodes.map(function(valueNode) { | ||
var subContext = { | ||
const subContext = { | ||
options: context.options, | ||
@@ -293,40 +316,56 @@ global: context.global, | ||
function localizeDecl(decl, context) { | ||
var valuesNode = Tokenizer.parseValues(decl.value); | ||
const valuesNode = Tokenizer.parseValues(decl.value); | ||
var isAnimation = /animation?$/.test(decl.prop); | ||
if (isAnimation) return localizeAnimationShorthandDeclValues(valuesNode, decl, context); | ||
const isAnimation = /animation?$/i.test(decl.prop); | ||
var isAnimationName = /animation(-name)?$/.test(decl.prop); | ||
if (isAnimationName) return localizeDeclValues(true, valuesNode, decl, context); | ||
if (isAnimation) { | ||
return localizeAnimationShorthandDeclValues(valuesNode, decl, context); | ||
} | ||
const isAnimationName = /animation(-name)?$/i.test(decl.prop); | ||
if (isAnimationName) { | ||
return localizeDeclValues(true, valuesNode, decl, context); | ||
} | ||
return localizeDeclValues(false, valuesNode, decl, context); | ||
} | ||
module.exports = postcss.plugin('postcss-modules-local-by-default', function (options) { | ||
module.exports = postcss.plugin('postcss-modules-local-by-default', function( | ||
options | ||
) { | ||
if (typeof options !== 'object') { | ||
options = {}; // If options is undefined or not an object the plugin fails | ||
} | ||
if(options && options.mode) { | ||
if(options.mode !== 'global' && options.mode !== 'local' && options.mode !== 'pure') { | ||
throw new Error('options.mode must be either "global", "local" or "pure" (default "local")'); | ||
if (options && options.mode) { | ||
if ( | ||
options.mode !== 'global' && | ||
options.mode !== 'local' && | ||
options.mode !== 'pure' | ||
) { | ||
throw new Error( | ||
'options.mode must be either "global", "local" or "pure" (default "local")' | ||
); | ||
} | ||
} | ||
var pureMode = options && options.mode === 'pure'; | ||
var globalMode = options && options.mode === 'global'; | ||
const pureMode = options && options.mode === 'pure'; | ||
const globalMode = options && options.mode === 'global'; | ||
return function(css) { | ||
css.walkAtRules(function(atrule) { | ||
if(/keyframes$/.test(atrule.name)) { | ||
var globalMatch = /^\s*:global\s*\((.+)\)\s*$/.exec(atrule.params); | ||
var localMatch = /^\s*:local\s*\((.+)\)\s*$/.exec(atrule.params); | ||
var globalKeyframes = globalMode; | ||
if(globalMatch) { | ||
if(pureMode) { | ||
throw atrule.error('@keyframes :global(...) is not allowed in pure mode'); | ||
if (/keyframes$/i.test(atrule.name)) { | ||
const globalMatch = /^\s*:global\s*\((.+)\)\s*$/.exec(atrule.params); | ||
const localMatch = /^\s*:local\s*\((.+)\)\s*$/.exec(atrule.params); | ||
let globalKeyframes = globalMode; | ||
if (globalMatch) { | ||
if (pureMode) { | ||
throw atrule.error( | ||
'@keyframes :global(...) is not allowed in pure mode' | ||
); | ||
} | ||
atrule.params = globalMatch[1]; | ||
globalKeyframes = true; | ||
} else if(localMatch) { | ||
} else if (localMatch) { | ||
atrule.params = localMatch[0]; | ||
globalKeyframes = false; | ||
} else if(!globalMode) { | ||
} else if (!globalMode) { | ||
atrule.params = ':local(' + atrule.params + ')'; | ||
@@ -340,5 +379,5 @@ } | ||
}); | ||
} else if(atrule.nodes) { | ||
} else if (atrule.nodes) { | ||
atrule.nodes.forEach(function(decl) { | ||
if(decl.type === 'decl') { | ||
if (decl.type === 'decl') { | ||
localizeDecl(decl, { | ||
@@ -353,8 +392,11 @@ options: options, | ||
css.walkRules(function(rule) { | ||
if(rule.parent.type === 'atrule' && /keyframes$/.test(rule.parent.name)) { | ||
if ( | ||
rule.parent.type === 'atrule' && | ||
/keyframes$/i.test(rule.parent.name) | ||
) { | ||
// ignore keyframe rules | ||
return; | ||
} | ||
var selector = Tokenizer.parse(rule.selector); | ||
var context = { | ||
const selector = Tokenizer.parse(rule.selector); | ||
const context = { | ||
options: options, | ||
@@ -364,11 +406,15 @@ global: globalMode, | ||
}; | ||
var newSelector; | ||
let newSelector; | ||
try { | ||
newSelector = localizeNode(selector, context); | ||
} catch(e) { | ||
} catch (e) { | ||
throw rule.error(e.message); | ||
} | ||
if(pureMode && context.hasPureGlobals) { | ||
throw rule.error('Selector "' + Tokenizer.stringify(selector) + '" is not pure ' + | ||
'(pure selectors must contain at least one local class or id)'); | ||
if (pureMode && context.hasPureGlobals) { | ||
throw rule.error( | ||
'Selector "' + | ||
Tokenizer.stringify(selector) + | ||
'" is not pure ' + | ||
'(pure selectors must contain at least one local class or id)' | ||
); | ||
} | ||
@@ -375,0 +421,0 @@ // Less-syntax mixins parse as rules with no nodes |
{ | ||
"name": "postcss-modules-local-by-default", | ||
"version": "2.0.0", | ||
"version": "2.0.1", | ||
"description": "A CSS Modules transform to make local scope the default", | ||
@@ -5,0 +5,0 @@ "main": "src/index.js", |
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
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
19076
377
0