source: frontend/node_modules/@jridgewell/gen-mapping/src/gen-mapping.ts

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 2 weeks ago

Fix frontend appearance

  • Property mode set to 100644
File size: 16.7 KB
RevLine 
[9af201e]1import { SetArray, put, remove } from './set-array';
2import {
3 encode,
4 // encodeGeneratedRanges,
5 // encodeOriginalScopes
6} from '@jridgewell/sourcemap-codec';
7import { TraceMap, decodedMappings } from '@jridgewell/trace-mapping';
8
9import {
10 COLUMN,
11 SOURCES_INDEX,
12 SOURCE_LINE,
13 SOURCE_COLUMN,
14 NAMES_INDEX,
15} from './sourcemap-segment';
16
17import type { SourceMapInput } from '@jridgewell/trace-mapping';
18// import type { OriginalScope, GeneratedRange } from '@jridgewell/sourcemap-codec';
19import type { SourceMapSegment } from './sourcemap-segment';
20import type {
21 DecodedSourceMap,
22 EncodedSourceMap,
23 Pos,
24 Mapping,
25 // BindingExpressionRange,
26 // OriginalPos,
27 // OriginalScopeInfo,
28 // GeneratedRangeInfo,
29} from './types';
30
31export type { DecodedSourceMap, EncodedSourceMap, Mapping };
32
33export type Options = {
34 file?: string | null;
35 sourceRoot?: string | null;
36};
37
38const NO_NAME = -1;
39
40/**
41 * Provides the state to generate a sourcemap.
42 */
43export class GenMapping {
44 declare private _names: SetArray<string>;
45 declare private _sources: SetArray<string>;
46 declare private _sourcesContent: (string | null)[];
47 declare private _mappings: SourceMapSegment[][];
48 // private declare _originalScopes: OriginalScope[][];
49 // private declare _generatedRanges: GeneratedRange[];
50 declare private _ignoreList: SetArray<number>;
51 declare file: string | null | undefined;
52 declare sourceRoot: string | null | undefined;
53
54 constructor({ file, sourceRoot }: Options = {}) {
55 this._names = new SetArray();
56 this._sources = new SetArray();
57 this._sourcesContent = [];
58 this._mappings = [];
59 // this._originalScopes = [];
60 // this._generatedRanges = [];
61 this.file = file;
62 this.sourceRoot = sourceRoot;
63 this._ignoreList = new SetArray();
64 }
65}
66
67interface PublicMap {
68 _names: GenMapping['_names'];
69 _sources: GenMapping['_sources'];
70 _sourcesContent: GenMapping['_sourcesContent'];
71 _mappings: GenMapping['_mappings'];
72 // _originalScopes: GenMapping['_originalScopes'];
73 // _generatedRanges: GenMapping['_generatedRanges'];
74 _ignoreList: GenMapping['_ignoreList'];
75}
76
77/**
78 * Typescript doesn't allow friend access to private fields, so this just casts the map into a type
79 * with public access modifiers.
80 */
81function cast(map: unknown): PublicMap {
82 return map as any;
83}
84
85/**
86 * A low-level API to associate a generated position with an original source position. Line and
87 * column here are 0-based, unlike `addMapping`.
88 */
89export function addSegment(
90 map: GenMapping,
91 genLine: number,
92 genColumn: number,
93 source?: null,
94 sourceLine?: null,
95 sourceColumn?: null,
96 name?: null,
97 content?: null,
98): void;
99export function addSegment(
100 map: GenMapping,
101 genLine: number,
102 genColumn: number,
103 source: string,
104 sourceLine: number,
105 sourceColumn: number,
106 name?: null,
107 content?: string | null,
108): void;
109export function addSegment(
110 map: GenMapping,
111 genLine: number,
112 genColumn: number,
113 source: string,
114 sourceLine: number,
115 sourceColumn: number,
116 name: string,
117 content?: string | null,
118): void;
119export function addSegment(
120 map: GenMapping,
121 genLine: number,
122 genColumn: number,
123 source?: string | null,
124 sourceLine?: number | null,
125 sourceColumn?: number | null,
126 name?: string | null,
127 content?: string | null,
128): void {
129 return addSegmentInternal(
130 false,
131 map,
132 genLine,
133 genColumn,
134 source,
135 sourceLine,
136 sourceColumn,
137 name,
138 content,
139 );
140}
141
142/**
143 * A high-level API to associate a generated position with an original source position. Line is
144 * 1-based, but column is 0-based, due to legacy behavior in `source-map` library.
145 */
146export function addMapping(
147 map: GenMapping,
148 mapping: {
149 generated: Pos;
150 source?: null;
151 original?: null;
152 name?: null;
153 content?: null;
154 },
155): void;
156export function addMapping(
157 map: GenMapping,
158 mapping: {
159 generated: Pos;
160 source: string;
161 original: Pos;
162 name?: null;
163 content?: string | null;
164 },
165): void;
166export function addMapping(
167 map: GenMapping,
168 mapping: {
169 generated: Pos;
170 source: string;
171 original: Pos;
172 name: string;
173 content?: string | null;
174 },
175): void;
176export function addMapping(
177 map: GenMapping,
178 mapping: {
179 generated: Pos;
180 source?: string | null;
181 original?: Pos | null;
182 name?: string | null;
183 content?: string | null;
184 },
185): void {
186 return addMappingInternal(false, map, mapping as Parameters<typeof addMappingInternal>[2]);
187}
188
189/**
190 * Same as `addSegment`, but will only add the segment if it generates useful information in the
191 * resulting map. This only works correctly if segments are added **in order**, meaning you should
192 * not add a segment with a lower generated line/column than one that came before.
193 */
194export const maybeAddSegment: typeof addSegment = (
195 map,
196 genLine,
197 genColumn,
198 source,
199 sourceLine,
200 sourceColumn,
201 name,
202 content,
203) => {
204 return addSegmentInternal(
205 true,
206 map,
207 genLine,
208 genColumn,
209 source,
210 sourceLine,
211 sourceColumn,
212 name,
213 content,
214 );
215};
216
217/**
218 * Same as `addMapping`, but will only add the mapping if it generates useful information in the
219 * resulting map. This only works correctly if mappings are added **in order**, meaning you should
220 * not add a mapping with a lower generated line/column than one that came before.
221 */
222export const maybeAddMapping: typeof addMapping = (map, mapping) => {
223 return addMappingInternal(true, map, mapping as Parameters<typeof addMappingInternal>[2]);
224};
225
226/**
227 * Adds/removes the content of the source file to the source map.
228 */
229export function setSourceContent(map: GenMapping, source: string, content: string | null): void {
230 const {
231 _sources: sources,
232 _sourcesContent: sourcesContent,
233 // _originalScopes: originalScopes,
234 } = cast(map);
235 const index = put(sources, source);
236 sourcesContent[index] = content;
237 // if (index === originalScopes.length) originalScopes[index] = [];
238}
239
240export function setIgnore(map: GenMapping, source: string, ignore = true) {
241 const {
242 _sources: sources,
243 _sourcesContent: sourcesContent,
244 _ignoreList: ignoreList,
245 // _originalScopes: originalScopes,
246 } = cast(map);
247 const index = put(sources, source);
248 if (index === sourcesContent.length) sourcesContent[index] = null;
249 // if (index === originalScopes.length) originalScopes[index] = [];
250 if (ignore) put(ignoreList, index);
251 else remove(ignoreList, index);
252}
253
254/**
255 * Returns a sourcemap object (with decoded mappings) suitable for passing to a library that expects
256 * a sourcemap, or to JSON.stringify.
257 */
258export function toDecodedMap(map: GenMapping): DecodedSourceMap {
259 const {
260 _mappings: mappings,
261 _sources: sources,
262 _sourcesContent: sourcesContent,
263 _names: names,
264 _ignoreList: ignoreList,
265 // _originalScopes: originalScopes,
266 // _generatedRanges: generatedRanges,
267 } = cast(map);
268 removeEmptyFinalLines(mappings);
269
270 return {
271 version: 3,
272 file: map.file || undefined,
273 names: names.array,
274 sourceRoot: map.sourceRoot || undefined,
275 sources: sources.array,
276 sourcesContent,
277 mappings,
278 // originalScopes,
279 // generatedRanges,
280 ignoreList: ignoreList.array,
281 };
282}
283
284/**
285 * Returns a sourcemap object (with encoded mappings) suitable for passing to a library that expects
286 * a sourcemap, or to JSON.stringify.
287 */
288export function toEncodedMap(map: GenMapping): EncodedSourceMap {
289 const decoded = toDecodedMap(map);
290 return Object.assign({}, decoded, {
291 // originalScopes: decoded.originalScopes.map((os) => encodeOriginalScopes(os)),
292 // generatedRanges: encodeGeneratedRanges(decoded.generatedRanges as GeneratedRange[]),
293 mappings: encode(decoded.mappings as SourceMapSegment[][]),
294 });
295}
296
297/**
298 * Constructs a new GenMapping, using the already present mappings of the input.
299 */
300export function fromMap(input: SourceMapInput): GenMapping {
301 const map = new TraceMap(input);
302 const gen = new GenMapping({ file: map.file, sourceRoot: map.sourceRoot });
303
304 putAll(cast(gen)._names, map.names);
305 putAll(cast(gen)._sources, map.sources as string[]);
306 cast(gen)._sourcesContent = map.sourcesContent || map.sources.map(() => null);
307 cast(gen)._mappings = decodedMappings(map) as GenMapping['_mappings'];
308 // TODO: implement originalScopes/generatedRanges
309 if (map.ignoreList) putAll(cast(gen)._ignoreList, map.ignoreList);
310
311 return gen;
312}
313
314/**
315 * Returns an array of high-level mapping objects for every recorded segment, which could then be
316 * passed to the `source-map` library.
317 */
318export function allMappings(map: GenMapping): Mapping[] {
319 const out: Mapping[] = [];
320 const { _mappings: mappings, _sources: sources, _names: names } = cast(map);
321
322 for (let i = 0; i < mappings.length; i++) {
323 const line = mappings[i];
324 for (let j = 0; j < line.length; j++) {
325 const seg = line[j];
326
327 const generated = { line: i + 1, column: seg[COLUMN] };
328 let source: string | undefined = undefined;
329 let original: Pos | undefined = undefined;
330 let name: string | undefined = undefined;
331
332 if (seg.length !== 1) {
333 source = sources.array[seg[SOURCES_INDEX]];
334 original = { line: seg[SOURCE_LINE] + 1, column: seg[SOURCE_COLUMN] };
335
336 if (seg.length === 5) name = names.array[seg[NAMES_INDEX]];
337 }
338
339 out.push({ generated, source, original, name } as Mapping);
340 }
341 }
342
343 return out;
344}
345
346// This split declaration is only so that terser can elminiate the static initialization block.
347function addSegmentInternal<S extends string | null | undefined>(
348 skipable: boolean,
349 map: GenMapping,
350 genLine: number,
351 genColumn: number,
352 source: S,
353 sourceLine: S extends string ? number : null | undefined,
354 sourceColumn: S extends string ? number : null | undefined,
355 name: S extends string ? string | null | undefined : null | undefined,
356 content: S extends string ? string | null | undefined : null | undefined,
357): void {
358 const {
359 _mappings: mappings,
360 _sources: sources,
361 _sourcesContent: sourcesContent,
362 _names: names,
363 // _originalScopes: originalScopes,
364 } = cast(map);
365 const line = getIndex(mappings, genLine);
366 const index = getColumnIndex(line, genColumn);
367
368 if (!source) {
369 if (skipable && skipSourceless(line, index)) return;
370 return insert(line, index, [genColumn]);
371 }
372
373 // Sigh, TypeScript can't figure out sourceLine and sourceColumn aren't nullish if source
374 // isn't nullish.
375 assert<number>(sourceLine);
376 assert<number>(sourceColumn);
377
378 const sourcesIndex = put(sources, source);
379 const namesIndex = name ? put(names, name) : NO_NAME;
380 if (sourcesIndex === sourcesContent.length) sourcesContent[sourcesIndex] = content ?? null;
381 // if (sourcesIndex === originalScopes.length) originalScopes[sourcesIndex] = [];
382
383 if (skipable && skipSource(line, index, sourcesIndex, sourceLine, sourceColumn, namesIndex)) {
384 return;
385 }
386
387 return insert(
388 line,
389 index,
390 name
391 ? [genColumn, sourcesIndex, sourceLine, sourceColumn, namesIndex]
392 : [genColumn, sourcesIndex, sourceLine, sourceColumn],
393 );
394}
395
396function assert<T>(_val: unknown): asserts _val is T {
397 // noop.
398}
399
400function getIndex<T>(arr: T[][], index: number): T[] {
401 for (let i = arr.length; i <= index; i++) {
402 arr[i] = [];
403 }
404 return arr[index];
405}
406
407function getColumnIndex(line: SourceMapSegment[], genColumn: number): number {
408 let index = line.length;
409 for (let i = index - 1; i >= 0; index = i--) {
410 const current = line[i];
411 if (genColumn >= current[COLUMN]) break;
412 }
413 return index;
414}
415
416function insert<T>(array: T[], index: number, value: T) {
417 for (let i = array.length; i > index; i--) {
418 array[i] = array[i - 1];
419 }
420 array[index] = value;
421}
422
423function removeEmptyFinalLines(mappings: SourceMapSegment[][]) {
424 const { length } = mappings;
425 let len = length;
426 for (let i = len - 1; i >= 0; len = i, i--) {
427 if (mappings[i].length > 0) break;
428 }
429 if (len < length) mappings.length = len;
430}
431
432function putAll<T extends string | number>(setarr: SetArray<T>, array: T[]) {
433 for (let i = 0; i < array.length; i++) put(setarr, array[i]);
434}
435
436function skipSourceless(line: SourceMapSegment[], index: number): boolean {
437 // The start of a line is already sourceless, so adding a sourceless segment to the beginning
438 // doesn't generate any useful information.
439 if (index === 0) return true;
440
441 const prev = line[index - 1];
442 // If the previous segment is also sourceless, then adding another sourceless segment doesn't
443 // genrate any new information. Else, this segment will end the source/named segment and point to
444 // a sourceless position, which is useful.
445 return prev.length === 1;
446}
447
448function skipSource(
449 line: SourceMapSegment[],
450 index: number,
451 sourcesIndex: number,
452 sourceLine: number,
453 sourceColumn: number,
454 namesIndex: number,
455): boolean {
456 // A source/named segment at the start of a line gives position at that genColumn
457 if (index === 0) return false;
458
459 const prev = line[index - 1];
460
461 // If the previous segment is sourceless, then we're transitioning to a source.
462 if (prev.length === 1) return false;
463
464 // If the previous segment maps to the exact same source position, then this segment doesn't
465 // provide any new position information.
466 return (
467 sourcesIndex === prev[SOURCES_INDEX] &&
468 sourceLine === prev[SOURCE_LINE] &&
469 sourceColumn === prev[SOURCE_COLUMN] &&
470 namesIndex === (prev.length === 5 ? prev[NAMES_INDEX] : NO_NAME)
471 );
472}
473
474function addMappingInternal<S extends string | null | undefined>(
475 skipable: boolean,
476 map: GenMapping,
477 mapping: {
478 generated: Pos;
479 source: S;
480 original: S extends string ? Pos : null | undefined;
481 name: S extends string ? string | null | undefined : null | undefined;
482 content: S extends string ? string | null | undefined : null | undefined;
483 },
484) {
485 const { generated, source, original, name, content } = mapping;
486 if (!source) {
487 return addSegmentInternal(
488 skipable,
489 map,
490 generated.line - 1,
491 generated.column,
492 null,
493 null,
494 null,
495 null,
496 null,
497 );
498 }
499 assert<Pos>(original);
500 return addSegmentInternal(
501 skipable,
502 map,
503 generated.line - 1,
504 generated.column,
505 source as string,
506 original.line - 1,
507 original.column,
508 name,
509 content,
510 );
511}
512
513/*
514export function addOriginalScope(
515 map: GenMapping,
516 data: {
517 start: Pos;
518 end: Pos;
519 source: string;
520 kind: string;
521 name?: string;
522 variables?: string[];
523 },
524): OriginalScopeInfo {
525 const { start, end, source, kind, name, variables } = data;
526 const {
527 _sources: sources,
528 _sourcesContent: sourcesContent,
529 _originalScopes: originalScopes,
530 _names: names,
531 } = cast(map);
532 const index = put(sources, source);
533 if (index === sourcesContent.length) sourcesContent[index] = null;
534 if (index === originalScopes.length) originalScopes[index] = [];
535
536 const kindIndex = put(names, kind);
537 const scope: OriginalScope = name
538 ? [start.line - 1, start.column, end.line - 1, end.column, kindIndex, put(names, name)]
539 : [start.line - 1, start.column, end.line - 1, end.column, kindIndex];
540 if (variables) {
541 scope.vars = variables.map((v) => put(names, v));
542 }
543 const len = originalScopes[index].push(scope);
544 return [index, len - 1, variables];
545}
546*/
547
548// Generated Ranges
549/*
550export function addGeneratedRange(
551 map: GenMapping,
552 data: {
553 start: Pos;
554 isScope: boolean;
555 originalScope?: OriginalScopeInfo;
556 callsite?: OriginalPos;
557 },
558): GeneratedRangeInfo {
559 const { start, isScope, originalScope, callsite } = data;
560 const {
561 _originalScopes: originalScopes,
562 _sources: sources,
563 _sourcesContent: sourcesContent,
564 _generatedRanges: generatedRanges,
565 } = cast(map);
566
567 const range: GeneratedRange = [
568 start.line - 1,
569 start.column,
570 0,
571 0,
572 originalScope ? originalScope[0] : -1,
573 originalScope ? originalScope[1] : -1,
574 ];
575 if (originalScope?.[2]) {
576 range.bindings = originalScope[2].map(() => [[-1]]);
577 }
578 if (callsite) {
579 const index = put(sources, callsite.source);
580 if (index === sourcesContent.length) sourcesContent[index] = null;
581 if (index === originalScopes.length) originalScopes[index] = [];
582 range.callsite = [index, callsite.line - 1, callsite.column];
583 }
584 if (isScope) range.isScope = true;
585 generatedRanges.push(range);
586
587 return [range, originalScope?.[2]];
588}
589
590export function setEndPosition(range: GeneratedRangeInfo, pos: Pos) {
591 range[0][2] = pos.line - 1;
592 range[0][3] = pos.column;
593}
594
595export function addBinding(
596 map: GenMapping,
597 range: GeneratedRangeInfo,
598 variable: string,
599 expression: string | BindingExpressionRange,
600) {
601 const { _names: names } = cast(map);
602 const bindings = (range[0].bindings ||= []);
603 const vars = range[1];
604
605 const index = vars!.indexOf(variable);
606 const binding = getIndex(bindings, index);
607
608 if (typeof expression === 'string') binding[0] = [put(names, expression)];
609 else {
610 const { start } = expression;
611 binding.push([put(names, expression.expression), start.line - 1, start.column]);
612 }
613}
614*/
Note: See TracBrowser for help on using the repository browser.