@mapcss/preset-svg
Version:
SVG as CSS for MapCSS
211 lines (210 loc) • 7.21 kB
JavaScript
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);
}