Skip to content

Commit

Permalink
middleware update
Browse files Browse the repository at this point in the history
100% test coverage, middleware revamp, optimizations, add root property to AST allowing both horizontal and vertical traversal.
  • Loading branch information
thysultan committed Mar 8, 2020
1 parent 179132d commit 36e73be
Show file tree
Hide file tree
Showing 14 changed files with 589 additions and 461 deletions.
97 changes: 64 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,59 +1,90 @@
## Experimental rewrite
# STYLIS

The idea is experiment with going full-on with shipping es modules with the lessons learned, and see how small, how fast, and how modular we can go.
[![stylis](https://stylis.js.org/assets/logo.svg)](https://github.com/thysultan/stylis.js)

Currently the rewrite sits comfortably just under 2kb, with a theoratical performance improvement(haven't test anything yet). This estimate includes the prefixer so excluded this would sit within the low-range ballpark of around ~1kb.
A Light–weight CSS Preprocessor.

In comparision the current version sits around ~4kb.
[![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/dyo/dyo/blob/master/LICENSE.md)
[![NPM](https://badgen.net/npm/v/dyo)](https://www.npmjs.com/package/dyo)

### Example:
## Installation

```js
import {compile, serialize, stringify} from 'stylis'
* Use a Direct Download: `<script src=stylis.js></script>`
* Use a CDN: `<script src=unpkg.com/stylis></script>`
* Use NPM: `npm install stylis --save`

serialize(compile(`...`), stringify)
```
## Features

- nesting `a { &:hover {} }`
- selector namespacing
- vendor prefixing (flex-box, etc...)
- minification
- esm module compatible
- tree-shaking-able

## Abstract Syntax Structure

```js
const comment = {
value: '/*! Lorem ipsum dolor sit. */',
type: 'comment',
props: '!',
children: 'Lorem ipsum dolor sit.',
line: 1,
column: 1,
caret: 2
}

const declaration = {
value: 'color:red',
value: 'color:red;',
type: 'declaration',
props: 'color',
children: 'red',
line: 1,
column: 1,
caret: 2
line: 1, column: 1
}

const ruleset = {
value: "h1,h2",
type: "rule",
value: 'h1,h2',
type: 'rule',
props: ['h1', 'h2'],
children: [...],
line: 1,
column: 1,
caret: 2
line: 1, column: 1
}

const atruleset = {
value: "@media (max-width:100), (min-width:100)",
type: "@media",
value: '@media (max-width:100), (min-width:100)',
type: '@media',
props: ['(max-width:100)', '(min-width:100)'],
children: [...],
line: 1,
column: 1,
caret: 2
line: 1, column: 1
}
```

## Example:

```js
import {compile, serialize, stringify} from 'stylis'

serialize(compile(`...`), stringify)
```

### Compile

```js
compile(`h1{all:unset}`) === {value: 'h1', type: 'ruleset', props: ['h1'], children: [...]}
compile(`--varb:unset;`) === {value: '--foo:unset;', type: 'declaration', props: '--foo', children: 'unset'}
```

### Serialize

```js
serialize(compile(`h1{all:unset}`), stringify)
```

### Middleware

```js
serialize(compile(`h1{all:unset}`), middleware((element, index, children) => console.log(element), stringify))
```

### Tokenize

```js
tokenize(`h1 h2 h3 [h4 h5] fn(args) "a b c"`) === ['h1', 'h2', 'h3', '[h4 h5]', 'fn', '(args)', '"a b c"']
```

## Benchmark

Stylis is at-least 2X faster than it's predecesor.
4 changes: 2 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export * from './src/Enum.js'
export * from './src/Utility.js'
export * from './src/Parser.js'
export * from './src/Prefixer.js'
export * from './src/Tokenizer.js'
export * from './src/Serializer.js'
export * from './src/Middleware.js'
export * from './src/Tokenizer.js'
export * from './src/Utility.js'
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "stylis",
"version": "4.0.0",
"license": "MIT",
"description": "Stylis is a light – weight css preprocessor",
"description": "A Light–weight CSS Preprocessor",
"homepage": "https://github.com/thysultan/stylis.js",
"author": "Sultan Tarimo <[email protected]>",
"repository": "https://github.com/thysultan/stylis.js",
Expand Down
11 changes: 5 additions & 6 deletions src/Enum.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
export var COMMENT = 'comment'
export var MS = '-ms-'
export var MOZ = '-moz-'
export var WEBKIT = '-webkit-'

export var RULESET = 'ruleset'
export var DECLARATION = 'declaration'

Expand All @@ -10,11 +13,7 @@ export var VIEWPORT = '@viewport'
export var SUPPORTS = '@supports'
export var DOCUMENT = '@document'
export var NAMESPACE = '@namespace'
export var FONT_FACE = '@font-face'
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 MS = '-ms-'
export var MOZ = '-moz-'
export var WEBKIT = '-webkit-'
99 changes: 61 additions & 38 deletions src/Middleware.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
import {KEYFRAMES, DECLARATION} from './Enum.js'
import {strlen} from './Utility.js'
import {RULESET, KEYFRAMES, DECLARATION} from './Enum.js'
import {test, charat, substr, strlen, sizeof, combine} from './Utility.js'
import {tokenize} from './Tokenizer.js'
import {stringify} from './Serializer.js'
import {prefix} from './Prefixer.js'

/**
* @param {object} element
* @param {function} callback
* @return {string}
* @param {function[]} collection
* @return {function}
*/
export function prefixer (element, callback) {
switch (element.type) {
case DECLARATION: return prefix(element.value, strlen(element.props))
case KEYFRAMES: return prefix(stringify(element, callback), 10)
}
export function middleware (collection) {
var length = sizeof(collection)

return function (element, index, children, callback) {
var output = ''

return stringify(element, callback)
for (var i = 0; i < length; i++)
output += collection[i](element, index, children, callback) || ''

return output
}
}

/**
Expand All @@ -23,41 +27,60 @@ export function prefixer (element, callback) {
*/
export function rulesheet (callback) {
return function (element) {
if (element = stringify(element, prefixer))
callback(element)
if (!element.root)
if (element = element.return)
callback(element)
}
}

/**
* @param {object} element
* @param {number} index
* @param {object[]} children
* @param {function} callback
* @return {function}
*/
export function sourcemap (callback) {
return function (element) {
callback({line: element.line, column: element.column, caret: element.caret})
}
export function prefixer (element, index, children, callback) {
if (element.return === element.prefix)
switch (element.type) {
case DECLARATION: element.prefix = prefix(element.value, element.length)
break
case KEYFRAMES: element.prefix = prefix(stringify(element, index, element.prefix = null, callback), 10)
break
case RULESET:
if (element.length)
if (test(children = element.value, /:place|:read-/))
element.prefix = prefix(stringify(element, index, element.prefix = null, callback), 0)
break
}
}

// TODO
/**
* @example element.props = cascade(element.props, '[id=uuid]')
* @param {string[]} selector
* @param {string} namespace
* @return {string[]}
* @param {object} element
* @param {number} index
* @param {object[]} children
*/
export function cascade (selector, namespace) {
selector.map(function (value) {
// h1 h2 :matches(h1 h2) => h1[uuid] h2[uuid] [uuid]:matches(h1 h2)
return dealloc(tokenize(alloc(value))).map(function (value, index, children) {
switch (charat(value, 0)) {
// :global
case 'g':
return value
case '~': case '>': case '+': case '(':
break
default:
return value + namespace
}
}).join(' ')
})
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: value = substr(value, 1, strlen(value))
// \0 ( + > ~
case 0: case 40: case 43: case 62: case 126:
return value
// :
case 58:
if (value === ':global')
children[index + 1] = '\f' + substr(children[index + 1], index = 1, -1)
// \s
case 32:
return index === 1 ? '' : value
default:
return index ? value + element : (element = value, sizeof(children) === 1 ? value : '')
}
})
})
}
}
Loading

0 comments on commit 36e73be

Please sign in to comment.