lix-website/themes/lix/assets/bootstrap/node_modules/@stylelint/postcss-css-in-js/object-parser.js
2024-04-26 22:49:34 -06:00

345 lines
6.8 KiB
JavaScript

'use strict';
const camelCase = require('./camel-case');
const getTemplate = require('./get-template');
const Literal = require('./literal');
const ObjectLiteral = require('./object');
const postcss = require('postcss');
const unCamelCase = require('./un-camel-case');
function forEach(arr, callback) {
arr && arr.forEach(callback);
}
function defineRaws(node, prop, prefix, suffix, props) {
if (!props) {
props = {};
}
const descriptor = {
enumerable: true,
get: () => node[prop],
set: (value) => {
node[prop] = value;
},
};
if (!props.raw) {
props.raw = descriptor;
} else if (props.raw === 'camel') {
props.raw = {
enumerable: true,
get: () => camelCase(node[prop]),
set: (value) => {
node[prop] = unCamelCase(value);
},
};
}
props.value = descriptor;
node.raws[prop] = Object.defineProperties(
{
prefix,
suffix,
},
props,
);
}
class objectParser {
constructor(input) {
this.input = input;
}
parse(node) {
const root = postcss.root({
source: {
input: this.input,
start: node.loc.start,
},
});
root.raws.node = node;
const obj = new ObjectLiteral({
raws: {
node,
},
});
root.push(obj);
this.process(node, obj);
this.sort(root);
this.raws(root);
const startNode = root.first.raws.node;
const endNode = root.last.raws.node;
const start = {
line: startNode.loc.start.line,
};
let before = root.source.input.css.slice(
startNode.start - startNode.loc.start.column,
startNode.start,
);
if (/^\s+$/.test(before)) {
start.column = 1;
} else {
before = '';
start.column = startNode.loc.start.column;
}
root.first.raws.before = before;
root.source.input.css = before + root.source.input.css.slice(startNode.start, endNode.end);
root.source.start = start;
this.root = root;
}
process(node, parent) {
['leadingComments', 'innerComments', 'trailingComments'].forEach((prop) => {
forEach(node[prop], (child) => {
this.source(child, this.comment(child, parent));
});
});
const child = (this[node.type] || this.literal).apply(this, [node, parent]);
this.source(node, child);
return child;
}
source(node, parent) {
parent.source = {
input: this.input,
start: node.loc.start,
end: node.loc.end,
};
return parent;
}
raws(parent, node) {
const source = this.input.css;
parent.nodes.forEach((child, i) => {
if (i) {
child.raws.before = source
.slice(parent.nodes[i - 1].raws.node.end, child.raws.node.start)
.replace(/^\s*,+/, '');
} else if (node) {
child.raws.before = source.slice(node.start, child.raws.node.start).replace(/^\s*{+/, '');
}
});
if (node) {
let semicolon;
let after;
if (parent.nodes.length) {
after = source.slice(parent.last.raws.node.end, node.end).replace(/^\s*,+/, () => {
semicolon = true;
return '';
});
} else {
after = source.slice(node.start, node.end).replace(/^\s*{/, '');
}
parent.raws.after = after.replace(/}+\s*$/, '');
parent.raws.semicolon = semicolon || false;
}
}
sort(node) {
node.nodes = node.nodes.sort((a, b) => a.raws.node.start - b.raws.node.start);
}
getNodeValue(node, wrappedValue) {
const source = this.input.css;
let rawValue;
let cookedValue;
switch (node.type) {
case 'Identifier': {
const isCssFloat = node.name === 'cssFloat';
return {
prefix: '',
suffix: '',
raw: isCssFloat && node.name,
value: isCssFloat ? 'float' : node.name,
};
}
case 'StringLiteral': {
rawValue = node.extra.raw.slice(1, -1);
cookedValue = node.value;
break;
}
case 'TemplateLiteral': {
rawValue = getTemplate(node, source);
break;
}
default: {
rawValue = source.slice(node.start, node.end);
break;
}
}
const valueWrap = wrappedValue.split(rawValue);
return {
prefix: valueWrap[0],
suffix: valueWrap[1],
value: cookedValue || rawValue,
};
}
ObjectExpression(node, parent) {
forEach(node.properties, (child) => {
this.process(child, parent);
});
this.sort(parent);
this.raws(parent, node);
return parent;
}
ObjectProperty(node, parent) {
const source = this.input.css;
let between = source.indexOf(':', node.key.end);
const rawKey = source.slice(node.start, between).trimRight();
const rawValue = source.slice(between + 1, node.end).trimLeft();
between = source.slice(node.start + rawKey.length, node.end - rawValue.length);
const key = this.getNodeValue(node.key, rawKey);
if (node.value.type === 'ObjectExpression') {
let rule;
if (/^@(\S+)(\s*)(.*)$/.test(key.value)) {
const name = RegExp.$1;
const afterName = RegExp.$2;
const params = RegExp.$3;
const atRule = postcss.atRule({
name: unCamelCase(name),
raws: {
afterName,
},
nodes: [],
});
defineRaws(atRule, 'name', `${key.prefix}@`, params ? '' : key.suffix, {
raw: 'camel',
});
if (params) {
atRule.params = params;
defineRaws(atRule, 'params', '', key.suffix);
}
rule = atRule;
} else {
// rule = this.rule(key, keyWrap, node.value, parent);
rule = postcss.rule({
selector: key.value,
});
defineRaws(rule, 'selector', key.prefix, key.suffix);
}
raw(rule);
this.ObjectExpression(node.value, rule);
return rule;
}
const value = this.getNodeValue(node.value, rawValue);
if (key.value[0] === '@') {
const atRule = postcss.atRule({
name: unCamelCase(key.value),
params: value.value,
});
defineRaws(atRule, 'name', key.prefix, key.suffix, {
raw: 'camel',
});
defineRaws(atRule, 'params', value.prefix, value.suffix);
raw(atRule);
return atRule;
}
let decl;
if (key.raw) {
decl = postcss.decl({
prop: key.value,
value: value.value,
raws: {
prop: key,
},
});
} else {
decl = postcss.decl({
prop: unCamelCase(key.value),
value: value.value,
});
defineRaws(decl, 'prop', key.prefix, key.suffix, {
raw: 'camel',
});
}
defineRaws(decl, 'value', value.prefix, value.suffix);
raw(decl);
return decl;
function raw(postcssNode) {
postcssNode.raws.between = between;
postcssNode.raws.node = node;
parent.push(postcssNode);
}
}
literal(node, parent) {
const literal = new Literal({
text: this.input.css.slice(node.start, node.end),
raws: {
node,
},
});
parent.push(literal);
return literal;
}
comment(node, parent) {
if (
!parent.nodes ||
(node.start < parent.raws.node.start && parent.type !== 'root' && parent.parent)
) {
return this.comment(node, parent.parent);
}
const text = node.value.match(/^(\s*)((?:\S[\s\S]*?)?)(\s*)$/);
const comment = postcss.comment({
text: text[2],
raws: {
node,
left: text[1],
right: text[3],
inline: node.type === 'CommentLine',
},
});
parent.push(comment);
return comment;
}
}
module.exports = objectParser;