Skip to content

Instantly share code, notes, and snippets.

@jonathantneal
Last active April 28, 2020 13:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jonathantneal/6333494ea6dcbd5c10f1128b4b3e1a58 to your computer and use it in GitHub Desktop.
Save jonathantneal/6333494ea6dcbd5c10f1128b4b3e1a58 to your computer and use it in GitHub Desktop.
// original size: 11659 / gzipped size: 3401
voicss = (function(A, F, O, S) {
/* Helpers
/* ====================================================================== */
var arrp = A.prototype
var objectAssign = O.assign || function(target) {
for (var i = 0, source; (source = ++i in arguments && O(arguments[i])); ) for (var name in source) objectHasOwnProperty(source, name) && (target[name] = source[name])
return target
}
var objectCreate = O.create
var objectDefineProperty = Object.defineProperty
var objectGetPrototype = O.getPrototypeOf
var objectHasOwnProperty = F.call.bind(O.hasOwnProperty)
function splice(own, start, count, items) {
return arrp.splice.bind(own, start, count).apply(null, items)
}
function asString() {
return arrp.map.call(arguments, function (value) {
return value == null ? '' : S(value)
}).join('')
}
function defineProp(object, name, bitmask, valueOrGetter, setter) {
var descriptor = { configurable: bitmask & 2, enumerable: bitmask & 1 }
if (bitmask & 4) descriptor.writable = true
if (bitmask & 8) {
descriptor.get = valueOrGetter
descriptor.set = setter
} else descriptor.value = valueOrGetter
return objectDefineProperty(object, name, descriptor)
}
function defineProps(object, props) {
for (var name in props) defineProp(object, name, props[name][0], props[name][1])
return object
}
function createClass(name, Class, Super, proto) {
return (
types[name] = (
(
Class = F('a,s,f,t', 'return f=function ' + name + '(){return a.apply(t=this instanceof f?this:s(f.prototype),arguments),t}')(Class, objectCreate)
).prototype = defineProps(
objectCreate(Super.prototype),
objectAssign({}, proto, { constructor: [6, Class] })
)
).constructor
)
}
function createArray() {
var array = []
arrp.push.apply(array, arguments)
return defineProp(array, 'toString', 6, function () { return this.join('') })
}
function getFilteredNodes(nodes, parent) {
return arrp.reduce.call(nodes, function (nodes, node) {
nodes.push.apply(
nodes,
node !== O(node)
? getFilteredNodes(parse(node).value, parent)
: node instanceof CSSNode
? setParent(node) || [node]
: []
)
return nodes
}, [])
function setParent(node) {
if (parent) node.parent = parent
}
}
function defineNode(node, definers, props) {
for (var name in definers) defineProp(node, name, 7, definers[name])
defineProp(node, 'parent', 6, null)
defineProp(node, 'source', 6, { start: null, end: null })
return objectAssign(node, props)
}
function trimArray(array) {
while (array[0] instanceof CSSWhitespace) array.shift()
while (array[array.length - 1] instanceof CSSWhitespace) array.pop()
return array
}
/* Parser
/* ====================================================================== */
function parse(css) {
css = S(css)
var cssRegExp = /\/\*((?:[^*]|\*[^\/])*)\*\/|([ \t\n\f\r]+)|"((?:[^"\\\n\f\r]|\\\r\n|\\[\W\w])*)("|\n|\f|\r|$)|'((?:[^'\\\n\f\r]|\\\r\n|\\[\W\w])*)('|\n|\f|\r|$)|#((?:[-\w]|[^\x00-\x7F]|\\[^\n\f\r])+)|([+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[Ee]-?\d+)?)|(-?(?:[-A-Z_a-z]|[^\x00-\x7F]|\\[^\n\f\r])(?:[-\w]|[^\x00-\x7F]|\\[^\n\f\r])*)|([\uD800-\uDBFF][\uDC00-\uDFFF]|[\W\w])/g
var cssMatches
var root = CSSBlock({ source: { start: 0, end: null, input: css } })
var parent = root
var last = {}
var lastIndex = 0
var source
while ((cssMatches = cssRegExp.exec(css)) != null) {
source = {
start: lastIndex,
end: (
lastIndex = cssRegExp.lastIndex
)
}
parser.apply(cssRegExp, cssMatches)
}
return root
function parser(delimiter, comment, whitespace, stringDoubleQuote, stringDoubleQuoteDelimiterEnd, stringSingleQuote, stringSingleQuoteDelimiterEnd, hashIdentifier, number, nameIdentifier) {
if (comment != null) {
append(CSSComment, { value: comment })
} else if (whitespace != null) {
append(CSSWhitespace, { value: whitespace })
} else if (stringDoubleQuote != null) {
append(CSSString, { value: stringDoubleQuote, delimiterStart: '"', delimiterEnd: stringDoubleQuoteDelimiterEnd })
} else if (stringSingleQuote != null) {
append(CSSString, { value: stringSingleQuote, delimiterStart: "'", delimiterEnd: stringSingleQuoteDelimiterEnd })
} else if (hashIdentifier != null) {
append(CSSHashIdentifier, { value: hashIdentifier })
} else if (number != null) {
append(CSSNumber, { value: number, unit: '' })
} else if (nameIdentifier != null) {
if (last instanceof CSSNumber) {
last.unit = nameIdentifier
} else if (last.value === '@') {
splice(parent.value, -1, 1, [ last = CSSAtIdentifier({ parent: parent, value: nameIdentifier }) ])
} else {
append(CSSNameIdentifier, { value: nameIdentifier })
}
} else {
if (delimiter === '%' && last instanceof CSSNumber) {
last.unit = delimiter
} else if (delimiter === '(' && last instanceof CSSNameIdentifier) {
splice(parent.value, -1, 1, [parent = last = CSSFunction({ name: last.value, delimiterStart: delimiter, parent: parent }) ])
} else if (delimiter === '(' || delimiter === '[' || delimiter === '{') {
parent = append(CSSBlock, { delimiterStart: delimiter, parent: parent })
} else if ((delimiter === ')' && parent.delimiterStart === '(') || (delimiter === ']' && parent.delimiterStart === '[') || (delimiter === '}' && parent.delimiterStart === '{')) {
parent.delimiterEnd = delimiter
parent = parent.parent
} else {
append(CSSDelimiter, { value: delimiter })
}
}
}
function append(CSSClass, details) {
parent.value.push(last = CSSClass(details))
return objectAssign(last, {
parent: parent,
source: source
})
}
}
/* Descriptors
/* ====================================================================== */
var valueDescriptor = {
clone: [6, function clone(props, isPlain) {
var source = []
var clones = []
return objectAssign(cloneValue(this), props)
function cloneValue(value) {
return value === O(value) ? cloneObject(value) : value
}
function cloneObject(object) {
var cloneIndex
var cloned
if (~(cloneIndex = clones.indexOf(object))) cloned = clones[cloneIndex]
else source.push(object) && clones.push(cloned = A.isArray(object) ? createArray() : isPlain ? { type: null } : objectCreate(objectGetPrototype(object)))
for (var name in object) {
if (isPlain || objectHasOwnProperty(object, name)) {
cloned[name] = cloneValue(object[name])
}
}
return cloned
}
}],
after: [6, function after() {
var parent = this.parent
var value = parent && parent.value
var index = value && value.indexOf(this)
if (~index) splice(value, index, 0, getFilteredNodes(arguments, parent))
return this
}],
appendTo: [6, function appendTo(parent) {
if (parent) parent.append(this)
return this
}],
assign: [6, function assign() {
return objectAssign.bind(null, this).apply(null, arguments)
}],
before: [6, function before() {
var parent = this.parent
var value = parent && parent.value
var index = value && value.indexOf(this)
if (~index) splice(value, index, 0, getFilteredNodes(arguments, parent))
return this
}],
define: [6, function define() {
arrp.forEach.call(arguments, defineProps.bind(null, this))
return this
}],
parent: [6, null],
prependTo: [6, function prependTo(parent) {
if (parent) parent.prepend(this)
return this
}],
replaceWith: [6, function replaceWith() {
if (this.parent) this.parent.replace.bind(this.parent, this).apply(null, arguments)
return this
}],
root: [10, function () {
var root = this
do { root = root.parent } while (root)
return root
}],
toJSON: [6, function toJSON() {
return this.clone({}, true)
}],
toString: [6, function toString() {
return asString(this.value)
}],
type: [11, function () {
return this.constructor.name
}],
valueOf: [6, function valueOf() {
return this.clone({}, true)
}],
walk: [6, function walk(cbBefore, cbAfter) {
walkNode(this)
return this
function walkNode(parent) {
return (
!A.isArray(parent.value) ||
parent.value.slice(0).every(function (child, index) {
return (
typeof cbBefore !== 'function' ||
cbBefore(child, index) !== false ||
(
walkNode(child) &&
(
typeof cbAfter !== 'function' ||
cbAfter(child, index) !== false
)
)
)
})
)
}
}]
}
var blockDescriptor = {
append: [6, function append() {
arrp.push.apply(this.value, getFilteredNodes(arguments, this))
return this
}],
first: [10, function () {
return this.value[0] || null
}],
last: [10, function () {
return this.value[this.value.length - 1] || null
}],
prepend: [6, function prepend() {
arrp.unshift.apply(this.value, getFilteredNodes(arguments, this))
return this
}],
remove: [6, function remove(removee) {
var index = this.value.indexOf(removee)
if (~index) {
removee.parent = null
splice(this.value, index, 1, [])
}
return this
}],
replace: [6, function replace(replacee) {
var index = this.value.indexOf(replacee)
if (~index) {
replacee.parent = null
splice(this.value, index, 1, getFilteredNodes(arguments, this))
}
return this
}],
toString: [6, function toString() {
return asString(this.delimiterStart, this.value, this.delimiterEnd)
}]
}
/* Nodes
/* ====================================================================== */
var types = {}
function cssValueConstructor(props) {
defineNode(this, { value: null }, props)
}
function cssValueStringConstructor(props) {
defineNode(this, { value: '' }, props)
}
function cssValueArrayDelimiteredConstructor(props) {
defineNode(this, { value: createArray(), delimiterStart: '', delimiterEnd: '' }, props)
}
var CSSNode = createClass('CSSNode', function CSSNode(props) {
defineNode(this, null, props)
}, O)
var CSSValue = createClass('CSSValue', cssValueConstructor, CSSNode, valueDescriptor)
var CSSComment = createClass('CSSComment', function CSSComment(props) {
defineNode(this, { value: null, delimiterStart: '/*', delimiterEnd: '*/' }, props)
}, CSSValue, {
toString: [6, function toString() {
return asString(this.delimiterStart, this.value, this.delimiterEnd)
}]
})
var CSSWhitespace = createClass('CSSWhitespace', cssValueStringConstructor, CSSValue)
var CSSString = createClass('CSSString', function CSSString(props) {
defineNode(this, { value: '', delimiterStart: '', delimiterEnd: '' }, props)
}, CSSValue, {
toString: [6, function toString() {
return asString(this.delimiterStart, this.value, this.delimiterEnd)
}]
})
var CSSAtIdentifier = createClass('CSSAtIdentifier', cssValueStringConstructor, CSSValue, {
toString: [6, function toString() {
return asString('@', this.value)
}]
})
var CSSHashIdentifier = createClass('CSSHashIdentifier', cssValueStringConstructor, CSSValue, {
toString: [6, function toString() {
return asString('#', this.value)
}]
})
var CSSNameIdentifier = createClass('CSSNameIdentifier', cssValueStringConstructor, CSSValue)
var CSSNumber = createClass('CSSNumber', function CSSNumber(props) {
defineNode(this, { value: '', unit: '' }, props)
}, CSSValue, {
toString: [6, function toString() {
return asString(this.value, this.unit)
}]
})
var CSSDelimiter = createClass('CSSDelimiter', cssValueStringConstructor, CSSValue)
var CSSBlock = createClass('CSSBlock', cssValueArrayDelimiteredConstructor, CSSValue, blockDescriptor)
var CSSFunction = createClass('CSSFunction', function CSSFunction(props) {
defineNode(this, { name: '', value: createArray(), delimiterStart: '(', delimiterEnd: ')' }, props)
}, CSSBlock, {
toString: [6, function toString() {
return asString(this.name, this.delimiterStart, this.value, this.delimiterEnd)
}]
})
/* Elements
/* ====================================================================== */
var CSSElement = createClass('CSSElement', cssValueConstructor, CSSNode, valueDescriptor)
var CSSDeclaration = createClass('CSSDeclaration', function CSSDeclaration(props) {
defineNode(this, { name: createArray(), value: createArray(), delimiterEnd: '' }, props)
}, CSSElement, {
nameText: [10, function () {
return asString(this.name).trim()
}],
valueText: [10, function () {
return asString(this.value).trim()
}],
toString: [6, function toString() {
return asString(this.name, ':', this.value)
}]
})
var CSSRule = createClass('CSSRule', function CSSRule(props) {
defineNode(this, { prelude: createArray(), value: createArray(), delimiterStart: '', delimiterEnd: '' }, props)
}, CSSElement, objectAssign({}, blockDescriptor, {
preludeText: [10, function () {
return asString(this.prelude).trim()
}],
declarations: [10, function () {
return this.value.filter(function (node) {
return node instanceof CSSDeclaration
})
}],
rules: [10, function () {
return this.value.filter(function (node) {
return node instanceof CSSRule
})
}],
toString: [6, function toString() {
return asString(this.prelude, this.delimiterStart, this.value, this.delimiterEnd)
}]
}))
var CSSAtRule = createClass('CSSAtRule', function CSSAtRule(props) {
defineNode(this, { name: createArray(), prelude: createArray(), value: createArray(), delimiterStart: '', delimiterEnd: '' }, props)
}, CSSRule, {
toString: [6, function toString() {
return asString(this.name, this.prelude, this.delimiterStart, this.value, this.delimiterEnd)
}]
})
var CSSStyleRule = createClass('CSSStyleRule', function CSSStyleRule(props) {
defineNode(this, { prelude: createArray(), value: createArray(), delimiterStart: '', delimiterEnd: '' }, props)
}, CSSRule, {
toString: [6, function toString() {
return asString(this.name, this.prelude, this.delimiterStart, this.value, this.delimiterEnd)
}]
})
/* Selectors
/* ========================================================================== */
var CSSSelectorNode = createClass('CSSSelectorNode', cssValueConstructor, CSSElement)
var CSSSimpleSelector = createClass('CSSSimpleSelector', cssValueConstructor, CSSSelectorNode, {
valueText: [10, function () {
return asString(this.value).trim()
}]
})
var CSSTypeSelector = createClass('CSSTypeSelector', cssValueStringConstructor, CSSSimpleSelector)
var CSSIdSelector = createClass('CSSIdSelector', cssValueStringConstructor, CSSSimpleSelector)
var CSSUniversalSelector = createClass('CSSUniversalSelector', cssValueStringConstructor, CSSSimpleSelector)
var CSSClassSelector = createClass('CSSClassSelector', cssValueStringConstructor, CSSSimpleSelector, {
toString: [6, function toString() {
return asString('.', this.value)
}]
})
var CSSPseudoSelector = createClass('CSSPseudoSelector', function CSSPseudoSelector(props) {
defineNode(this, { name: '', value: createArray(), colons: '', delimiterStart: '', delimiterEnd: '' }, props)
}, CSSSimpleSelector, {
toString: [6, function toString() {
return asString(this.colons, this.name, this.delimiterStart, this.value, this.delimiterEnd)
}]
})
var CSSAttributeSelector = createClass('CSSAttributeSelector', function CSSAttributeSelector(props) {
defineNode(this, { name: createArray(), matcher: createArray(), value: createArray(), modifier: createArray() }, props)
}, CSSSimpleSelector, {
toString: [6, function toString() {
return asString(this.name, this.matcher, this.value, this.modifier)
}]
})
var CSSCombinator = createClass('CSSCombinator', cssValueStringConstructor, CSSSelectorNode)
var CSSSelector = createClass('CSSSelector', function CSSSelector(props) {
defineNode(this, { value: createArray() }, props)
}, CSSElement, objectAssign({
valueText: [10, function () {
return asString(this.value)
}]
}, blockDescriptor))
/* Consumers
/* ========================================================================== */
function consumeNodes(css) {
return typeof css === 'string' ? parse(css).value : A.isArray(css) ? css : [css]
}
function consumeCommaSeparatedList(nodes) {
nodes = consumeNodes(nodes)
var arg = CSSBlock()
var args = createArray(arg)
var node
while (node = nodes.shift()) {
if (node.value === ',') trimArray(arg.value) && args.push(arg = CSSBlock())
else arg.value.push(node)
}
trimArray(arg.value)
return args
}
function consumeSpaceSeparatedList(nodes) {
nodes = consumeNodes(nodes)
var args = createArray()
var node
while (node = nodes.shift()) {
if (node instanceof CSSWhitespace) continue
else args.push(node)
}
return args
}
// original size: 433 / gzipped size: 233
function consumeDeclaration(nodes) {
nodes = consumeNodes(nodes)
var undo = createArray()
var declaration = CSSDeclaration()
var declarationName = declaration.name
var declarationValue = declaration.value
var node
// whitespace before declaration name
while ((node = nodes[0]) instanceof CSSComment || node instanceof CSSWhitespace) declarationName.push(nodes.shift())
// declaration name
if (node instanceof CSSNameIdentifier) declarationName.push(nodes.shift())
else return undo
// whitespace after declaration name
while ((node = nodes[0]) instanceof CSSComment || node instanceof CSSWhitespace) declarationName.push(nodes.shift())
// colon
if (node instanceof CSSDelimiter && node.value === ':') nodes.shift()
else return undo
// declaration value until semicolon or end
while ((node = nodes.shift())) {
if (node.value === ';') {
declaration.delimiterEnd = node.value
break
} else declarationValue.push(node)
}
return [ declaration ]
}
function consumeDeclarations(nodes, consumers) {
nodes = consumeNodes(nodes)
var declarations = createArray()
var node
while (node = nodes[0]) {
if (node instanceof CSSNameIdentifier) arrp.push.apply(declarations, consumeDeclaration(nodes))
if (node instanceof CSSAtIdentifier || node.value === '&') arrp.push.apply(declarations, consumeRule(nodes, consumers))
else declarations.push(nodes.shift())
}
return declarations
}
function consumeRule(nodes, consumers) {
nodes = consumeNodes(nodes)
consumers = objectAssign({
CSSAtRule: consumeRules,
CSSStyleRule: consumeDeclarations,
'CSSAtRule@nest': consumeDeclarations,
'CSSAtRule@nest.prelude': consumeSelectors
}, consumers)
var preludeArray1 = createArray()
var preludeArray2 = createArray()
var node
while (node = nodes[0]) {
// consume comments and whitespace
if (node instanceof CSSComment || node instanceof CSSWhitespace) preludeArray1.push(nodes.shift())
// consume an at rule
else if (node instanceof CSSAtIdentifier) {
preludeArray1.push(nodes.shift())
while (node = nodes[0]) {
// consume at at rule ending with a semicolon
if (node instanceof CSSBlock && node.delimiterStart === '{') return prepare(
CSSAtRule(
objectAssign({ name: preludeArray1, prelude: preludeArray2 }, nodes.shift())
)
)
// consume at at rule ending with a block
if (node instanceof CSSDelimiter && node.value === ';') return nodes.shift(), prepare(
CSSAtRule({ name: preludeArray1, prelude: preludeArray2, delimiterEnd: ';' })
)
// consume anything else
preludeArray2.push(nodes.shift())
}
// return everything consumed because this is no rule
arrp.push.apply(preludeArray1, preludeArray2)
break
} else {
// consume an style rule
while (node = nodes[0]) {
if (node instanceof CSSBlock && node.delimiterStart === '{') return prepare(
CSSStyleRule(
objectAssign({ prelude: consumeSelectors(preludeArray1) }, nodes.shift())
)
)
preludeArray1.push(nodes.shift())
}
// return everything consumed because this is no rule
break
}
}
// return everything consumed because this is no rule
return preludeArray1
function prepare(rule) {
var ruleType = rule.type
var ruleName = ruleType + asString(rule.name)
var ruleConsumer = consumers[ruleName] || consumers[ruleType]
var preludeConsumerType = asString(ruleType, '.prelude')
var preludeConsumerName = asString(ruleName, '.prelude')
var preludeConsumer = consumers[preludeConsumerType] || consumers[preludeConsumerName]
if (ruleType === 'CSSStyleRule') objectAssign(consumers, {
CSSAtRule: consumeDeclarations,
CSSStyleRule: consumeDeclarations
})
if (typeof preludeConsumer === 'function') splice(rule.prelude, 0, 0, preludeConsumer(rule.prelude, consumers))
if (typeof ruleConsumer === 'function') splice(rule.value, 0, 0, ruleConsumer(rule.value, consumers))
return [ rule ]
}
}
function consumeRules(nodes, consumers) {
nodes = consumeNodes(nodes)
var rules = createArray()
var node
while (node = nodes[0]) {
if (node instanceof CSSComment || node instanceof CSSWhitespace || node instanceof CSSBlock) rules.push(nodes.shift())
else arrp.push.apply(rules, consumeRule(nodes, consumers))
}
return rules
}
function consumeSelector(nodes) {
nodes = consumeNodes(nodes)
var selector = createArray()
var selectorAfter = createArray()
var node
while ((node = nodes[0]) instanceof CSSComment || node instanceof CSSWhitespace) selector.push(nodes.shift())
while ((node = nodes[nodes.length - 1]) instanceof CSSComment || node instanceof CSSWhitespace) selectorAfter.push(nodes.pop())
while (node = nodes[0]) {
if (node instanceof CSSComment) selector.push(nodes.shift())
else if (node instanceof CSSWhitespace) selector.push(consumeCombinator())
else if (node instanceof CSSNameIdentifier) selector.push(CSSTypeSelector(nodes.shift()))
else if (node instanceof CSSHashIdentifier) selector.push(CSSIdSelector(nodes.shift()))
else if (node instanceof CSSDelimiter) {
if (node.value === ',') break
else if (node.value === '*') selector.push(CSSUniversalSelector(CSSUniversalSelector(nodes.shift())))
else if (node.value === '.' && nodes[1] instanceof CSSNameIdentifier) selector.push(CSSClassSelector(nodes.shift() && nodes.shift()))
else if (node.value === ':') selector.push.apply(selector, consumePseudo())
else if (node.value === '&') selector.push(CSSTypeSelector(nodes.shift()))
else selector.push(consumeCombinator())
} else if (node instanceof CSSBlock) {
if (node.delimiterStart === '[') selector.push.apply(selector, consumeAttributeSelector(nodes.shift()))
else selector.push(prepare(CSSSelector(objectAssign({}, nodes.shift()))))
}
else selector.push(nodes.shift())
}
selector.push.apply(selector, selectorAfter)
return [ CSSSelector({ value: selector }) ]
function consumeCombinator() {
var combinator = createArray()
while ((node = nodes[0]) instanceof CSSComment || node instanceof CSSWhitespace || node instanceof CSSDelimiter) combinator.push(nodes.shift())
return CSSCombinator({ value: combinator })
}
function consumePseudo() {
var undo = createArray()
var colons = ''
while (
(node = nodes.shift()) instanceof CSSComment ||
(
node instanceof CSSDelimiter &&
node.value === ':' &&
(colons += ':')
)
) undo.push(node)
return node instanceof CSSNameIdentifier
? prepare(CSSPseudoSelector({ name: node.value, colons: colons }))
: node instanceof CSSFunction
? prepare(CSSPseudoSelector(objectAssign({ colons: colons }, node)))
: nodes.unshift.apply(nodes, undo) && [consumeCombinator()]
}
function consumeAttributeSelector(block) {
var nodes = block.value
var attributeName = createArray()
var attributeMatcher = createArray()
var attributeValue = createArray()
var attributeModifier = createArray()
var node
// consume attribute name
while ((node = nodes.shift()) instanceof CSSComment || node instanceof CSSWhitespace) attributeName.push(node)
if (node instanceof CSSNameIdentifier) attributeName.push(node)
else return attributeName
while ((node = nodes.shift()) instanceof CSSComment || node instanceof CSSWhitespace) attributeName.push(node)
// return [{name}]
if (!nodes.length) return prepareAttribute()
// consume attribute matcher
if (node instanceof CSSDelimiter) while (node instanceof CSSComment || node instanceof CSSDelimiter) attributeMatcher.push(node)
else return attributeName.push.apply(attributeName, attributeMatcher), attributeName
while ((node = nodes.shift()) instanceof CSSComment || node instanceof CSSWhitespace) attributeMatcher.push(node)
// consume attribute value
if (node instanceof CSSString || node instanceof CSSNameIdentifier) attributeValue.push(node)
else return attributeName.push.apply(attributeName, attributeMatcher), attributeName
// consume attribute modifier
attributeModifier.push.apply(attributeModifier, nodes.splice(0))
// return [{name}={value}{modifier}]
return prepareAttribute()
function prepareAttribute() {
return prepare(CSSAttributeSelector(objectAssign({}, block, { name: attributeName, matcher: attributeMatcher, value: attributeValue, modifier: attributeModifier })))
}
}
function prepare(node) {
var name = asString(node.name)
if (!name || !/^nth-/.test(name)) splice(node.value, 0, 0, consumeSelectors(node.value))
return [ node ]
}
}
function consumeSelectors(nodes) {
nodes = consumeNodes(nodes)
var selectors = []
var selector = createArray()
var node
while (node = nodes[0]) {
if (node instanceof CSSDelimiter && node.value === ',') {
nodes.shift()
if (selector.length) {
selectors.push.apply(selectors, consumeSelector(selector))
selector = createArray()
}
} else selector.push(nodes.shift())
}
selectors.push.apply(selectors, consumeSelector(selector))
return selectors
}
function consume(nodes, consumers) {
return CSSBlock({ value: consumeRules(nodes, consumers) })
}
consume.commaSeparatedList = consumeCommaSeparatedList
consume.declaration = consumeDeclaration
consume.declarations = consumeDeclarations
consume.rule = consumeRule
consume.rules = consumeRules
consume.selector = consumeSelector
consume.selectors = consumeSelectors
consume.spaceSeparatedList = consumeSpaceSeparatedList
/* Library
/* ====================================================================== */
return {
asString: asString,
consume: consume,
createClass: createClass,
defineProp: defineProp,
defineProps: defineProps,
objectAssign: objectAssign,
parse: parse,
types: types
}
})(Array, Function, Object, String)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment