@tonyganch
CSScomb
github.com/csscomb.a, .b,
.c{
color: tomato;width:100px;
height:auto}
.a, .b, .c {
width: 100px;
height: auto;
color: tomato;
}
Success story:
- препроцессоры
- php → js
- регулярные выражения → парсер
1. Парсеры
2. Как работают
3. Что выбрать
4. Как написать
p {
color:
white }
p
↓
color
↓
white
p
↓
background
↓
white
p {
background:
white }
p {
color:
white }
↓
p {
background:
white }
строка → дерево
↓
строка ← дерево
строка → дерево
↓
строка ← дерево
строка → дерево
↓
строка ← дерево
1. Парсеры
2. Как работают
3. Что выбрать
4. Как написать
.panda {
color: black-and-white;
}
function getPanda() {
return this.panda;
}
строка → дерево
/* A comment describing the ruleset.*/ .selector-1,.selector-2,.selector-3[type="text"] { box-sizing: border-box; display: block; margin: 0; color: #333; background: #fff; } /* A longer comment describing this ruleset. */ .selector-4, .selector-5 { padding: 10px; } /* This logical grouping of rulesets has no interleaving blank lines. */ .profile { margin: 0; }
/* A comment describing the ruleset.*/
.selector-1,.selector-2,.selector-3[type="text"] { box-sizing: border-box; display: block; margin: 0; color: #333; background: #fff; }
/* A longer comment describing this ruleset. */
.selector-4, .selector-5 { padding: 10px; }
/* This logical grouping of rulesets has no interleaving blank lines. */
.profile { margin: 0; }
.selector-1,.selector-2,.selector-3[type="text"] { box-sizing: border-box; display: block; margin: 0; color: #333; background: #fff; }
.selector-4, .selector-5 { padding: 10px; }
.profile { margin: 0; }
документ
↙ ↙ ↘ ↘
комментарий текст комментарий текст
[
{
type: 'comment',
start: 0,
end: 12
},
{
type: 'text',
start: 13,
end: 32
}
]
[
{
type: 'comment',
start: 0,
end: 12
},
{
type: 'text',
start: 13,
end: 32
}
]
Парсер:
1. читает символы
2. группирует по правилам
/*
Comment
*/
p {
/* Comment */
color: white; / Comment */
}
p {
/* Comment */
color: white; / Comment */
}
p {
/* Comment */
color: white; / Comment */
}
p {
/* Comment */
color: white; / Comment */
}
p {
/* Comment */
color: white; / Comment */
}
p {
/* Comment */
color: white; / Comment */
}
p {
/* Comment */
color: white; / Comment */
}
p {
/* Comment */
color: white; / Comment */
}
p {
/* Comment */
color: white; / Comment */
}
p {
/* Comment */
color: white; / Comment */
}
p {
/* Comment */
color: white; / Comment */
}
p {
/* Comment */
color: white; / Comment */
}
p {
/* Comment */
color: white; / Comment */
}
p {
/* Comment */
color: white; / Comment */
}
документ
↙ ↓ ↘
текст комментарий текст
function parse(string) {
var tree = [], node;
for (var i = 0; i < string.length; i++;) {
node = getComment(i) || getText(i);
tree.push(node);
i += node.value.length;
}
return tree;
}
function getComment(i) {
if (string.indexOf('/*', i) !== i) return;
var end = string.indexOf('*/', i + 2) + 1;
var value = string.splice(i, end);
return createNode('comment', value);
}
[{
type: 'text',
value: 'p {\n '
}, {
type: 'comment',
value: '/* Comment */'
}, {
type: 'text',
value: '\n color: white; / Comment */\n}' },
}]
пробелы
комментарии
идентификаторы
знаки препинания
строка → токены → дерево
парные скобки
[^};]*?{((([^\{\}]+)|(?R))*)}
[^};]*?
{(
(
([^\{\}]+)
|
(?R)
)*
)}
[^};]*?
{(
(
([^\{\}]+)
|
(?R)
)*
)}
{
type: 'leftCurlyBrace',
matchingBrace: 12
}
Дерево:
- дерево разбора
(parse tree)
- AST
(abstract syntax tree)
AST не сохраняет:
- пробелы
- знаки препинаний: ; ,
- ключевые слова: function if
функция
↙ ↘
аргументы тело
↙ ↘ ↓
x y выражение
↙ ↘
присвоение присвоение
↙ ↘ ↙ ↘
x 5 y 10
function (x, y) {
x = 5, y = 10;
}
function (x, y) {
x = 5, y = 10;
}
function (x, y) {
x = 5, y = 10;
}
функция
↙ ↘
аргументы тело
↙ ↘ ↓
x y выражение
↙ ↘
присвоение присвоение
↙ ↘ ↙ ↘
x 5 y 10
function (x, y) {
x = 5, y = 10;
}
(x, y) ->
x = 5
y = 10
строка
↘
parse tree
↙
строка
строка
↘
AST
↙
строка
1. Парсеры
2. Как работают
3. Что выбрать
4. Как написать
Mozilla Parser API
developer.mozilla.org/en-US/docs/
Mozilla/Projects/SpiderMonkey/Parser_API
UglifyJS
PostCSS
Gonzales
Gonzales PE
CSSOM
.panda {
color: white;
color: black;
}
.panda {color:white}
.panda { color: white ; }
[
{
start: 12,
end: 14,
line: 2,
}, {
start: 27,
end: 38,
line: 2
}
]
✓ PostCSS ✗ CSSOM
✓ Gonzales ✗ CSS
меньше деталей —
выше скорость
css.eachDecl(function (decl) {
decl.parent.prepend(decl.clone());
});
API:
- как часть парсера (PostCSS)
- как отдельный модуль (Gonzales AST)
.panda
color white
color()
color black
.panda
color white
1. Парсеры
2. Как работают
3. Что выбрать
4. Как написать
форк = экономия
Gonzales
Gonzales PE
Gonzales LESS, SCSS,
Sass
↘ ↙
Gonzales PE
CSSOM
W3C ≠ реальность
.panda {
color/*\**/: white\9;
}
@media \0screen\,screen\9 {}
.panda { [;color: white;]; }
.panda { )color: white; }
.panda { =color: white; }
@media \0screen\,screen\9 {}
.panda { [;color: white;]; }
.panda { )color: white; }
.panda { =color: white; }
строка → дерево
строка → токены → дерево
Парсер:
- читает символы
- группирует по правилам
Дерево:
- parse tree
- AST
AST не сохраняет:
- пробелы
- знаки препинаний
- ключевые слова
При выборе смотрите на:
- формат дерева
- скорость
- API
- препроцессоры
форки = хорошо
спецификации = хорошо
@media \0screen\,screen\9 {}
.panda { [;color: white;]; }
.panda { )color: white; }
.panda { =color: white; }
@tonyganch
Gonzales PE
github.com/tonyganch/gonzales-pe