Я пытаюсь проанализировать структуру некоторого CSS для использования в качестве входных данных для renderkid в Node.js, вроде (но не так, как), как Парсинг CSS в JavaScript / jQuery.
Например, я хочу, чтобы этот CSS
body { font-size: 10px; }
html { font-size: 11px; }
html, body { font-size: 12px; }
@media only screen and (max-width: 600px) {
body {
background-color: lightblue;
}
}
был проанализирован как этот объект:
{
body: {
"font-size": "12px"
},
html: {
"font-size": "12px"
},
"@media only screen and (max-width: 600px)": {
body: {
"font-size": "12px"
},
}
}
Чтобы не изобретать велосипед заново путем написания парсера CSS, я использую популярный пакет css
, который возвращает AST предоставленного CSS, который в данном случае выглядит следующим образом:
{
"type": "stylesheet",
"stylesheet": {
"rules": [{
"type": "rule",
"selectors": ["body"],
"declarations": [{
"type": "declaration",
"property": "font-size",
"value": "10px",
"position": {
"start": {
"line": 1,
"column": 8
},
"end": {
"line": 1,
"column": 23
}
}
}],
"position": {
"start": {
"line": 1,
"column": 1
},
"end": {
"line": 1,
"column": 26
}
}
}, {
"type": "rule",
"selectors": ["html"],
"declarations": [{
"type": "declaration",
"property": "font-size",
"value": "11px",
"position": {
"start": {
"line": 2,
"column": 8
},
"end": {
"line": 2,
"column": 23
}
}
}],
"position": {
"start": {
"line": 2,
"column": 1
},
"end": {
"line": 2,
"column": 26
}
}
}, {
"type": "rule",
"selectors": ["html", "body"],
"declarations": [{
"type": "declaration",
"property": "font-size",
"value": "12px",
"position": {
"start": {
"line": 3,
"column": 14
},
"end": {
"line": 3,
"column": 29
}
}
}],
"position": {
"start": {
"line": 3,
"column": 1
},
"end": {
"line": 3,
"column": 32
}
}
}, {
"type": "media",
"media": "only screen and (max-width: 600px)",
"rules": [{
"type": "rule",
"selectors": ["body"],
"declarations": [{
"type": "declaration",
"property": "background-color",
"value": "lightblue",
"position": {
"start": {
"line": 6,
"column": 5
},
"end": {
"line": 6,
"column": 32
}
}
}],
"position": {
"start": {
"line": 5,
"column": 3
},
"end": {
"line": 7,
"column": 4
}
}
}],
"position": {
"start": {
"line": 4,
"column": 1
},
"end": {
"line": 8,
"column": 2
}
}
}],
"parsingErrors": []
}
}
На данный момент мне удалось придумать этот код:
"use strict"
const {
parse: parseCSS,
} = require("css")
const _ = require("lodash")
const pickToObject = (array, ...keys) => _.fromPairs(array.map((val) => [val[keys[0]], val[keys[1]]]))
module.exports = (css) => _.merge(...parseCSS(css).stylesheet.rules.map(({
declarations,
selectors,
type,
media,
rules,
}) => {
if (type === "rule") return _.fromPairs(selectors.map((selector) => [selector, pickToObject(declarations, "property", "value")]))
if (type === "media") {
return _.fromPairs([
[`@media ${media}`, _.merge(...rules.map(({
selectors,
declarations,
}) => _.fromPairs(selectors.map((selector) => [selector, pickToObject(declarations, "property", "value")]))))],
])
}
return undefined
}))
Однако я не уверен, как его оптимизировать дальше.
Просто чтобы уточнить: мне нужно создать каноническую функцию, которая может обрабатывать любые допустимые значения CSS, то есть просто захват значений из AST невозможен.