Skip to content

Commit

Permalink
Merge branch 'thysultan:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
palashgdev authored Sep 30, 2024
2 parents 9be0055 + f7bbabe commit fdbdda9
Show file tree
Hide file tree
Showing 16 changed files with 341 additions and 68 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ jobs:
node-version: [11.4.0]
steps:
- name: checkout
uses: actions/checkout@v1
uses: actions/checkout@v3
- name: setup ${{ matrix.node-version }}
uses: actions/setup-node@v1
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: test
run: |
npm install
npm test
- name: report
uses: coverallsapp/github-action@v1.0.1
uses: coverallsapp/github-action@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: ./coverage/lcov.info
file: ./coverage/lcov.info
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ coverage
.nyc_output
dist/
package-lock.json
yarn.lock
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ A Light–weight CSS Preprocessor.
[![Coverage](https://coveralls.io/repos/github/thysultan/stylis.js/badge.svg?branch=master)](https://coveralls.io/github/thysultan/stylis.js)
[![Size](https://badgen.net/bundlephobia/minzip/stylis)](https://bundlephobia.com/result?p=stylis)
[![Licence](https://badgen.net/badge/license/MIT/blue)](https://github.com/thysultan/stylis.js/blob/master/LICENSE)
[![NPM](https://badgen.net/npm/v/dyo)](https://www.npmjs.com/package/stylis)
[![NPM](https://badgen.net/npm/v/stylis)](https://www.npmjs.com/package/stylis)

## Installation

Expand Down Expand Up @@ -150,7 +150,7 @@ For example consider the following: `--foo: {};`

While this is valid CSS and supported. It is unclear what should happen when the rule collides with the implicit block termination rule that allows i.e `h1{color:red}`(notice the omitted semicolon) to also be a valid CSS production. This results in the following contradiction in: `h1{--example: {}` is it to be treated as `h1{--foo:{;}` or `h1{--foo:{}` the later of which is an unterminated block or in the following: `h1{--foo:{} h1{color:red;}` should it be `h1 {--foo:{}h1{color:red;};` where `{}h1{color:red;` is part of the css variable `--foo` and not a new rule or should it be something else?

Never the less Stylis still supports the exotic forms highlighted in the spec, however you should consider it as a general rule to delimit such exotic uses of variables in strings or parentheses i.e: `h1{--foo:'{'}` or `h1{--foo:({)}`.
Nevertheless Stylis still supports the exotic forms highlighted in the spec, however you should consider it as a general rule to delimit such exotic uses of variables in strings or parentheses i.e: `h1{--foo:'{'}` or `h1{--foo:({)}`.

## Benchmark

Expand Down
4 changes: 4 additions & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@
</div>
<script type=module>
import {compile, serialize, middleware, prefixer, stringify} from 'https://unpkg.com/stylis?module'
import * as stylis from 'https://unpkg.com/stylis?module'

window.stylis = stylis

function tabbed (select, ranged, content) {
ranged.deleteContents()
Expand All @@ -66,6 +69,7 @@
// formatting
default:
value = serialize(compile(`[namespace]{${value.target.textContent}}`), middleware([prefixer, stringify]))
value = value.replace(/</g, '&lt;').replace(/>/g, '&gt;')
value = value.replace(/(;|\})/g, (match, group) => group + (group === '}' ? '\n\n' : '\n'))
value = value.replace(/(.*?)\{/g, (match, group) => '<span class=selector>' + group.trim() + '</span> {\n')
value = value.replace(/:(.*);/g, (match, group) => ': <span class=value>' + group.trim() + '</span>;')
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "stylis",
"version": "4.1.1",
"version": "4.3.4",
"license": "MIT",
"description": "A Light–weight CSS Preprocessor",
"homepage": "https://github.com/thysultan/stylis.js",
Expand Down
2 changes: 2 additions & 0 deletions src/Enum.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ export var KEYFRAMES = '@keyframes'
export var FONT_FACE = '@font-face'
export var COUNTER_STYLE = '@counter-style'
export var FONT_FEATURE_VALUES = '@font-feature-values'
export var LAYER = '@layer'
export var SCOPE = '@scope'
24 changes: 14 additions & 10 deletions src/Middleware.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
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 {match, charat, substr, strlen, sizeof, replace, combine, filter, assign} from './Utility.js'
import {copy, lift, tokenize} from './Tokenizer.js'
import {serialize} from './Serializer.js'
import {prefix} from './Prefixer.js'

Expand Down Expand Up @@ -49,18 +49,22 @@ export function prefixer (element, index, children, callback) {
return serialize([copy(element, {value: replace(element.value, '@', '@' + WEBKIT)})], callback)
case RULESET:
if (element.length)
return combine(element.props, function (value) {
switch (match(value, /(::plac\w+|:read-\w+)/)) {
return combine(children = element.props, function (value) {
switch (match(value, callback = /(::plac\w+|:read-\w+)/)) {
// :read-(only|write)
case ':read-only': case ':read-write':
return serialize([copy(element, {props: [replace(value, /:(read-\w+)/, ':' + MOZ + '$1')]})], callback)
lift(copy(element, {props: [replace(value, /:(read-\w+)/, ':' + MOZ + '$1')]}))
lift(copy(element, {props: [value]}))
assign(element, {props: filter(children, callback)})
break
// :placeholder
case '::placeholder':
return serialize([
copy(element, {props: [replace(value, /:(plac\w+)/, ':' + WEBKIT + 'input-$1')]}),
copy(element, {props: [replace(value, /:(plac\w+)/, ':' + MOZ + '$1')]}),
copy(element, {props: [replace(value, /:(plac\w+)/, MS + 'input-$1')]})
], callback)
lift(copy(element, {props: [replace(value, /:(plac\w+)/, ':' + WEBKIT + 'input-$1')]}))
lift(copy(element, {props: [replace(value, /:(plac\w+)/, ':' + MOZ + '$1')]}))
lift(copy(element, {props: [replace(value, /:(plac\w+)/, MS + 'input-$1')]}))
lift(copy(element, {props: [value]}))
assign(element, {props: filter(children, callback)})
break
}

return ''
Expand Down
42 changes: 23 additions & 19 deletions src/Parser.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {COMMENT, RULESET, DECLARATION} from './Enum.js'
import {abs, trim, from, sizeof, strlen, substr, append, replace, indexof} from './Utility.js'
import {node, char, prev, next, peek, caret, alloc, dealloc, delimit, whitespace, escaping, identifier, commenter} from './Tokenizer.js'
import {abs, charat, trim, from, sizeof, strlen, substr, append, replace, indexof} from './Utility.js'
import {node, char, prev, next, peek, token, caret, alloc, dealloc, delimit, whitespace, escaping, identifier, commenter} from './Tokenizer.js'

/**
* @param {string} value
Expand Down Expand Up @@ -43,8 +43,8 @@ export function parse (value, root, parent, rule, rules, rulesets, pseudo, point
switch (previous = character, character = next()) {
// (
case 40:
if (previous != 108 && characters.charCodeAt(length - 1) == 58) {
if (indexof(characters += replace(delimit(character), '&', '&\f'), '&\f') != -1)
if (previous != 108 && charat(characters, length - 1) == 58) {
if (indexof(characters += replace(delimit(character), '&', '&\f'), '&\f', abs(index ? points[index - 1] : 0)) != -1)
ampersand = -1
break
}
Expand All @@ -64,7 +64,8 @@ export function parse (value, root, parent, rule, rules, rulesets, pseudo, point
case 47:
switch (peek()) {
case 42: case 47:
append(comment(commenter(next(), caret()), root, parent), declarations)
append(comment(commenter(next(), caret()), root, parent, declarations), declarations)
if ((token(previous || 1) == 5 || token(peek() || 1) == 5) && strlen(characters) && substr(characters, -1, void 0) !== ' ') characters += ' '
break
default:
characters += '/'
Expand All @@ -79,24 +80,24 @@ export function parse (value, root, parent, rule, rules, rulesets, pseudo, point
// \0 }
case 0: case 125: scanning = 0
// ;
case 59 + offset:
if (property > 0 && (strlen(characters) - length))
append(property > 32 ? declaration(characters + ';', rule, parent, length - 1) : declaration(replace(characters, ' ', '') + ';', rule, parent, length - 2), declarations)
case 59 + offset: if (ampersand == -1) characters = replace(characters, /\f/g, '')
if (property > 0 && (strlen(characters) - length || (variable === 0 && previous === 47)))
append(property > 32 ? declaration(characters + ';', rule, parent, length - 1, declarations) : declaration(replace(characters, ' ', '') + ';', rule, parent, length - 2, declarations), declarations)
break
// @ ;
case 59: characters += ';'
// { rule/at-rule
default:
append(reference = ruleset(characters, root, parent, index, offset, rules, points, type, props = [], children = [], length), rulesets)
append(reference = ruleset(characters, root, parent, index, offset, rules, points, type, props = [], children = [], length, rulesets), rulesets)

if (character === 123)
if (offset === 0)
parse(characters, root, reference, reference, props, rulesets, length, points, children)
else
switch (atrule) {
// d m s
case 100: case 109: case 115:
parse(value, reference, reference, rule && append(ruleset(value, reference, reference, 0, 0, rules, points, type, rules, props = [], length), children), rules, children, length, points, rule ? props : children)
switch (atrule === 99 && charat(characters, 3) === 110 ? 100 : atrule) {
// d l m s
case 100: case 108: case 109: case 115:
parse(value, reference, reference, rule && append(ruleset(value, reference, reference, 0, 0, rules, points, type, rules, props = [], length, children), children), rules, children, length, points, rule ? props : children)
break
default:
parse(characters, reference, reference, reference, [''], children, 0, points, children)
Expand Down Expand Up @@ -154,9 +155,10 @@ export function parse (value, root, parent, rule, rules, rulesets, pseudo, point
* @param {string[]} props
* @param {string[]} children
* @param {number} length
* @param {object[]} siblings
* @return {object}
*/
export function ruleset (value, root, parent, index, offset, rules, points, type, props, children, length) {
export function ruleset (value, root, parent, index, offset, rules, points, type, props, children, length, siblings) {
var post = offset - 1
var rule = offset === 0 ? rules : ['']
var size = sizeof(rule)
Expand All @@ -166,26 +168,28 @@ export function ruleset (value, root, parent, index, offset, rules, points, type
if (z = trim(j > 0 ? rule[x] + ' ' + y : replace(y, /&\f/g, rule[x])))
props[k++] = z

return node(value, root, parent, offset === 0 ? RULESET : type, props, children, length)
return node(value, root, parent, offset === 0 ? RULESET : type, props, children, length, siblings)
}

/**
* @param {number} value
* @param {object} root
* @param {object?} parent
* @param {object[]} siblings
* @return {object}
*/
export function comment (value, root, parent) {
return node(value, root, parent, COMMENT, from(char()), substr(value, 2, -2), 0)
export function comment (value, root, parent, siblings) {
return node(value, root, parent, COMMENT, from(char()), substr(value, 2, -2), 0, siblings)
}

/**
* @param {string} value
* @param {object} root
* @param {object?} parent
* @param {number} length
* @param {object[]} siblings
* @return {object}
*/
export function declaration (value, root, parent, length) {
return node(value, root, parent, DECLARATION, substr(value, 0, length), substr(value, length + 1, -1), length)
export function declaration (value, root, parent, length, siblings) {
return node(value, root, parent, DECLARATION, substr(value, 0, length), substr(value, length + 1, -1), length, siblings)
}
13 changes: 8 additions & 5 deletions src/Prefixer.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@ export function prefix (value, length, children) {
case 5737: case 4201: case 3177: case 3433: case 1641: case 4457: case 2921:
// text-decoration, filter, clip-path, backface-visibility, column, box-decoration-break
case 5572: case 6356: case 5844: case 3191: case 6645: case 3005:
// mask, mask-image, mask-(mode|clip|size), mask-(repeat|origin), mask-position, mask-composite,
case 6391: case 5879: case 5623: case 6135: case 4599: case 4855:
// background-clip, columns, column-(count|fill|gap|rule|rule-color|rule-style|rule-width|span|width)
case 4215: case 6389: case 5109: case 5365: case 5621: case 3829:
// mask, mask-image, mask-(mode|clip|size), mask-(repeat|origin), mask-position
case 6391: case 5879: case 5623: case 6135: case 4599:
return WEBKIT + value + value
// mask-composite
case 4855:
return WEBKIT + value.replace('add', 'source-over').replace('substract', 'source-out').replace('intersect', 'source-in').replace('exclude', 'xor') + value
// tab-size
case 4789:
return MOZ + value + value
Expand Down Expand Up @@ -76,7 +79,7 @@ export function prefix (value, length, children) {
return replace(value, /(image-set\([^]*)/, WEBKIT + '$1' + '$`$1')
// justify-content
case 4968:
return replace(replace(value, /(.+:)(flex-)?(.*)/, WEBKIT + 'box-pack:$3' + MS + 'flex-pack:$3'), /s.+-b[^;]+/, 'justify') + WEBKIT + value + value
return replace(replace(value, /(.+:)(flex-)?(.*)/, WEBKIT + 'box-pack:$3' + MS + 'flex-pack:$3'), /space-between/, 'justify') + WEBKIT + value + value
// justify-self
case 4200:
if (!match(value, /flex-|baseline/)) return MS + 'grid-column-align' + substr(value, length) + value
Expand All @@ -87,7 +90,7 @@ export function prefix (value, length, children) {
// grid-(row|column)-start
case 4384: case 3616:
if (children && children.some(function (element, index) { return length = index, match(element.props, /grid-\w+-end/) })) {
return ~indexof(value + (children = children[length].value), 'span') ? value : (MS + replace(value, '-start', '') + value + MS + 'grid-row-span:' + (~indexof(children, 'span') ? match(children, /\d+/) : +match(children, /\d+/) - +match(value, /\d+/)) + ';')
return ~indexof(value + (children = children[length].value), 'span', 0) ? value : (MS + replace(value, '-start', '') + value + MS + 'grid-row-span:' + (~indexof(children, 'span', 0) ? match(children, /\d+/) : +match(children, /\d+/) - +match(value, /\d+/)) + ';')
}
return MS + replace(value, '-start', '') + value
// grid-(row|column)-end
Expand All @@ -113,7 +116,7 @@ export function prefix (value, length, children) {
return replace(value, /(.+:)(.+)-([^]+)/, '$1' + WEBKIT + '$2-$3' + '$1' + MOZ + (charat(value, length + 3) == 108 ? '$3' : '$2-$3')) + value
// (s)tretch
case 115:
return ~indexof(value, 'stretch') ? prefix(replace(value, 'stretch', 'fill-available'), length, children) + value : value
return ~indexof(value, 'stretch', 0) ? prefix(replace(value, 'stretch', 'fill-available'), length, children) + value : value
}
break
// grid-(column|row)
Expand Down
10 changes: 5 additions & 5 deletions src/Serializer.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {IMPORT, COMMENT, RULESET, DECLARATION, KEYFRAMES} from './Enum.js'
import {strlen, sizeof} from './Utility.js'
import {IMPORT, LAYER, COMMENT, RULESET, DECLARATION, KEYFRAMES} from './Enum.js'
import {strlen} from './Utility.js'

/**
* @param {object[]} children
Expand All @@ -8,9 +8,8 @@ import {strlen, sizeof} from './Utility.js'
*/
export function serialize (children, callback) {
var output = ''
var length = sizeof(children)

for (var i = 0; i < length; i++)
for (var i = 0; i < children.length; i++)
output += callback(children[i], i, children, callback) || ''

return output
Expand All @@ -25,10 +24,11 @@ export function serialize (children, callback) {
*/
export function stringify (element, index, children, callback) {
switch (element.type) {
case LAYER: if (element.children.length) break
case IMPORT: case DECLARATION: return element.return = element.return || element.value
case COMMENT: return ''
case KEYFRAMES: return element.return = element.value + '{' + serialize(element.children, callback) + '}'
case RULESET: element.value = element.props.join(',')
case RULESET: if (!strlen(element.value = element.props.join(','))) return ''
}

return strlen(children = serialize(element.children, callback)) ? element.return = element.value + '{' + children + '}' : ''
Expand Down
17 changes: 14 additions & 3 deletions src/Tokenizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ export var characters = ''
* @param {string} type
* @param {string[] | string} props
* @param {object[] | string} children
* @param {object[]} siblings
* @param {number} length
*/
export function node (value, root, parent, type, props, children, length) {
return {value: value, root: root, parent: parent, type: type, props: props, children: children, line: line, column: column, length: length, return: ''}
export function node (value, root, parent, type, props, children, length, siblings) {
return {value: value, root: root, parent: parent, type: type, props: props, children: children, line: line, column: column, length: length, return: '', siblings: siblings}
}

/**
Expand All @@ -26,7 +27,17 @@ export function node (value, root, parent, type, props, children, length) {
* @return {object}
*/
export function copy (root, props) {
return assign(node('', null, null, '', null, null, 0), root, {length: -root.length}, props)
return assign(node('', null, null, '', null, null, 0, root.siblings), root, {length: -root.length}, props)
}

/**
* @param {object} root
*/
export function lift (root) {
while (root.root)
root = copy(root.root, {children: [root]})

append(root, root.siblings)
}

/**
Expand Down
16 changes: 13 additions & 3 deletions src/Utility.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export var assign = Object.assign
* @return {number}
*/
export function hash (value, length) {
return (((((((length << 2) ^ charat(value, 0)) << 2) ^ charat(value, 1)) << 2) ^ charat(value, 2)) << 2) ^ charat(value, 3)
return charat(value, 0) ^ 45 ? (((((((length << 2) ^ charat(value, 0)) << 2) ^ charat(value, 1)) << 2) ^ charat(value, 2)) << 2) ^ charat(value, 3) : 0
}

/**
Expand Down Expand Up @@ -55,10 +55,11 @@ export function replace (value, pattern, replacement) {
/**
* @param {string} value
* @param {string} search
* @param {number} position
* @return {number}
*/
export function indexof (value, search) {
return value.indexOf(search)
export function indexof (value, search, position) {
return value.indexOf(search, position)
}

/**
Expand Down Expand Up @@ -113,3 +114,12 @@ export function append (value, array) {
export function combine (array, callback) {
return array.map(callback).join('')
}

/**
* @param {string[]} array
* @param {RegExp} pattern
* @return {string[]}
*/
export function filter (array, pattern) {
return array.filter(function (value) { return !match(value, pattern) })
}
Loading

0 comments on commit fdbdda9

Please sign in to comment.