blob: b1bc0f0b13140ef0925629e3ece7346145947085 [file] [log] [blame]
"use strict";
const reNewLine = /(?:\r?\n|\r)/gm;
const Input = require("postcss/lib/input");
const Document = require("./document");
const getSyntax = require("./get-syntax");
const patch = require("./patch-postcss");
class LocalFixer {
constructor (lines, style) {
let line = 0;
let column = style.startIndex;
lines.some((lineEndIndex, lineNumber) => {
if (lineEndIndex >= style.startIndex) {
line = lineNumber--;
if (lineNumber in lines) {
column = style.startIndex - lines[lineNumber] - 1;
}
return true;
}
});
this.line = line;
this.column = column;
this.style = style;
}
object (object) {
if (object) {
if (object.line === 1) {
object.column += this.column;
}
object.line += this.line;
}
}
node (node) {
this.object(node.source.start);
this.object(node.source.end);
}
root (root) {
this.node(root);
root.walk(node => {
this.node(node);
});
}
error (error) {
if (error && error.name === "CssSyntaxError") {
this.object(error);
this.object(error.input);
error.message = error.message.replace(/:\d+:\d+:/, ":" + error.line + ":" + error.column + ":");
}
return error;
}
parse (opts) {
const style = this.style;
const syntax = style.syntax || getSyntax(style.lang, opts);
let root = style.root;
try {
root = syntax.parse(style.content, Object.assign({}, opts, {
map: false,
}, style.opts));
} catch (error) {
if (style.ignoreErrors) {
return;
} else if (!style.skipConvert) {
this.error(error);
}
throw error;
}
if (!style.skipConvert) {
this.root(root);
}
root.source.inline = Boolean(style.inline);
root.source.lang = style.lang;
root.source.syntax = syntax;
return root;
}
}
function docFixer (source, opts) {
let match;
const lines = [];
reNewLine.lastIndex = 0;
while ((match = reNewLine.exec(source))) {
lines.push(match.index);
}
lines.push(source.length);
return function parseStyle (style) {
return new LocalFixer(lines, style).parse(opts);
};
}
function parseStyle (source, opts, styles) {
patch(Document);
const document = new Document();
let index = 0;
if (styles.length) {
const parseStyle = docFixer(source, opts);
styles.sort((a, b) => (
a.startIndex - b.startIndex
)).forEach(style => {
const root = parseStyle(style);
if (root) {
root.raws.beforeStart = source.slice(index, style.startIndex);
if (style.endIndex) {
index = style.endIndex;
} else {
index = style.startIndex + (style.content || root.source.input.css).length;
}
root.document = document;
document.nodes.push(root);
}
});
}
document.raws.afterEnd = index ? source.slice(index) : source;
document.source = {
input: new Input(source, opts),
start: {
line: 1,
column: 1,
},
opts,
};
return document;
}
module.exports = parseStyle;