Files
2025-07-08 14:47:27 +02:00

329 lines
10 KiB
JavaScript

import { CssTypes, } from '../type';
class Compiler {
level = 0;
indentation = ' ';
compress = false;
constructor(options) {
if (typeof options?.indent === 'string') {
this.indentation = options?.indent;
}
if (options?.compress) {
this.compress = true;
}
}
// We disable no-unused-vars for _position. We keep position for potential reintroduction of source-map
// eslint-disable-next-line @typescript-eslint/no-unused-vars
emit(str, _position) {
return str;
}
/**
* Increase, decrease or return current indentation.
*/
indent(level) {
this.level = this.level || 1;
if (level) {
this.level += level;
return '';
}
return Array(this.level).join(this.indentation);
}
visit(node) {
switch (node.type) {
case CssTypes.stylesheet:
return this.stylesheet(node);
case CssTypes.rule:
return this.rule(node);
case CssTypes.declaration:
return this.declaration(node);
case CssTypes.comment:
return this.comment(node);
case CssTypes.container:
return this.container(node);
case CssTypes.charset:
return this.charset(node);
case CssTypes.document:
return this.document(node);
case CssTypes.customMedia:
return this.customMedia(node);
case CssTypes.fontFace:
return this.fontFace(node);
case CssTypes.host:
return this.host(node);
case CssTypes.import:
return this.import(node);
case CssTypes.keyframes:
return this.keyframes(node);
case CssTypes.keyframe:
return this.keyframe(node);
case CssTypes.layer:
return this.layer(node);
case CssTypes.media:
return this.media(node);
case CssTypes.namespace:
return this.namespace(node);
case CssTypes.page:
return this.page(node);
case CssTypes.supports:
return this.supports(node);
}
}
mapVisit(nodes, delim) {
let buf = '';
delim = delim || '';
for (let i = 0, length = nodes.length; i < length; i++) {
buf += this.visit(nodes[i]);
if (delim && i < length - 1) {
buf += this.emit(delim);
}
}
return buf;
}
compile(node) {
if (this.compress) {
return node.stylesheet.rules.map(this.visit, this).join('');
}
return this.stylesheet(node);
}
/**
* Visit stylesheet node.
*/
stylesheet(node) {
return this.mapVisit(node.stylesheet.rules, '\n\n');
}
/**
* Visit comment node.
*/
comment(node) {
if (this.compress) {
return this.emit('', node.position);
}
return this.emit(this.indent() + '/*' + node.comment + '*/', node.position);
}
/**
* Visit container node.
*/
container(node) {
if (this.compress) {
return (this.emit('@container ' + node.container, node.position) +
this.emit('{') +
this.mapVisit(node.rules) +
this.emit('}'));
}
return (this.emit(this.indent() + '@container ' + node.container, node.position) +
this.emit(' {\n' + this.indent(1)) +
this.mapVisit(node.rules, '\n\n') +
this.emit('\n' + this.indent(-1) + this.indent() + '}'));
}
/**
* Visit container node.
*/
layer(node) {
if (this.compress) {
return (this.emit('@layer ' + node.layer, node.position) +
(node.rules
? this.emit('{') +
this.mapVisit(node.rules) +
this.emit('}')
: ';'));
}
return (this.emit(this.indent() + '@layer ' + node.layer, node.position) +
(node.rules
? this.emit(' {\n' + this.indent(1)) +
this.mapVisit(node.rules, '\n\n') +
this.emit('\n' + this.indent(-1) + this.indent() + '}')
: ';'));
}
/**
* Visit import node.
*/
import(node) {
return this.emit('@import ' + node.import + ';', node.position);
}
/**
* Visit media node.
*/
media(node) {
if (this.compress) {
return (this.emit('@media ' + node.media, node.position) +
this.emit('{') +
this.mapVisit(node.rules) +
this.emit('}'));
}
return (this.emit(this.indent() + '@media ' + node.media, node.position) +
this.emit(' {\n' + this.indent(1)) +
this.mapVisit(node.rules, '\n\n') +
this.emit('\n' + this.indent(-1) + this.indent() + '}'));
}
/**
* Visit document node.
*/
document(node) {
const doc = '@' + (node.vendor || '') + 'document ' + node.document;
if (this.compress) {
return (this.emit(doc, node.position) +
this.emit('{') +
this.mapVisit(node.rules) +
this.emit('}'));
}
return (this.emit(doc, node.position) +
this.emit(' ' + ' {\n' + this.indent(1)) +
this.mapVisit(node.rules, '\n\n') +
this.emit(this.indent(-1) + '\n}'));
}
/**
* Visit charset node.
*/
charset(node) {
return this.emit('@charset ' + node.charset + ';', node.position);
}
/**
* Visit namespace node.
*/
namespace(node) {
return this.emit('@namespace ' + node.namespace + ';', node.position);
}
/**
* Visit supports node.
*/
supports(node) {
if (this.compress) {
return (this.emit('@supports ' + node.supports, node.position) +
this.emit('{') +
this.mapVisit(node.rules) +
this.emit('}'));
}
return (this.emit(this.indent() + '@supports ' + node.supports, node.position) +
this.emit(' {\n' + this.indent(1)) +
this.mapVisit(node.rules, '\n\n') +
this.emit('\n' + this.indent(-1) + this.indent() + '}'));
}
/**
* Visit keyframes node.
*/
keyframes(node) {
if (this.compress) {
return (this.emit('@' + (node.vendor || '') + 'keyframes ' + node.name, node.position) +
this.emit('{') +
this.mapVisit(node.keyframes) +
this.emit('}'));
}
return (this.emit('@' + (node.vendor || '') + 'keyframes ' + node.name, node.position) +
this.emit(' {\n' + this.indent(1)) +
this.mapVisit(node.keyframes, '\n') +
this.emit(this.indent(-1) + '}'));
}
/**
* Visit keyframe node.
*/
keyframe(node) {
const decls = node.declarations;
if (this.compress) {
return (this.emit(node.values.join(','), node.position) +
this.emit('{') +
this.mapVisit(decls) +
this.emit('}'));
}
return (this.emit(this.indent()) +
this.emit(node.values.join(', '), node.position) +
this.emit(' {\n' + this.indent(1)) +
this.mapVisit(decls, '\n') +
this.emit(this.indent(-1) + '\n' + this.indent() + '}\n'));
}
/**
* Visit page node.
*/
page(node) {
if (this.compress) {
const sel = node.selectors.length ? node.selectors.join(', ') : '';
return (this.emit('@page ' + sel, node.position) +
this.emit('{') +
this.mapVisit(node.declarations) +
this.emit('}'));
}
const sel = node.selectors.length ? node.selectors.join(', ') + ' ' : '';
return (this.emit('@page ' + sel, node.position) +
this.emit('{\n') +
this.emit(this.indent(1)) +
this.mapVisit(node.declarations, '\n') +
this.emit(this.indent(-1)) +
this.emit('\n}'));
}
/**
* Visit font-face node.
*/
fontFace(node) {
if (this.compress) {
return (this.emit('@font-face', node.position) +
this.emit('{') +
this.mapVisit(node.declarations) +
this.emit('}'));
}
return (this.emit('@font-face ', node.position) +
this.emit('{\n') +
this.emit(this.indent(1)) +
this.mapVisit(node.declarations, '\n') +
this.emit(this.indent(-1)) +
this.emit('\n}'));
}
/**
* Visit host node.
*/
host(node) {
if (this.compress) {
return (this.emit('@host', node.position) +
this.emit('{') +
this.mapVisit(node.rules) +
this.emit('}'));
}
return (this.emit('@host', node.position) +
this.emit(' {\n' + this.indent(1)) +
this.mapVisit(node.rules, '\n\n') +
this.emit(this.indent(-1) + '\n}'));
}
/**
* Visit custom-media node.
*/
customMedia(node) {
return this.emit('@custom-media ' + node.name + ' ' + node.media + ';', node.position);
}
/**
* Visit rule node.
*/
rule(node) {
const decls = node.declarations;
if (!decls.length) {
return '';
}
if (this.compress) {
return (this.emit(node.selectors.join(','), node.position) +
this.emit('{') +
this.mapVisit(decls) +
this.emit('}'));
}
const indent = this.indent();
return (this.emit(node.selectors
.map(s => {
return indent + s;
})
.join(',\n'), node.position) +
this.emit(' {\n') +
this.emit(this.indent(1)) +
this.mapVisit(decls, '\n') +
this.emit(this.indent(-1)) +
this.emit('\n' + this.indent() + '}'));
}
/**
* Visit declaration node.
*/
declaration(node) {
if (this.compress) {
return (this.emit(node.property + ':' + node.value, node.position) +
this.emit(';'));
}
return (this.emit(this.indent()) +
this.emit(node.property + ': ' + node.value, node.position) +
this.emit(';'));
}
}
export default Compiler;