Skip to content

Instantly share code, notes, and snippets.

@thysultan
Last active April 11, 2020 14:54
Show Gist options
  • Save thysultan/186b10150fce56d40f7cac2b165780c8 to your computer and use it in GitHub Desktop.
Save thysultan/186b10150fce56d40f7cac2b165780c8 to your computer and use it in GitHub Desktop.
stylis.js/pull/#203
import {MS, MOZ, WEBKIT, RULESET, KEYFRAMES, DECLARATION} from './Enum.js'
import {match, charat, substr, strlen, sizeof, replace, combine} from './Utility.js'
import {copy, tokenize} from './Tokenizer.js'
import {serialize} from './Serializer.js'
import {prefix} from './Prefixer.js'
/**
* @param {function[]} collection
* @return {function}
*/
export function middleware (collection) {
var length = sizeof(collection)
return function (element, index, children, callback) {
var output = ''
for (var i = 0; i < length; i++)
output += collection[i](element, index, children, callback) || ''
return output
}
}
/**
* @param {function} callback
* @return {function}
*/
export function rulesheet (callback) {
return function (element) {
if (!element.root)
if (element = element.return)
callback(element)
}
}
/**
* @param {object} element
* @param {number} index
* @param {object[]} children
* @param {function} callback
*/
export function prefixer (element, index, children, callback) {
if (!element.return)
switch (element.type) {
case DECLARATION: element.return = prefix(element.value, element.length)
break
case KEYFRAMES:
return serialize([copy(replace(element.value, '@', '@' + WEBKIT), element, '')], callback)
case RULESET:
if (element.length)
return combine(element.props, function (value) {
switch (match(value, /(::place\w+|:read-\w+)/)) {
// :read-(only|write)
case ':read-only': case ':read-write':
return serialize([copy(replace(value, /(read.+)/, MOZ + '$1'), element, '')], callback)
// :placeholder
case '::placeholder':
return serialize([
copy(replace(value, /(plac.+)/, WEBKIT + 'input-$1'), element, ''),
copy(replace(value, /(plac.+)/, MOZ + '$1'), element, ''),
copy(replace(value, /:(plac.+)/, MS + 'input-$1'), element, '')
], callback)
}
return ''
})
}
}
/**
* @param {object} element
* @param {number} index
* @param {object[]} children
*/
export function namespace (element) {
switch (element.type) {
case RULESET:
element.props = element.props.map(function (value) {
return combine(tokenize(value), function (value, index, children) {
switch (charat(value, 0)) {
// \f
case 12:
return substr(value, 1, strlen(value))
// \0 ( + > ~
case 0: case 40: case 43: case 62: case 126:
return value
// :
case 58:
if (children[index + 1] === 'global')
children[index + 1] = '', children[index + 2] = '\f' + substr(children[index + 2], index = 1, -1)
// \s
case 32:
return index === 1 ? '' : value
default:
switch (index) {
case 0: element = value
return sizeof(children) > 1 ? '' : value
case index = sizeof(children) - 1: case 2:
return index === 2 ? value + element + element : value + element
default:
return value
}
}
})
})
}
}
import {COMMENT, RULESET, DECLARATION} from './Enum.js'
import {abs, trim, from, sizeof, strlen, substr, append, replace} from './Utility.js'
import {node, char, next, peek, caret, alloc, dealloc, delimit, whitespace, identifier, commenter} from './Tokenizer.js'
/**
* @param {string} value
* @return {object[]}
*/
export function compile (value) {
return dealloc(parse('', null, null, [''], value = alloc(value), 0, [0], value))
}
/**
* @param {string} value
* @param {object} root
* @param {string[]} rule
* @param {string[]} rules
* @param {string[]} rulesets
* @param {number[]} psuedo
* @param {number[]} points
* @param {string[]} declarations
* @return {object}
*/
export function parse (value, root, rule, rules, rulesets, psuedo, points, declarations) {
var index = 0
var offset = 0
var length = psuedo
var atrule = 0
var property = 0
var previous = 0
var variable = 1
var scanning = 1
var ampersand = 1
var character = 0
var type = ''
var props = rules
var children = rulesets
var reference = rule
var characters = type
while (scanning)
switch (previous = character, character = next()) {
// " ' [ (
case 34: case 39: case 91: case 40:
characters += delimit(character)
break
// \t \n \s
case 9: case 10: case 32:
characters += whitespace(previous)
break
// /
case 47:
switch (peek()) {
case 42: case 47:
append(comment(commenter(next(), caret()), root), declarations)
break
default:
characters += '/'
}
break
// {
case 123 * variable:
points[index++] = strlen(characters) * ampersand
// } ; \0
case 125 * variable: case 59: case 0:
switch (character) {
// \0 }
case 0: case 125: scanning = 0
// ;
case 59 + offset:
if (property > 0)
append(property > 32 ? declaration(characters + ';', rule, length) : declaration(replace(characters, ' ', '') + ';', rule, length - 1), declarations)
break
// @ ;
case 59: characters += ';'
// { rule/at-rule
default:
append(reference = ruleset(characters, root, index, offset, rules, points, type, props = [], children = [], length), rulesets)
if (character === 123)
if (offset === 0)
parse(characters, root, reference, props, rulesets, length, points, children)
else
switch (atrule) {
// d m s
case 100: case 109: case 115:
parse(value, reference, rule && append(ruleset(value, reference, 0, 0, rules, points, type, rules, props = [], length), children), rules, children, length, points, rule ? props : children)
break
default:
parse(characters, reference, reference, [''], children, length, points, children)
}
}
index = offset = property = 0, variable = ampersand = 1, type = characters = '', length = psuedo
break
// :
case 58:
length = strlen(characters), property = previous
default:
switch (characters += from(character), character * variable) {
// &
case 38:
ampersand = offset > 0 ? 1 : (characters += '\f', -1)
break
// ,
case 44:
points[index++] = (strlen(characters) - 1) * ampersand, ampersand = 1
break
// @
case 64:
// -
if (peek() === 45)
characters += delimit(next())
atrule = peek(), offset = strlen(type = characters += identifier(caret())), character++
break
// -
case 45:
if (previous === 45)
variable = 0
}
}
return rulesets
}
/**
* @param {string} value
* @param {object} root
* @param {number} index
* @param {number} offset
* @param {string[]} rules
* @param {number[]} points
* @param {string} type
* @param {string[]} props
* @param {string[]} children
* @param {number} length
* @return {object}
*/
export function ruleset (value, root, index, offset, rules, points, type, props, children, length) {
var post = offset - 1
var rule = offset === 0 ? rules : ['']
var size = sizeof(rule)
for (var i = 0, j = 0, k = 0; i < index; ++i)
for (var x = 0, y = substr(value, post + 1, post = abs(j = points[i])), z = value; x < size; ++x)
if (z = trim(j > 0 ? rule[x] + ' ' + y : replace(y, /&\f/g, rule[x])))
props[k++] = z
return node(value, root, offset === 0 ? RULESET : type, props, children, length)
}
/**
* @param {number} value
* @param {string[]} root
* @param {number} type
* @return {object}
*/
export function comment (value, root) {
return node(value, root, COMMENT, from(char()), substr(value, 2, -2), 0)
}
/**
* @param {string} value
* @param {string[]} root
* @param {number} length
* @return {object}
*/
export function declaration (value, root, length) {
return node(value, root, DECLARATION, substr(value, 0, length), substr(value, length + 1, -1), length)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment