From b18c377187d93daa984d714a81101f17c7a53dbd Mon Sep 17 00:00:00 2001 From: evilebottnawi Date: Fri, 23 Nov 2018 14:39:54 +0300 Subject: [PATCH 1/2] chore: refactor --- .eslintrc | 4 +- CHANGELOG.md | 6 ++ index.js | 242 ++++++++++++++++++++++++++++++--------------------- 3 files changed, 153 insertions(+), 99 deletions(-) diff --git a/.eslintrc b/.eslintrc index 5bae42e..ffd436e 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,9 +1,11 @@ { + "parserOptions": { + "ecmaVersion": 2018 + }, "env": { "node": true }, "rules": { - "strict": [2, "never"], "quotes": [2, "single"] } } diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cd020b..bbe372a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [2.0.1] - 2018-11-23 +### Changed +- Handle uppercase `keyframes` at rule. + ## [2.0.0] - 2018-11-23 ### Changed - Drop support `nodejs@4`. @@ -72,3 +76,5 @@ This project adheres to [Semantic Versioning](http://semver.org/). [0.0.9]: https://github.com/postcss-modules-local-by-default/compare/v0.0.8...v0.0.9 [0.0.10]: https://github.com/postcss-modules-local-by-default/compare/v0.0.9...v0.0.10 [0.0.11]: https://github.com/postcss-modules-local-by-default/compare/v0.0.10...v0.0.11 +[0.0.11]: 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 diff --git a/index.js b/index.js index 09be822..4c5c7e1 100644 --- a/index.js +++ b/index.js @@ -1,51 +1,57 @@ -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(); } return array; } 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, lastWasSpacing: true, hasLocals: false, explicit: false }; 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; } return n; @@ -64,7 +70,7 @@ function localizeNode(node, context) { break; case 'spacing': - if(context.ignoreNextSpacing) { + if (context.ignoreNextSpacing) { context.ignoreNextSpacing = false; context.lastWasSpacing = false; context.enforceNoSpacing = false; @@ -74,26 +80,38 @@ function localizeNode(node, context) { return node; 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; return null; } break; 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, hasLocals: false, explicit: true @@ -118,14 +136,14 @@ function localizeNode(node, context) { node = Object.create(node); node.nodes = normalizeNodeArray(newNodes); } - if(subContext.hasLocals) { + if (subContext.hasLocals) { context.hasLocals = true; } break; case 'id': case 'class': - if(!context.global) { + if (!context.global) { node = { type: 'nested-pseudo-class', name: 'local', @@ -144,10 +162,10 @@ function localizeNode(node, context) { } 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); newNode.name = ':local(' + newNode.name + ')'; context.localizeNextItem = false; @@ -156,7 +174,7 @@ function localizeDeclNode(node, context) { break; case 'nested-item': - var newNodes = node.nodes.map(function(n) { + const newNodes = node.nodes.map(function(n) { return localizeDeclValue(n, context); }); node = Object.create(node); @@ -164,7 +182,7 @@ function localizeDeclNode(node, context) { break; case 'url': - if(context.options && context.options.rewriteUrl) { + if (context.options && context.options.rewriteUrl) { newNode = Object.create(node); newNode.url = context.options.rewriteUrl(context.global, node.url); return newNode; @@ -175,7 +193,7 @@ function localizeDeclNode(node, context) { } function localizeDeclValue(valueNode, context) { - var newValueNode = Object.create(valueNode); + const newValueNode = Object.create(valueNode); newValueNode.nodes = valueNode.nodes.map(function(node) { return localizeDeclNode(node, context); }); @@ -183,7 +201,7 @@ function localizeDeclValue(valueNode, context) { } function localizeAnimationShorthandDeclValueNodes(nodes, context) { - var validIdent = validIdent = /^-?[_a-z][_a-z0-9-]*$/i; + let validIdent = /^-?[_a-z][_a-z0-9-]*$/i; /* The spec defines some keywords that you can use to describe properties such as the timing @@ -196,52 +214,54 @@ function localizeAnimationShorthandDeclValueNodes(nodes, context) { The animation will repeat an infinite number of times from the first argument, and will have an animation name of infinite from the second. */ - 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 = {}; + let 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 { shouldParseAnimationName = true; } } - var subContext = { + const subContext = { options: context.options, global: context.global, localizeNextItem: shouldParseAnimationName && !context.global @@ -251,19 +271,22 @@ function localizeAnimationShorthandDeclValueNodes(nodes, context) { } 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; }); decl.value = Tokenizer.stringifyValues(newValuesNode); } 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, global: context.global, localizeNextItem: localize && !context.global @@ -274,44 +297,60 @@ function localizeDeclValues(localize, valuesNode, decl, context) { } function localizeDecl(decl, context) { - var valuesNode = Tokenizer.parseValues(decl.value); + const valuesNode = Tokenizer.parseValues(decl.value); + + const isAnimation = /animation?$/i.test(decl.prop); - var isAnimation = /animation?$/.test(decl.prop); - if (isAnimation) return localizeAnimationShorthandDeclValues(valuesNode, decl, context); + if (isAnimation) { + return localizeAnimationShorthandDeclValues(valuesNode, decl, context); + } + + const isAnimationName = /animation(-name)?$/i.test(decl.prop); - var isAnimationName = /animation(-name)?$/.test(decl.prop); - if (isAnimationName) return localizeDeclValues(true, valuesNode, decl, context); + 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 + ')'; } atrule.walkDecls(function(decl) { @@ -320,9 +359,9 @@ module.exports = postcss.plugin('postcss-modules-local-by-default', function (op global: globalKeyframes }); }); - } else if(atrule.nodes) { + } else if (atrule.nodes) { atrule.nodes.forEach(function(decl) { - if(decl.type === 'decl') { + if (decl.type === 'decl') { localizeDecl(decl, { options: options, global: globalMode @@ -332,25 +371,32 @@ module.exports = postcss.plugin('postcss-modules-local-by-default', function (op } }); 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, global: globalMode, hasPureGlobals: false }; - 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)' + ); } // Less-syntax mixins parse as rules with no nodes if (rule.nodes) { From aefcd4b7d49e2def5a626b1ce30e0db6932c221b Mon Sep 17 00:00:00 2001 From: evilebottnawi Date: Fri, 23 Nov 2018 14:40:52 +0300 Subject: [PATCH 2/2] chore: refactor --- CHANGELOG.md | 2 +- index.js | 4 +- package.json | 2 +- test.js | 124 ++++++++++++++++++++++++++++++--------------------- 4 files changed, 78 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bbe372a..859f781 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,5 +76,5 @@ This project adheres to [Semantic Versioning](http://semver.org/). [0.0.9]: https://github.com/postcss-modules-local-by-default/compare/v0.0.8...v0.0.9 [0.0.10]: https://github.com/postcss-modules-local-by-default/compare/v0.0.9...v0.0.10 [0.0.11]: https://github.com/postcss-modules-local-by-default/compare/v0.0.10...v0.0.11 -[0.0.11]: https://github.com/postcss-modules-local-by-default/compare/v1.3.1...v2.0.0 +[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 diff --git a/index.js b/index.js index 4c5c7e1..98a8c09 100644 --- a/index.js +++ b/index.js @@ -201,7 +201,7 @@ function localizeDeclValue(valueNode, context) { } function localizeAnimationShorthandDeclValueNodes(nodes, context) { - let validIdent = /^-?[_a-z][_a-z0-9-]*$/i; + const validIdent = /^-?[_a-z][_a-z0-9-]*$/i; /* The spec defines some keywords that you can use to describe properties such as the timing @@ -238,7 +238,7 @@ function localizeAnimationShorthandDeclValueNodes(nodes, context) { $unset: Infinity }; - let didParseAnimationName = false; + const didParseAnimationName = false; const parsedAnimationKeywords = {}; return nodes.map(function(valueNode) { const value = diff --git a/package.json b/package.json index 5d21151..f8158cb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "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", "main": "src/index.js", "engines": { diff --git a/test.js b/test.js index 8464c22..ca13592 100644 --- a/test.js +++ b/test.js @@ -1,9 +1,11 @@ -var test = require('tape'); -var postcss = require('postcss'); -var plugin = require('./'); -var name = require('./package.json').name; +'use strict'; -var tests = [ +const test = require('tape'); +const postcss = require('postcss'); +const plugin = require('./'); +const name = require('./package.json').name; + +const tests = [ { should: 'scope selectors', input: '.foobar {}', @@ -157,7 +159,8 @@ var tests = [ { should: 'localize animation with vendor prefix', input: '.foo { -webkit-animation: bar; animation: bar; }', - expected: ':local(.foo) { -webkit-animation: :local(bar); animation: :local(bar); }' + expected: + ':local(.foo) { -webkit-animation: :local(bar); animation: :local(bar); }' }, { should: 'not localize other rules', @@ -171,8 +174,10 @@ var tests = [ }, { should: 'handle a complex animation rule', - input: '.foo { animation: foo, bar 5s linear 2s infinite alternate, barfoo 1s; }', - expected: ':local(.foo) { animation: :local(foo), :local(bar) 5s linear 2s infinite alternate, :local(barfoo) 1s; }' + input: + '.foo { animation: foo, bar 5s linear 2s infinite alternate, barfoo 1s; }', + expected: + ':local(.foo) { animation: :local(foo), :local(bar) 5s linear 2s infinite alternate, :local(barfoo) 1s; }' }, { should: 'handle animations where the first value is not the animation name', @@ -180,14 +185,18 @@ var tests = [ expected: ':local(.foo) { animation: 1s :local(foo); }' }, { - should: 'handle animations where the first value is not the animation name whilst also using keywords', + should: + 'handle animations where the first value is not the animation name whilst also using keywords', input: '.foo { animation: 1s normal ease-out infinite foo; }', - expected: ':local(.foo) { animation: 1s normal ease-out infinite :local(foo); }' + expected: + ':local(.foo) { animation: 1s normal ease-out infinite :local(foo); }' }, { should: 'handle animations with custom timing functions', - input: '.foo { animation: 1s normal cubic-bezier(0.25, 0.5, 0.5. 0.75) foo; }', - expected: ':local(.foo) { animation: 1s normal cubic-bezier(0.25, 0.5, 0.5. 0.75) :local(foo); }' + input: + '.foo { animation: 1s normal cubic-bezier(0.25, 0.5, 0.5. 0.75) foo; }', + expected: + ':local(.foo) { animation: 1s normal cubic-bezier(0.25, 0.5, 0.5. 0.75) :local(foo); }' }, { should: 'handle animations whose names are keywords', @@ -202,7 +211,8 @@ var tests = [ { should: 'handle "constructor" as animation name', input: '.foo { animation: constructor constructor; }', - expected: ':local(.foo) { animation: :local(constructor) :local(constructor); }' + expected: + ':local(.foo) { animation: :local(constructor) :local(constructor); }' }, { should: 'default to global when mode provided', @@ -247,7 +257,8 @@ var tests = [ { should: 'localize keyframes', input: '@keyframes foo { from { color: red; } to { color: blue; } }', - expected: '@keyframes :local(foo) { from { color: red; } to { color: blue; } }' + expected: + '@keyframes :local(foo) { from { color: red; } to { color: blue; } }' }, { should: 'localize keyframes in global default mode', @@ -257,8 +268,10 @@ var tests = [ }, { should: 'localize explicit keyframes', - input: '@keyframes :local(foo) { 0% { color: red; } 33.3% { color: yellow; } 100% { color: blue; } } @-webkit-keyframes :global(bar) { from { color: red; } to { color: blue; } }', - expected: '@keyframes :local(foo) { 0% { color: red; } 33.3% { color: yellow; } 100% { color: blue; } } @-webkit-keyframes bar { from { color: red; } to { color: blue; } }' + input: + '@keyframes :local(foo) { 0% { color: red; } 33.3% { color: yellow; } 100% { color: blue; } } @-webkit-keyframes :global(bar) { from { color: red; } to { color: blue; } }', + expected: + '@keyframes :local(foo) { 0% { color: red; } 33.3% { color: yellow; } 100% { color: blue; } } @-webkit-keyframes bar { from { color: red; } to { color: blue; } }' }, { should: 'ignore :export statements', @@ -274,7 +287,8 @@ var tests = [ should: 'compile in pure mode', input: ':global(.foo).bar, [type="radio"] ~ .label, :not(.foo), #bar {}', options: { mode: 'pure' }, - expected: '.foo:local(.bar), [type="radio"] ~ :local(.label), :not(:local(.foo)), :local(#bar) {}' + expected: + '.foo:local(.bar), [type="radio"] ~ :local(.label), :not(:local(.foo)), :local(#bar) {}' }, { should: 'compile explict global element', @@ -381,16 +395,19 @@ var tests = [ }, { should: 'not modify urls without option', - input: '.a { background: url(./image.png); }\n' + + input: + '.a { background: url(./image.png); }\n' + ':global .b { background: url(image.png); }\n' + '.c { background: url("./image.png"); }', - expected: ':local(.a) { background: url(./image.png); }\n' + + expected: + ':local(.a) { background: url(./image.png); }\n' + '.b { background: url(image.png); }\n' + ':local(.c) { background: url("./image.png"); }' }, { should: 'rewrite url in local block', - input: '.a { background: url(./image.png); }\n' + + input: + '.a { background: url(./image.png); }\n' + ':global .b { background: url(image.png); }\n' + '.c { background: url("./image.png"); }\n' + '.d { background: -webkit-image-set(url("./image.png") 1x, url("./image2x.png") 2x); }\n' + @@ -401,16 +418,17 @@ var tests = [ '@keyframes ani2 { 0% { src: url("./image.png"); } }', options: { rewriteUrl: function(global, url) { - var mode = global ? 'global' : 'local'; + const mode = global ? 'global' : 'local'; return '(' + mode + ')' + url + '"' + mode + '"'; } }, - expected: ':local(.a) { background: url((local\\)./image.png\\\"local\\\"); }\n' + - '.b { background: url((global\\)image.png\\\"global\\\"); }\n' + - ':local(.c) { background: url(\"(local)./image.png\\\"local\\\"\"); }\n' + - ':local(.d) { background: -webkit-image-set(url(\"(local)./image.png\\\"local\\\"\") 1x, url(\"(local)./image2x.png\\\"local\\\"\") 2x); }\n' + - '@font-face { src: url(\"(local)./font.woff\\\"local\\\"\"); }\n' + - '@-webkit-font-face { src: url(\"(local)./font.woff\\\"local\\\"\"); }\n' + + expected: + ':local(.a) { background: url((local\\)./image.png\\"local\\"); }\n' + + '.b { background: url((global\\)image.png\\"global\\"); }\n' + + ':local(.c) { background: url("(local)./image.png\\"local\\""); }\n' + + ':local(.d) { background: -webkit-image-set(url("(local)./image.png\\"local\\"") 1x, url("(local)./image2x.png\\"local\\"") 2x); }\n' + + '@font-face { src: url("(local)./font.woff\\"local\\""); }\n' + + '@-webkit-font-face { src: url("(local)./font.woff\\"local\\""); }\n' + '@media screen { :local(.a) { src: url("(local)./image.png\\"local\\""); } }\n' + '@keyframes ani1 { 0% { src: url("(global)image.png\\"global\\""); } }\n' + '@keyframes :local(ani2) { 0% { src: url("(local)./image.png\\"local\\""); } }' @@ -423,40 +441,46 @@ var tests = [ { should: 'not crash on a rule without nodes', input: (function() { - var inner = postcss.rule({ selector: '.b', ruleWithoutBody: true }); - var outer = postcss.rule({ selector: '.a' }).push(inner); - var root = postcss.root().push(outer); + const inner = postcss.rule({ selector: '.b', ruleWithoutBody: true }); + const outer = postcss.rule({ selector: '.a' }).push(inner); + const root = postcss.root().push(outer); inner.nodes = undefined; return root; })(), // postcss-less's stringify would honor `ruleWithoutBody` and omit the trailing `{}` expected: ':local(.a) {\n :local(.b) {}\n}' } - ]; -function process (css, options) { - return postcss(plugin(options)).process(css).css; +function process(css, options) { + return postcss(plugin(options)).process(css).css; } -test(name, function (t) { - t.plan(tests.length); +test(name, function(t) { + t.plan(tests.length); - tests.forEach(function (testCase) { - var options = testCase.options; - if(testCase.error) { - t.throws(function() { - process(testCase.input, options); - }, testCase.error, 'should ' + testCase.should); - } else { - t.equal(process(testCase.input, options), testCase.expected, 'should ' + testCase.should); - } - }); + tests.forEach(function(testCase) { + const options = testCase.options; + if (testCase.error) { + t.throws( + function() { + process(testCase.input, options); + }, + testCase.error, + 'should ' + testCase.should + ); + } else { + t.equal( + process(testCase.input, options), + testCase.expected, + 'should ' + testCase.should + ); + } + }); }); - -test('should use the postcss plugin api', function (t) { - t.plan(2); - t.ok(plugin().postcssVersion, 'should be able to access version'); - t.equal(plugin().postcssPlugin, name, 'should be able to access name'); +test('should use the postcss plugin api', function(t) { + t.plan(2); + t.ok(plugin().postcssVersion, 'should be able to access version'); + t.equal(plugin().postcssPlugin, name, 'should be able to access name'); });