summaryrefslogtreecommitdiff
path: root/node_modules/webpack-sources/lib/ReplaceSource.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/webpack-sources/lib/ReplaceSource.js')
-rw-r--r--node_modules/webpack-sources/lib/ReplaceSource.js467
1 files changed, 467 insertions, 0 deletions
diff --git a/node_modules/webpack-sources/lib/ReplaceSource.js b/node_modules/webpack-sources/lib/ReplaceSource.js
new file mode 100644
index 00000000..1a678d17
--- /dev/null
+++ b/node_modules/webpack-sources/lib/ReplaceSource.js
@@ -0,0 +1,467 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+*/
+"use strict";
+
+const { getMap, getSourceAndMap } = require("./helpers/getFromStreamChunks");
+const streamChunks = require("./helpers/streamChunks");
+const Source = require("./Source");
+const splitIntoLines = require("./helpers/splitIntoLines");
+
+// since v8 7.0, Array.prototype.sort is stable
+const hasStableSort =
+ typeof process === "object" &&
+ process.versions &&
+ typeof process.versions.v8 === "string" &&
+ !/^[0-6]\./.test(process.versions.v8);
+
+// This is larger than max string length
+const MAX_SOURCE_POSITION = 0x20000000;
+
+class Replacement {
+ constructor(start, end, content, name) {
+ this.start = start;
+ this.end = end;
+ this.content = content;
+ this.name = name;
+ if (!hasStableSort) {
+ this.index = -1;
+ }
+ }
+}
+
+class ReplaceSource extends Source {
+ constructor(source, name) {
+ super();
+ this._source = source;
+ this._name = name;
+ /** @type {Replacement[]} */
+ this._replacements = [];
+ this._isSorted = true;
+ }
+
+ getName() {
+ return this._name;
+ }
+
+ getReplacements() {
+ this._sortReplacements();
+ return this._replacements;
+ }
+
+ replace(start, end, newValue, name) {
+ if (typeof newValue !== "string")
+ throw new Error(
+ "insertion must be a string, but is a " + typeof newValue
+ );
+ this._replacements.push(new Replacement(start, end, newValue, name));
+ this._isSorted = false;
+ }
+
+ insert(pos, newValue, name) {
+ if (typeof newValue !== "string")
+ throw new Error(
+ "insertion must be a string, but is a " +
+ typeof newValue +
+ ": " +
+ newValue
+ );
+ this._replacements.push(new Replacement(pos, pos - 1, newValue, name));
+ this._isSorted = false;
+ }
+
+ source() {
+ if (this._replacements.length === 0) {
+ return this._source.source();
+ }
+ let current = this._source.source();
+ let pos = 0;
+ const result = [];
+
+ this._sortReplacements();
+ for (const replacement of this._replacements) {
+ const start = Math.floor(replacement.start);
+ const end = Math.floor(replacement.end + 1);
+ if (pos < start) {
+ const offset = start - pos;
+ result.push(current.slice(0, offset));
+ current = current.slice(offset);
+ pos = start;
+ }
+ result.push(replacement.content);
+ if (pos < end) {
+ const offset = end - pos;
+ current = current.slice(offset);
+ pos = end;
+ }
+ }
+ result.push(current);
+ return result.join("");
+ }
+
+ map(options) {
+ if (this._replacements.length === 0) {
+ return this._source.map(options);
+ }
+ return getMap(this, options);
+ }
+
+ sourceAndMap(options) {
+ if (this._replacements.length === 0) {
+ return this._source.sourceAndMap(options);
+ }
+ return getSourceAndMap(this, options);
+ }
+
+ original() {
+ return this._source;
+ }
+
+ _sortReplacements() {
+ if (this._isSorted) return;
+ if (hasStableSort) {
+ this._replacements.sort(function (a, b) {
+ const diff1 = a.start - b.start;
+ if (diff1 !== 0) return diff1;
+ const diff2 = a.end - b.end;
+ if (diff2 !== 0) return diff2;
+ return 0;
+ });
+ } else {
+ this._replacements.forEach((repl, i) => (repl.index = i));
+ this._replacements.sort(function (a, b) {
+ const diff1 = a.start - b.start;
+ if (diff1 !== 0) return diff1;
+ const diff2 = a.end - b.end;
+ if (diff2 !== 0) return diff2;
+ return a.index - b.index;
+ });
+ }
+ this._isSorted = true;
+ }
+
+ streamChunks(options, onChunk, onSource, onName) {
+ this._sortReplacements();
+ const repls = this._replacements;
+ let pos = 0;
+ let i = 0;
+ let replacmentEnd = -1;
+ let nextReplacement =
+ i < repls.length ? Math.floor(repls[i].start) : MAX_SOURCE_POSITION;
+ let generatedLineOffset = 0;
+ let generatedColumnOffset = 0;
+ let generatedColumnOffsetLine = 0;
+ const sourceContents = [];
+ const nameMapping = new Map();
+ const nameIndexMapping = [];
+ const checkOriginalContent = (sourceIndex, line, column, expectedChunk) => {
+ let content =
+ sourceIndex < sourceContents.length
+ ? sourceContents[sourceIndex]
+ : undefined;
+ if (content === undefined) return false;
+ if (typeof content === "string") {
+ content = splitIntoLines(content);
+ sourceContents[sourceIndex] = content;
+ }
+ const contentLine = line <= content.length ? content[line - 1] : null;
+ if (contentLine === null) return false;
+ return (
+ contentLine.slice(column, column + expectedChunk.length) ===
+ expectedChunk
+ );
+ };
+ let { generatedLine, generatedColumn } = streamChunks(
+ this._source,
+ Object.assign({}, options, { finalSource: false }),
+ (
+ chunk,
+ generatedLine,
+ generatedColumn,
+ sourceIndex,
+ originalLine,
+ originalColumn,
+ nameIndex
+ ) => {
+ let chunkPos = 0;
+ let endPos = pos + chunk.length;
+
+ // Skip over when it has been replaced
+ if (replacmentEnd > pos) {
+ // Skip over the whole chunk
+ if (replacmentEnd >= endPos) {
+ const line = generatedLine + generatedLineOffset;
+ if (chunk.endsWith("\n")) {
+ generatedLineOffset--;
+ if (generatedColumnOffsetLine === line) {
+ // undo exiting corrections form the current line
+ generatedColumnOffset += generatedColumn;
+ }
+ } else if (generatedColumnOffsetLine === line) {
+ generatedColumnOffset -= chunk.length;
+ } else {
+ generatedColumnOffset = -chunk.length;
+ generatedColumnOffsetLine = line;
+ }
+ pos = endPos;
+ return;
+ }
+
+ // Partially skip over chunk
+ chunkPos = replacmentEnd - pos;
+ if (
+ checkOriginalContent(
+ sourceIndex,
+ originalLine,
+ originalColumn,
+ chunk.slice(0, chunkPos)
+ )
+ ) {
+ originalColumn += chunkPos;
+ }
+ pos += chunkPos;
+ const line = generatedLine + generatedLineOffset;
+ if (generatedColumnOffsetLine === line) {
+ generatedColumnOffset -= chunkPos;
+ } else {
+ generatedColumnOffset = -chunkPos;
+ generatedColumnOffsetLine = line;
+ }
+ generatedColumn += chunkPos;
+ }
+
+ // Is a replacement in the chunk?
+ if (nextReplacement < endPos) {
+ do {
+ let line = generatedLine + generatedLineOffset;
+ if (nextReplacement > pos) {
+ // Emit chunk until replacement
+ const offset = nextReplacement - pos;
+ const chunkSlice = chunk.slice(chunkPos, chunkPos + offset);
+ onChunk(
+ chunkSlice,
+ line,
+ generatedColumn +
+ (line === generatedColumnOffsetLine
+ ? generatedColumnOffset
+ : 0),
+ sourceIndex,
+ originalLine,
+ originalColumn,
+ nameIndex < 0 || nameIndex >= nameIndexMapping.length
+ ? -1
+ : nameIndexMapping[nameIndex]
+ );
+ generatedColumn += offset;
+ chunkPos += offset;
+ pos = nextReplacement;
+ if (
+ checkOriginalContent(
+ sourceIndex,
+ originalLine,
+ originalColumn,
+ chunkSlice
+ )
+ ) {
+ originalColumn += chunkSlice.length;
+ }
+ }
+
+ // Insert replacement content splitted into chunks by lines
+ const { content, name } = repls[i];
+ let matches = splitIntoLines(content);
+ let replacementNameIndex = nameIndex;
+ if (sourceIndex >= 0 && name) {
+ let globalIndex = nameMapping.get(name);
+ if (globalIndex === undefined) {
+ globalIndex = nameMapping.size;
+ nameMapping.set(name, globalIndex);
+ onName(globalIndex, name);
+ }
+ replacementNameIndex = globalIndex;
+ }
+ for (let m = 0; m < matches.length; m++) {
+ const contentLine = matches[m];
+ onChunk(
+ contentLine,
+ line,
+ generatedColumn +
+ (line === generatedColumnOffsetLine
+ ? generatedColumnOffset
+ : 0),
+ sourceIndex,
+ originalLine,
+ originalColumn,
+ replacementNameIndex
+ );
+
+ // Only the first chunk has name assigned
+ replacementNameIndex = -1;
+
+ if (m === matches.length - 1 && !contentLine.endsWith("\n")) {
+ if (generatedColumnOffsetLine === line) {
+ generatedColumnOffset += contentLine.length;
+ } else {
+ generatedColumnOffset = contentLine.length;
+ generatedColumnOffsetLine = line;
+ }
+ } else {
+ generatedLineOffset++;
+ line++;
+ generatedColumnOffset = -generatedColumn;
+ generatedColumnOffsetLine = line;
+ }
+ }
+
+ // Remove replaced content by settings this variable
+ replacmentEnd = Math.max(
+ replacmentEnd,
+ Math.floor(repls[i].end + 1)
+ );
+
+ // Move to next replacment
+ i++;
+ nextReplacement =
+ i < repls.length
+ ? Math.floor(repls[i].start)
+ : MAX_SOURCE_POSITION;
+
+ // Skip over when it has been replaced
+ const offset = chunk.length - endPos + replacmentEnd - chunkPos;
+ if (offset > 0) {
+ // Skip over whole chunk
+ if (replacmentEnd >= endPos) {
+ let line = generatedLine + generatedLineOffset;
+ if (chunk.endsWith("\n")) {
+ generatedLineOffset--;
+ if (generatedColumnOffsetLine === line) {
+ // undo exiting corrections form the current line
+ generatedColumnOffset += generatedColumn;
+ }
+ } else if (generatedColumnOffsetLine === line) {
+ generatedColumnOffset -= chunk.length - chunkPos;
+ } else {
+ generatedColumnOffset = chunkPos - chunk.length;
+ generatedColumnOffsetLine = line;
+ }
+ pos = endPos;
+ return;
+ }
+
+ // Partially skip over chunk
+ const line = generatedLine + generatedLineOffset;
+ if (
+ checkOriginalContent(
+ sourceIndex,
+ originalLine,
+ originalColumn,
+ chunk.slice(chunkPos, chunkPos + offset)
+ )
+ ) {
+ originalColumn += offset;
+ }
+ chunkPos += offset;
+ pos += offset;
+ if (generatedColumnOffsetLine === line) {
+ generatedColumnOffset -= offset;
+ } else {
+ generatedColumnOffset = -offset;
+ generatedColumnOffsetLine = line;
+ }
+ generatedColumn += offset;
+ }
+ } while (nextReplacement < endPos);
+ }
+
+ // Emit remaining chunk
+ if (chunkPos < chunk.length) {
+ const chunkSlice = chunkPos === 0 ? chunk : chunk.slice(chunkPos);
+ const line = generatedLine + generatedLineOffset;
+ onChunk(
+ chunkSlice,
+ line,
+ generatedColumn +
+ (line === generatedColumnOffsetLine ? generatedColumnOffset : 0),
+ sourceIndex,
+ originalLine,
+ originalColumn,
+ nameIndex < 0 ? -1 : nameIndexMapping[nameIndex]
+ );
+ }
+ pos = endPos;
+ },
+ (sourceIndex, source, sourceContent) => {
+ while (sourceContents.length < sourceIndex)
+ sourceContents.push(undefined);
+ sourceContents[sourceIndex] = sourceContent;
+ onSource(sourceIndex, source, sourceContent);
+ },
+ (nameIndex, name) => {
+ let globalIndex = nameMapping.get(name);
+ if (globalIndex === undefined) {
+ globalIndex = nameMapping.size;
+ nameMapping.set(name, globalIndex);
+ onName(globalIndex, name);
+ }
+ nameIndexMapping[nameIndex] = globalIndex;
+ }
+ );
+
+ // Handle remaining replacements
+ let remainer = "";
+ for (; i < repls.length; i++) {
+ remainer += repls[i].content;
+ }
+
+ // Insert remaining replacements content splitted into chunks by lines
+ let line = generatedLine + generatedLineOffset;
+ let matches = splitIntoLines(remainer);
+ for (let m = 0; m < matches.length; m++) {
+ const contentLine = matches[m];
+ onChunk(
+ contentLine,
+ line,
+ generatedColumn +
+ (line === generatedColumnOffsetLine ? generatedColumnOffset : 0),
+ -1,
+ -1,
+ -1,
+ -1
+ );
+
+ if (m === matches.length - 1 && !contentLine.endsWith("\n")) {
+ if (generatedColumnOffsetLine === line) {
+ generatedColumnOffset += contentLine.length;
+ } else {
+ generatedColumnOffset = contentLine.length;
+ generatedColumnOffsetLine = line;
+ }
+ } else {
+ generatedLineOffset++;
+ line++;
+ generatedColumnOffset = -generatedColumn;
+ generatedColumnOffsetLine = line;
+ }
+ }
+
+ return {
+ generatedLine: line,
+ generatedColumn:
+ generatedColumn +
+ (line === generatedColumnOffsetLine ? generatedColumnOffset : 0)
+ };
+ }
+
+ updateHash(hash) {
+ this._sortReplacements();
+ hash.update("ReplaceSource");
+ this._source.updateHash(hash);
+ hash.update(this._name || "");
+ for (const repl of this._replacements) {
+ hash.update(`${repl.start}${repl.end}${repl.content}${repl.name}`);
+ }
+ }
+}
+
+module.exports = ReplaceSource;