You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

262 lines
8.4 KiB
JavaScript

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseStyleAttributeValue = void 0;
const template_safe_parser_1 = __importDefault(require("./template-safe-parser"));
const postcss_1 = require("postcss");
const compat_1 = require("../compat");
function safeParseCss(css) {
try {
const input = new postcss_1.Input(css);
const parser = new template_safe_parser_1.default(input);
parser.parse();
return parser.root;
}
catch {
return null;
}
}
const cache = new WeakMap();
function parseStyleAttributeValue(node, context) {
if (cache.has(node)) {
return cache.get(node) || null;
}
cache.set(node, null);
if (!node.value?.length) {
return null;
}
const startOffset = node.value[0].range[0];
const sourceCode = (0, compat_1.getSourceCode)(context);
const cssCode = node.value.map((value) => sourceCode.getText(value)).join('');
const root = safeParseCss(cssCode);
if (!root) {
return root;
}
const ctx = {
startOffset,
value: node.value,
context
};
const mustacheTags = node.value.filter((v) => v.type === 'SvelteMustacheTag');
const converted = convertRoot(root, mustacheTags, (e) => e.range, ctx);
cache.set(node, converted);
return converted;
}
exports.parseStyleAttributeValue = parseStyleAttributeValue;
class IgnoreError extends Error {
}
function isStringLiteral(node) {
return node.type === 'Literal' && typeof node.value === 'string';
}
function convertRoot(root, interpolations, getRange, ctx) {
const nodes = [];
for (const child of root.nodes) {
const converted = convertChild(child, ctx);
if (!converted) {
return null;
}
while (interpolations[0]) {
const tagOrExpr = interpolations[0];
if (tagOrExpr.range[1] <= converted.range[0]) {
nodes.push(buildSvelteStyleInline(tagOrExpr));
interpolations.shift();
continue;
}
if (tagOrExpr.range[0] < converted.range[1]) {
try {
converted.addInterpolation(tagOrExpr);
}
catch (e) {
if (e instanceof IgnoreError)
return null;
throw e;
}
interpolations.shift();
continue;
}
break;
}
nodes.push(converted);
}
nodes.push(...interpolations.map(buildSvelteStyleInline));
return {
type: 'root',
nodes
};
function buildSvelteStyleInline(tagOrExpr) {
const inlineStyles = new Map();
let range = null;
function getRangeForInline() {
if (range) {
return range;
}
return range ?? (range = getRange(tagOrExpr));
}
return {
type: 'inline',
node: tagOrExpr,
get range() {
return getRangeForInline();
},
get loc() {
return toLoc(getRangeForInline(), ctx);
},
getInlineStyle(node) {
return getInlineStyle(node);
},
getAllInlineStyles() {
const allInlineStyles = new Map();
for (const node of extractExpressions(tagOrExpr)) {
const style = getInlineStyle(node);
if (style) {
allInlineStyles.set(node, style);
}
}
return allInlineStyles;
}
};
function getInlineStyle(node) {
if (node.type === 'SvelteMustacheTag') {
return getInlineStyle(node.expression);
}
if (inlineStyles.has(node)) {
return inlineStyles.get(node) || null;
}
const sourceCode = (0, compat_1.getSourceCode)(ctx.context);
inlineStyles.set(node, null);
let converted;
if (isStringLiteral(node)) {
const root = safeParseCss(sourceCode.getText(node).slice(1, -1));
if (!root) {
return null;
}
converted = convertRoot(root, [], () => [0, 0], {
...ctx,
startOffset: node.range[0] + 1
});
}
else if (node.type === 'TemplateLiteral') {
const root = safeParseCss(sourceCode.getText(node).slice(1, -1));
if (!root) {
return null;
}
converted = convertRoot(root, [...node.expressions], (e) => {
const index = node.expressions.indexOf(e);
return [node.quasis[index].range[1] - 2, node.quasis[index + 1].range[0] + 1];
}, {
...ctx,
startOffset: node.range[0] + 1
});
}
else {
return null;
}
inlineStyles.set(node, converted);
return converted;
}
function* extractExpressions(node) {
if (node.type === 'SvelteMustacheTag') {
yield* extractExpressions(node.expression);
}
else if (isStringLiteral(node)) {
yield node;
}
else if (node.type === 'TemplateLiteral') {
yield node;
}
else if (node.type === 'ConditionalExpression') {
yield* extractExpressions(node.consequent);
yield* extractExpressions(node.alternate);
}
else if (node.type === 'LogicalExpression') {
yield* extractExpressions(node.left);
yield* extractExpressions(node.right);
}
}
}
}
function convertChild(node, ctx) {
const range = convertRange(node, ctx);
if (node.type === 'decl') {
const propRange = [range[0], range[0] + node.prop.length];
const declValueStartIndex = propRange[1] + (node.raws.between || '').length;
const valueRange = [
declValueStartIndex,
declValueStartIndex + (node.raws.value?.value || node.value).length
];
const prop = {
name: node.prop,
range: propRange,
get loc() {
return toLoc(propRange, ctx);
},
interpolations: []
};
const value = {
value: node.value,
range: valueRange,
get loc() {
return toLoc(valueRange, ctx);
},
interpolations: []
};
const unknownInterpolations = [];
return {
type: 'decl',
prop,
value,
important: node.important,
range,
get loc() {
return toLoc(range, ctx);
},
addInterpolation(tagOrExpr) {
const index = tagOrExpr.range[0];
if (prop.range[0] <= index && index < prop.range[1]) {
prop.interpolations.push(tagOrExpr);
return;
}
if (value.range[0] <= index && index < value.range[1]) {
value.interpolations.push(tagOrExpr);
return;
}
unknownInterpolations.push(tagOrExpr);
},
unknownInterpolations
};
}
if (node.type === 'comment') {
return {
type: 'comment',
range,
get loc() {
return toLoc(range, ctx);
},
addInterpolation: () => {
throw new IgnoreError();
}
};
}
if (node.type === 'atrule') {
return null;
}
if (node.type === 'rule') {
return null;
}
return null;
}
function convertRange(node, ctx) {
return [
ctx.startOffset + node.source.start.offset,
ctx.startOffset + node.source.end.offset + 1
];
}
function toLoc(range, ctx) {
return {
start: (0, compat_1.getSourceCode)(ctx.context).getLocFromIndex(range[0]),
end: (0, compat_1.getSourceCode)(ctx.context).getLocFromIndex(range[1])
};
}