source: imaps-frontend/node_modules/webpack-sources/lib/ReplaceSource.js@ 79a0317

main
Last change on this file since 79a0317 was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 3 days ago

F4 Finalna Verzija

  • Property mode set to 100644
File size: 12.3 KB
RevLine 
[79a0317]1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5"use strict";
6
7const { getMap, getSourceAndMap } = require("./helpers/getFromStreamChunks");
8const streamChunks = require("./helpers/streamChunks");
9const Source = require("./Source");
10const splitIntoLines = require("./helpers/splitIntoLines");
11
12// since v8 7.0, Array.prototype.sort is stable
13const hasStableSort =
14 typeof process === "object" &&
15 process.versions &&
16 typeof process.versions.v8 === "string" &&
17 !/^[0-6]\./.test(process.versions.v8);
18
19// This is larger than max string length
20const MAX_SOURCE_POSITION = 0x20000000;
21
22class Replacement {
23 constructor(start, end, content, name) {
24 this.start = start;
25 this.end = end;
26 this.content = content;
27 this.name = name;
28 if (!hasStableSort) {
29 this.index = -1;
30 }
31 }
32}
33
34class ReplaceSource extends Source {
35 constructor(source, name) {
36 super();
37 this._source = source;
38 this._name = name;
39 /** @type {Replacement[]} */
40 this._replacements = [];
41 this._isSorted = true;
42 }
43
44 getName() {
45 return this._name;
46 }
47
48 getReplacements() {
49 this._sortReplacements();
50 return this._replacements;
51 }
52
53 replace(start, end, newValue, name) {
54 if (typeof newValue !== "string")
55 throw new Error(
56 "insertion must be a string, but is a " + typeof newValue
57 );
58 this._replacements.push(new Replacement(start, end, newValue, name));
59 this._isSorted = false;
60 }
61
62 insert(pos, newValue, name) {
63 if (typeof newValue !== "string")
64 throw new Error(
65 "insertion must be a string, but is a " +
66 typeof newValue +
67 ": " +
68 newValue
69 );
70 this._replacements.push(new Replacement(pos, pos - 1, newValue, name));
71 this._isSorted = false;
72 }
73
74 source() {
75 if (this._replacements.length === 0) {
76 return this._source.source();
77 }
78 let current = this._source.source();
79 let pos = 0;
80 const result = [];
81
82 this._sortReplacements();
83 for (const replacement of this._replacements) {
84 const start = Math.floor(replacement.start);
85 const end = Math.floor(replacement.end + 1);
86 if (pos < start) {
87 const offset = start - pos;
88 result.push(current.slice(0, offset));
89 current = current.slice(offset);
90 pos = start;
91 }
92 result.push(replacement.content);
93 if (pos < end) {
94 const offset = end - pos;
95 current = current.slice(offset);
96 pos = end;
97 }
98 }
99 result.push(current);
100 return result.join("");
101 }
102
103 map(options) {
104 if (this._replacements.length === 0) {
105 return this._source.map(options);
106 }
107 return getMap(this, options);
108 }
109
110 sourceAndMap(options) {
111 if (this._replacements.length === 0) {
112 return this._source.sourceAndMap(options);
113 }
114 return getSourceAndMap(this, options);
115 }
116
117 original() {
118 return this._source;
119 }
120
121 _sortReplacements() {
122 if (this._isSorted) return;
123 if (hasStableSort) {
124 this._replacements.sort(function (a, b) {
125 const diff1 = a.start - b.start;
126 if (diff1 !== 0) return diff1;
127 const diff2 = a.end - b.end;
128 if (diff2 !== 0) return diff2;
129 return 0;
130 });
131 } else {
132 this._replacements.forEach((repl, i) => (repl.index = i));
133 this._replacements.sort(function (a, b) {
134 const diff1 = a.start - b.start;
135 if (diff1 !== 0) return diff1;
136 const diff2 = a.end - b.end;
137 if (diff2 !== 0) return diff2;
138 return a.index - b.index;
139 });
140 }
141 this._isSorted = true;
142 }
143
144 streamChunks(options, onChunk, onSource, onName) {
145 this._sortReplacements();
146 const repls = this._replacements;
147 let pos = 0;
148 let i = 0;
149 let replacmentEnd = -1;
150 let nextReplacement =
151 i < repls.length ? Math.floor(repls[i].start) : MAX_SOURCE_POSITION;
152 let generatedLineOffset = 0;
153 let generatedColumnOffset = 0;
154 let generatedColumnOffsetLine = 0;
155 const sourceContents = [];
156 const nameMapping = new Map();
157 const nameIndexMapping = [];
158 const checkOriginalContent = (sourceIndex, line, column, expectedChunk) => {
159 let content =
160 sourceIndex < sourceContents.length
161 ? sourceContents[sourceIndex]
162 : undefined;
163 if (content === undefined) return false;
164 if (typeof content === "string") {
165 content = splitIntoLines(content);
166 sourceContents[sourceIndex] = content;
167 }
168 const contentLine = line <= content.length ? content[line - 1] : null;
169 if (contentLine === null) return false;
170 return (
171 contentLine.slice(column, column + expectedChunk.length) ===
172 expectedChunk
173 );
174 };
175 let { generatedLine, generatedColumn } = streamChunks(
176 this._source,
177 Object.assign({}, options, { finalSource: false }),
178 (
179 chunk,
180 generatedLine,
181 generatedColumn,
182 sourceIndex,
183 originalLine,
184 originalColumn,
185 nameIndex
186 ) => {
187 let chunkPos = 0;
188 let endPos = pos + chunk.length;
189
190 // Skip over when it has been replaced
191 if (replacmentEnd > pos) {
192 // Skip over the whole chunk
193 if (replacmentEnd >= endPos) {
194 const line = generatedLine + generatedLineOffset;
195 if (chunk.endsWith("\n")) {
196 generatedLineOffset--;
197 if (generatedColumnOffsetLine === line) {
198 // undo exiting corrections form the current line
199 generatedColumnOffset += generatedColumn;
200 }
201 } else if (generatedColumnOffsetLine === line) {
202 generatedColumnOffset -= chunk.length;
203 } else {
204 generatedColumnOffset = -chunk.length;
205 generatedColumnOffsetLine = line;
206 }
207 pos = endPos;
208 return;
209 }
210
211 // Partially skip over chunk
212 chunkPos = replacmentEnd - pos;
213 if (
214 checkOriginalContent(
215 sourceIndex,
216 originalLine,
217 originalColumn,
218 chunk.slice(0, chunkPos)
219 )
220 ) {
221 originalColumn += chunkPos;
222 }
223 pos += chunkPos;
224 const line = generatedLine + generatedLineOffset;
225 if (generatedColumnOffsetLine === line) {
226 generatedColumnOffset -= chunkPos;
227 } else {
228 generatedColumnOffset = -chunkPos;
229 generatedColumnOffsetLine = line;
230 }
231 generatedColumn += chunkPos;
232 }
233
234 // Is a replacement in the chunk?
235 if (nextReplacement < endPos) {
236 do {
237 let line = generatedLine + generatedLineOffset;
238 if (nextReplacement > pos) {
239 // Emit chunk until replacement
240 const offset = nextReplacement - pos;
241 const chunkSlice = chunk.slice(chunkPos, chunkPos + offset);
242 onChunk(
243 chunkSlice,
244 line,
245 generatedColumn +
246 (line === generatedColumnOffsetLine
247 ? generatedColumnOffset
248 : 0),
249 sourceIndex,
250 originalLine,
251 originalColumn,
252 nameIndex < 0 || nameIndex >= nameIndexMapping.length
253 ? -1
254 : nameIndexMapping[nameIndex]
255 );
256 generatedColumn += offset;
257 chunkPos += offset;
258 pos = nextReplacement;
259 if (
260 checkOriginalContent(
261 sourceIndex,
262 originalLine,
263 originalColumn,
264 chunkSlice
265 )
266 ) {
267 originalColumn += chunkSlice.length;
268 }
269 }
270
271 // Insert replacement content splitted into chunks by lines
272 const { content, name } = repls[i];
273 let matches = splitIntoLines(content);
274 let replacementNameIndex = nameIndex;
275 if (sourceIndex >= 0 && name) {
276 let globalIndex = nameMapping.get(name);
277 if (globalIndex === undefined) {
278 globalIndex = nameMapping.size;
279 nameMapping.set(name, globalIndex);
280 onName(globalIndex, name);
281 }
282 replacementNameIndex = globalIndex;
283 }
284 for (let m = 0; m < matches.length; m++) {
285 const contentLine = matches[m];
286 onChunk(
287 contentLine,
288 line,
289 generatedColumn +
290 (line === generatedColumnOffsetLine
291 ? generatedColumnOffset
292 : 0),
293 sourceIndex,
294 originalLine,
295 originalColumn,
296 replacementNameIndex
297 );
298
299 // Only the first chunk has name assigned
300 replacementNameIndex = -1;
301
302 if (m === matches.length - 1 && !contentLine.endsWith("\n")) {
303 if (generatedColumnOffsetLine === line) {
304 generatedColumnOffset += contentLine.length;
305 } else {
306 generatedColumnOffset = contentLine.length;
307 generatedColumnOffsetLine = line;
308 }
309 } else {
310 generatedLineOffset++;
311 line++;
312 generatedColumnOffset = -generatedColumn;
313 generatedColumnOffsetLine = line;
314 }
315 }
316
317 // Remove replaced content by settings this variable
318 replacmentEnd = Math.max(
319 replacmentEnd,
320 Math.floor(repls[i].end + 1)
321 );
322
323 // Move to next replacment
324 i++;
325 nextReplacement =
326 i < repls.length
327 ? Math.floor(repls[i].start)
328 : MAX_SOURCE_POSITION;
329
330 // Skip over when it has been replaced
331 const offset = chunk.length - endPos + replacmentEnd - chunkPos;
332 if (offset > 0) {
333 // Skip over whole chunk
334 if (replacmentEnd >= endPos) {
335 let line = generatedLine + generatedLineOffset;
336 if (chunk.endsWith("\n")) {
337 generatedLineOffset--;
338 if (generatedColumnOffsetLine === line) {
339 // undo exiting corrections form the current line
340 generatedColumnOffset += generatedColumn;
341 }
342 } else if (generatedColumnOffsetLine === line) {
343 generatedColumnOffset -= chunk.length - chunkPos;
344 } else {
345 generatedColumnOffset = chunkPos - chunk.length;
346 generatedColumnOffsetLine = line;
347 }
348 pos = endPos;
349 return;
350 }
351
352 // Partially skip over chunk
353 const line = generatedLine + generatedLineOffset;
354 if (
355 checkOriginalContent(
356 sourceIndex,
357 originalLine,
358 originalColumn,
359 chunk.slice(chunkPos, chunkPos + offset)
360 )
361 ) {
362 originalColumn += offset;
363 }
364 chunkPos += offset;
365 pos += offset;
366 if (generatedColumnOffsetLine === line) {
367 generatedColumnOffset -= offset;
368 } else {
369 generatedColumnOffset = -offset;
370 generatedColumnOffsetLine = line;
371 }
372 generatedColumn += offset;
373 }
374 } while (nextReplacement < endPos);
375 }
376
377 // Emit remaining chunk
378 if (chunkPos < chunk.length) {
379 const chunkSlice = chunkPos === 0 ? chunk : chunk.slice(chunkPos);
380 const line = generatedLine + generatedLineOffset;
381 onChunk(
382 chunkSlice,
383 line,
384 generatedColumn +
385 (line === generatedColumnOffsetLine ? generatedColumnOffset : 0),
386 sourceIndex,
387 originalLine,
388 originalColumn,
389 nameIndex < 0 ? -1 : nameIndexMapping[nameIndex]
390 );
391 }
392 pos = endPos;
393 },
394 (sourceIndex, source, sourceContent) => {
395 while (sourceContents.length < sourceIndex)
396 sourceContents.push(undefined);
397 sourceContents[sourceIndex] = sourceContent;
398 onSource(sourceIndex, source, sourceContent);
399 },
400 (nameIndex, name) => {
401 let globalIndex = nameMapping.get(name);
402 if (globalIndex === undefined) {
403 globalIndex = nameMapping.size;
404 nameMapping.set(name, globalIndex);
405 onName(globalIndex, name);
406 }
407 nameIndexMapping[nameIndex] = globalIndex;
408 }
409 );
410
411 // Handle remaining replacements
412 let remainer = "";
413 for (; i < repls.length; i++) {
414 remainer += repls[i].content;
415 }
416
417 // Insert remaining replacements content splitted into chunks by lines
418 let line = generatedLine + generatedLineOffset;
419 let matches = splitIntoLines(remainer);
420 for (let m = 0; m < matches.length; m++) {
421 const contentLine = matches[m];
422 onChunk(
423 contentLine,
424 line,
425 generatedColumn +
426 (line === generatedColumnOffsetLine ? generatedColumnOffset : 0),
427 -1,
428 -1,
429 -1,
430 -1
431 );
432
433 if (m === matches.length - 1 && !contentLine.endsWith("\n")) {
434 if (generatedColumnOffsetLine === line) {
435 generatedColumnOffset += contentLine.length;
436 } else {
437 generatedColumnOffset = contentLine.length;
438 generatedColumnOffsetLine = line;
439 }
440 } else {
441 generatedLineOffset++;
442 line++;
443 generatedColumnOffset = -generatedColumn;
444 generatedColumnOffsetLine = line;
445 }
446 }
447
448 return {
449 generatedLine: line,
450 generatedColumn:
451 generatedColumn +
452 (line === generatedColumnOffsetLine ? generatedColumnOffset : 0)
453 };
454 }
455
456 updateHash(hash) {
457 this._sortReplacements();
458 hash.update("ReplaceSource");
459 this._source.updateHash(hash);
460 hash.update(this._name || "");
461 for (const repl of this._replacements) {
462 hash.update(`${repl.start}${repl.end}${repl.content}${repl.name}`);
463 }
464 }
465}
466
467module.exports = ReplaceSource;
Note: See TracBrowser for help on using the repository browser.