UNPKG

@mapcss/preset-svg

Version:
211 lines (210 loc) 7.21 kB
import { SourceMapConsumer, SourceMapGenerator } from "./source_map.js"; import { fileURLToPath, pathToFileURL } from "./deps.js"; import { isAbsolute, resolve } from "./deps.js"; import { nanoid } from "./deps.js"; import terminalHighlight from "./terminal-highlight.js"; import CssSyntaxError from "./css-syntax-error.js"; import PreviousMap from "./previous-map.js"; let fromOffsetCache = Symbol("fromOffsetCache"); let sourceMapAvailable = Boolean(SourceMapConsumer && SourceMapGenerator); let pathAvailable = Boolean(resolve && isAbsolute); class Input { constructor(css, opts = {}) { if (css === null || typeof css === "undefined" || (typeof css === "object" && !css.toString)) { throw new Error(`PostCSS received ${css} instead of CSS string`); } this.css = css.toString(); if (this.css[0] === "\uFEFF" || this.css[0] === "\uFFFE") { this.hasBOM = true; this.css = this.css.slice(1); } else { this.hasBOM = false; } if (opts.from) { if (!pathAvailable || /^\w+:\/\//.test(opts.from) || isAbsolute(opts.from)) { this.file = opts.from; } else { this.file = resolve(opts.from); } } if (pathAvailable && sourceMapAvailable) { let map = new PreviousMap(this.css, opts); if (map.text) { this.map = map; let file = map.consumer().file; if (!this.file && file) this.file = this.mapResolve(file); } } if (!this.file) { this.id = "<input css " + nanoid(6) + ">"; } if (this.map) this.map.file = this.from; } fromOffset(offset) { let lastLine, lineToIndex; if (!this[fromOffsetCache]) { let lines = this.css.split("\n"); lineToIndex = new Array(lines.length); let prevIndex = 0; for (let i = 0, l = lines.length; i < l; i++) { lineToIndex[i] = prevIndex; prevIndex += lines[i].length + 1; } this[fromOffsetCache] = lineToIndex; } else { lineToIndex = this[fromOffsetCache]; } lastLine = lineToIndex[lineToIndex.length - 1]; let min = 0; if (offset >= lastLine) { min = lineToIndex.length - 1; } else { let max = lineToIndex.length - 2; let mid; while (min < max) { mid = min + ((max - min) >> 1); if (offset < lineToIndex[mid]) { max = mid - 1; } else if (offset >= lineToIndex[mid + 1]) { min = mid + 1; } else { min = mid; break; } } } return { line: min + 1, col: offset - lineToIndex[min] + 1, }; } error(message, line, column, opts = {}) { let result, endLine, endColumn; if (line && typeof line === "object") { let start = line; let end = column; if (typeof line.offset === "number") { let pos = this.fromOffset(start.offset); line = pos.line; column = pos.col; } else { line = start.line; column = start.column; } if (typeof end.offset === "number") { let pos = this.fromOffset(end.offset); endLine = pos.line; endColumn = pos.col; } else { endLine = end.line; endColumn = end.column; } } else if (!column) { let pos = this.fromOffset(line); line = pos.line; column = pos.col; } let origin = this.origin(line, column, endLine, endColumn); if (origin) { result = new CssSyntaxError(message, origin.endLine === undefined ? origin.line : { line: origin.line, column: origin.column }, origin.endLine === undefined ? origin.column : { line: origin.endLine, column: origin.endColumn }, origin.source, origin.file, opts.plugin); } else { result = new CssSyntaxError(message, endLine === undefined ? line : { line, column }, endLine === undefined ? column : { line: endLine, column: endColumn }, this.css, this.file, opts.plugin); } result.input = { line, column, endLine, endColumn, source: this.css }; if (this.file) { if (pathToFileURL) { result.input.url = pathToFileURL(this.file).toString(); } result.input.file = this.file; } return result; } origin(line, column, endLine, endColumn) { if (!this.map) return false; let consumer = this.map.consumer(); let from = consumer.originalPositionFor({ line, column }); if (!from.source) return false; let to; if (typeof endLine === "number") { to = consumer.originalPositionFor({ line: endLine, column: endColumn }); } let fromUrl; if (isAbsolute(from.source)) { fromUrl = pathToFileURL(from.source); } else { fromUrl = new URL(from.source, this.map.consumer().sourceRoot || pathToFileURL(this.map.mapFile)); } let result = { url: fromUrl.toString(), line: from.line, column: from.column, endLine: to && to.line, endColumn: to && to.column, }; if (fromUrl.protocol === "file:") { if (fileURLToPath) { result.file = fileURLToPath(fromUrl); } else { /* c8 ignore next 2 */ throw new Error(`file: protocol is not available in this PostCSS build`); } } let source = consumer.sourceContentFor(from.source); if (source) result.source = source; return result; } mapResolve(file) { if (/^\w+:\/\//.test(file)) { return file; } return resolve(this.map.consumer().sourceRoot || this.map.root || ".", file); } get from() { return this.file || this.id; } toJSON() { let json = {}; for (let name of ["hasBOM", "css", "file", "id"]) { if (this[name] != null) { json[name] = this[name]; } } if (this.map) { json.map = { ...this.map }; if (json.map.consumerCache) { json.map.consumerCache = undefined; } } return json; } } export default Input; Input.default = Input; if (terminalHighlight && terminalHighlight.registerInput) { terminalHighlight.registerInput(Input); }