Skip to content

Commit b85f39f

Browse files
committed
Remove keyframes in favor of postcss-icss-keyframes
1 parent 4fd6303 commit b85f39f

File tree

4 files changed

+480
-330
lines changed

4 files changed

+480
-330
lines changed

package.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,21 @@
2020
},
2121
"lint-staged": {
2222
"*.js": [
23+
"eslint",
2324
"prettier --single-quote --no-semi --write",
2425
"git add"
2526
]
2627
},
28+
"eslintConfig": {
29+
"parserOptions": {
30+
"ecmaVersion": 6,
31+
"sourceType": "module"
32+
},
33+
"env": {
34+
"es6": true
35+
},
36+
"extends": "eslint:recommended"
37+
},
2738
"babel": {
2839
"presets": [
2940
[
@@ -52,6 +63,7 @@
5263
"babel-preset-env": "^1.5.1",
5364
"codecov.io": "^0.1.2",
5465
"coveralls": "^2.11.2",
66+
"eslint": "^3.19.0",
5567
"husky": "^0.13.3",
5668
"jest": "^20.0.3",
5769
"lint-staged": "^3.4.2",

src/index.js

Lines changed: 40 additions & 215 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
var postcss = require('postcss')
2-
var Tokenizer = require('css-selector-tokenizer')
1+
/* eslint-env node */
2+
import postcss from 'postcss'
3+
import Tokenizer from 'css-selector-tokenizer'
4+
5+
const plugin = 'postcss-modules-local-by-default'
36

47
function normalizeNodeArray(nodes) {
58
var array = []
@@ -158,222 +161,44 @@ function localizeNode(node, context) {
158161
return node
159162
}
160163

161-
function localizeDeclNode(node, context) {
162-
var newNode
163-
switch (node.type) {
164-
case 'item':
165-
if (context.localizeNextItem) {
166-
newNode = Object.create(node)
167-
newNode.name = ':local(' + newNode.name + ')'
168-
context.localizeNextItem = false
169-
return newNode
170-
}
171-
break
172-
173-
case 'nested-item':
174-
var newNodes = node.nodes.map(function(n) {
175-
return localizeDeclValue(n, context)
176-
})
177-
node = Object.create(node)
178-
node.nodes = newNodes
179-
break
180-
}
181-
return node
182-
}
183-
184-
function localizeDeclValue(valueNode, context) {
185-
var newValueNode = Object.create(valueNode)
186-
newValueNode.nodes = valueNode.nodes.map(function(node) {
187-
return localizeDeclNode(node, context)
188-
})
189-
return newValueNode
190-
}
191-
192-
function localizeAnimationShorthandDeclValueNodes(nodes, context) {
193-
var validIdent = (validIdent = /^-?[_a-z][_a-z0-9-]*$/i)
194-
195-
/*
196-
The spec defines some keywords that you can use to describe properties such as the timing
197-
function. These are still valid animation names, so as long as there is a property that accepts
198-
a keyword, it is given priority. Only when all the properties that can take a keyword are
199-
exhausted can the animation name be set to the keyword. I.e.
200-
201-
animation: infinite infinite;
202-
203-
The animation will repeat an infinite number of times from the first argument, and will have an
204-
animation name of infinite from the second.
205-
*/
206-
var animationKeywords = {
207-
$alternate: 1,
208-
'$alternate-reverse': 1,
209-
$backwards: 1,
210-
$both: 1,
211-
$ease: 1,
212-
'$ease-in': 1,
213-
'$ease-in-out': 1,
214-
'$ease-out': 1,
215-
$forwards: 1,
216-
$infinite: 1,
217-
$linear: 1,
218-
$none: Infinity, // No matter how many times you write none, it will never be an animation name
219-
$normal: 1,
220-
$paused: 1,
221-
$reverse: 1,
222-
$running: 1,
223-
'$step-end': 1,
224-
'$step-start': 1,
225-
$initial: Infinity,
226-
$inherit: Infinity,
227-
$unset: Infinity
164+
module.exports = postcss.plugin(plugin, (options = {}) => css => {
165+
if (
166+
options.mode &&
167+
options.mode !== 'global' &&
168+
options.mode !== 'local' &&
169+
options.mode !== 'pure'
170+
) {
171+
throw Error(
172+
'options.mode must be either "global", "local" or "pure" (default "local")'
173+
)
228174
}
229-
230-
var didParseAnimationName = false
231-
var parsedAnimationKeywords = {}
232-
return nodes.map(function(valueNode) {
233-
var value = valueNode.type === 'item' ? valueNode.name.toLowerCase() : null
234-
235-
var shouldParseAnimationName = false
236-
237-
if (!didParseAnimationName && value && validIdent.test(value)) {
238-
if ('$' + value in animationKeywords) {
239-
parsedAnimationKeywords['$' + value] = '$' + value in
240-
parsedAnimationKeywords
241-
? parsedAnimationKeywords['$' + value] + 1
242-
: 0
243-
244-
shouldParseAnimationName =
245-
parsedAnimationKeywords['$' + value] >= animationKeywords['$' + value]
246-
} else {
247-
shouldParseAnimationName = true
248-
}
175+
var pureMode = options.mode === 'pure'
176+
var globalMode = options.mode === 'global'
177+
css.walkRules(function(rule) {
178+
if (rule.parent.type === 'atrule' && /keyframes$/.test(rule.parent.name)) {
179+
// ignore keyframe rules
180+
return
249181
}
250-
251-
var subContext = {
252-
options: context.options,
253-
global: context.global,
254-
localizeNextItem: shouldParseAnimationName && !context.global
182+
var selector = Tokenizer.parse(rule.selector)
183+
var context = {
184+
options: options,
185+
global: globalMode,
186+
hasPureGlobals: false
255187
}
256-
return localizeDeclNode(valueNode, subContext)
257-
})
258-
}
259-
260-
function localizeAnimationShorthandDeclValues(valuesNode, decl, context) {
261-
var newValuesNode = Object.create(valuesNode)
262-
newValuesNode.nodes = valuesNode.nodes.map(function(valueNode, index) {
263-
var newValueNode = Object.create(valueNode)
264-
newValueNode.nodes = localizeAnimationShorthandDeclValueNodes(
265-
valueNode.nodes,
266-
context
267-
)
268-
return newValueNode
269-
})
270-
decl.value = Tokenizer.stringifyValues(newValuesNode)
271-
}
272-
273-
function localizeDeclValues(localize, valuesNode, decl, context) {
274-
var newValuesNode = Object.create(valuesNode)
275-
newValuesNode.nodes = valuesNode.nodes.map(function(valueNode) {
276-
var subContext = {
277-
options: context.options,
278-
global: context.global,
279-
localizeNextItem: localize && !context.global
188+
var newSelector
189+
try {
190+
newSelector = localizeNode(selector, context)
191+
} catch (e) {
192+
throw rule.error(e.message)
280193
}
281-
return localizeDeclValue(valueNode, subContext)
282-
})
283-
decl.value = Tokenizer.stringifyValues(newValuesNode)
284-
}
285-
286-
function localizeDecl(decl, context) {
287-
var valuesNode = Tokenizer.parseValues(decl.value)
288-
289-
var isAnimation = /animation?$/.test(decl.prop)
290-
if (isAnimation)
291-
return localizeAnimationShorthandDeclValues(valuesNode, decl, context)
292-
293-
var isAnimationName = /animation(-name)?$/.test(decl.prop)
294-
if (isAnimationName)
295-
return localizeDeclValues(true, valuesNode, decl, context)
296-
297-
return localizeDeclValues(false, valuesNode, decl, context)
298-
}
299-
300-
module.exports = postcss.plugin(
301-
'postcss-modules-local-by-default',
302-
(options = {}) => (css, result) => {
303-
if (
304-
options.mode &&
305-
options.mode !== 'global' &&
306-
options.mode !== 'local' &&
307-
options.mode !== 'pure'
308-
) {
309-
throw Error(
310-
'options.mode must be either "global", "local" or "pure" (default "local")'
194+
if (pureMode && context.hasPureGlobals) {
195+
throw rule.error(
196+
'Selector "' +
197+
Tokenizer.stringify(selector) +
198+
'" is not pure ' +
199+
'(pure selectors must contain at least one local class or id)'
311200
)
312201
}
313-
var pureMode = options.mode === 'pure'
314-
var globalMode = options.mode === 'global'
315-
css.walkAtRules(function(atrule) {
316-
if (/keyframes$/.test(atrule.name)) {
317-
var globalMatch = /^\s*:global\s*\((.+)\)\s*$/.exec(atrule.params)
318-
var localMatch = /^\s*:local\s*\((.+)\)\s*$/.exec(atrule.params)
319-
var globalKeyframes = globalMode
320-
if (globalMatch) {
321-
if (pureMode) {
322-
throw atrule.error(
323-
'@keyframes :global(...) is not allowed in pure mode'
324-
)
325-
}
326-
atrule.params = globalMatch[1]
327-
globalKeyframes = true
328-
} else if (localMatch) {
329-
atrule.params = localMatch[0]
330-
globalKeyframes = false
331-
} else if (!globalMode) {
332-
atrule.params = ':local(' + atrule.params + ')'
333-
}
334-
atrule.walkDecls(function(decl) {
335-
localizeDecl(decl, {
336-
options: options,
337-
global: globalKeyframes
338-
})
339-
})
340-
}
341-
})
342-
css.walkRules(function(rule) {
343-
if (
344-
rule.parent.type === 'atrule' &&
345-
/keyframes$/.test(rule.parent.name)
346-
) {
347-
// ignore keyframe rules
348-
return
349-
}
350-
var selector = Tokenizer.parse(rule.selector)
351-
var context = {
352-
options: options,
353-
global: globalMode,
354-
hasPureGlobals: false
355-
}
356-
var newSelector
357-
try {
358-
newSelector = localizeNode(selector, context)
359-
} catch (e) {
360-
throw rule.error(e.message)
361-
}
362-
if (pureMode && context.hasPureGlobals) {
363-
throw rule.error(
364-
'Selector "' +
365-
Tokenizer.stringify(selector) +
366-
'" is not pure ' +
367-
'(pure selectors must contain at least one local class or id)'
368-
)
369-
}
370-
// Less-syntax mixins parse as rules with no nodes
371-
if (rule.nodes) {
372-
rule.nodes.forEach(function(decl) {
373-
localizeDecl(decl, context)
374-
})
375-
}
376-
rule.selector = Tokenizer.stringify(newSelector)
377-
})
378-
}
379-
)
202+
rule.selector = Tokenizer.stringify(newSelector)
203+
})
204+
})

0 commit comments

Comments
 (0)