UNPKG

@eslint/css-tree

Version:

A tool set for CSS: fast detailed parser (CSS → AST), walker (AST traversal), generator (AST → CSS) and lexer (validation and matching) based on specs and browser implementations

99 lines (79 loc) 2.76 kB
import { Delim, WhiteSpace } from '../tokenizer/index.js'; import { getTokenizer } from '../utils/get-tokenizer.js'; import { generateSourceMap } from './sourceMap.js'; import * as tokenBefore from './token-before.js'; const REVERSESOLIDUS = 0x005c; // U+005C REVERSE SOLIDUS (\) function processChildren(node, delimeter) { if (typeof delimeter === 'function') { let prev = null; node.children.forEach(node => { if (prev !== null) { delimeter.call(this, prev); } this.node(node); prev = node; }); return; } node.children.forEach(this.node, this); } export function createGenerator(config) { const types = new Map(); for (let [name, item] of Object.entries(config.node)) { const fn = item.generate || item; if (typeof fn === 'function') { types.set(name, item.generate || item); } } return function(node, options) { let buffer = ''; let prevCode = 0; let handlers = { node(node) { if (types.has(node.type)) { types.get(node.type).call(publicApi, node); } else { throw new Error('Unknown node type: ' + node.type); } }, tokenBefore: tokenBefore.safe, token(type, value) { prevCode = this.tokenBefore(prevCode, type, value); this.emit(value, type, false); if (type === Delim && value.charCodeAt(0) === REVERSESOLIDUS) { this.emit('\n', WhiteSpace, true); } }, emit(value) { buffer += value; }, result() { return buffer; } }; if (options) { if (typeof options.decorator === 'function') { handlers = options.decorator(handlers); } if (options.sourceMap) { handlers = generateSourceMap(handlers); } if (options.mode in tokenBefore) { handlers.tokenBefore = tokenBefore[options.mode]; } } const publicApi = { node: (node) => handlers.node(node), children: processChildren, token: (type, value) => handlers.token(type, value), tokenize: function (chunk) { const tokenize = getTokenizer(config); return tokenize(chunk, (type, start, end) => { this.token(type, chunk.slice(start, end)); }); } }; handlers.node(node); return handlers.result(); }; };