| "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; |