forked from lix-project/lix-website
128 lines
2.8 KiB
JavaScript
128 lines
2.8 KiB
JavaScript
|
"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;
|