UNPKG

@styn/tree

Version:
127 lines (104 loc) 3.5 kB
// Hey, hi! You can see an example of tree in the test file. const i = (content, count) => `${" ".repeat(count)}${content}`; // indentation const linewrap = content => content[content.length - 1] === "\n" ? content : `${content}\n`; const block = (content, _i = 0) => { const open = `{\n`; const close = i("}", _i); return `${open}${linewrap(content)}${close}\n`; }; const normalizeProp = prop => [...prop].map(l => l.toLowerCase() === l ? l : `-${l.toLowerCase()}`).join(""); const join = (arr, fn = x => x, ...args) => { return arr.map(item => fn(item, ...args)).map(linewrap).join(""); }; const stringify = tree => { const stringifyDeclarations = (declarations, _i = 0) => { return block(Object.keys(declarations).map(property => { const prop = normalizeProp(property); const value = declarations[property]; if (typeof value === "object") return undefined; return linewrap(i(`${prop}: ${value};`, _i + 2)); }).filter(Boolean).join(""), _i); }; const stringifyRule = (rule, _i = 0) => { const declarations = stringifyDeclarations(rule.declarations, _i); return linewrap(i(`${rule.selector} ${declarations}`, _i)); }; const stringifyAtRule = (atRule, _i = 0) => { const keyword = atRule.keyword; const values = atRule.values ? ` ${atRule.values.join(" ")}` : ""; if (atRule.declarations) { const declarations = stringifyDeclarations(atRule.declarations, _i); return linewrap(i(`${keyword}${values} ${declarations}`, _i)); } else if (atRule.rules) { const rules = atRule.rules.map(rule => stringifyRule(rule, _i + 2)).join(""); return linewrap(i(`${keyword}${values} ${block(rules, _i)}`, _i)); } else { return linewrap(i(`${keyword}${values};`, _i)); } }; const stringifyStynRule = rule => { if (rule.type === "at-rule") { return stringifyAtRule(rule); } else if (rule.type === "rule") { return stringifyRule(rule); } return ""; }; return join(tree.rules.map(stringifyStynRule).filter(Boolean)); }; const parse = object => { const rules = []; for (const prop in object) { const value = object[prop]; if (prop.startsWith("@")) { // Handle at-rules const atRule = { type: "at-rule", keyword: prop }; if (prop.startsWith("@font-face")) { // Handle at-rules with declarations atRule.declarations = value; } else if (typeof value === "object") { // Handle at-rules with selectors (rules) atRule.rules = []; for (const selector in value) { atRule.rules.push({ type: "rule", selector, declarations: value[selector] }); } } else if (typeof value === "string") { atRule.values = [value]; } rules.push(atRule); } else { // Handle normal rules const rule = { type: "rule", selector: prop, declarations: value }; rules.push(rule); } } return { rules, meta: {} }; }; const walk = (tree, cb) => { const treeCopy = { ...tree }; for (const rule of treeCopy.rules) { cb(rule, treeCopy.rules, treeCopy.rules.indexOf(rule)); if (rule.type === "at-rule" && typeof rule.rules !== "undefined") { for (const childRule of rule.rules) { cb(childRule, rule.rules, rule.rules.indexOf(childRule)); } } } return treeCopy; }; export { parse, stringify, walk };