538 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			538 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| /**
 | |
|  * @license
 | |
|  * Copyright Google Inc. All Rights Reserved.
 | |
|  *
 | |
|  * Use of this source code is governed by an MIT-style license that can be
 | |
|  * found in the LICENSE file at https://angular.io/license
 | |
|  */
 | |
| import {encode} from 'sourcemap-codec';
 | |
| 
 | |
| import {absoluteFrom} from '../../../src/ngtsc/file_system';
 | |
| import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing';
 | |
| import {RawSourceMap} from '../../src/sourcemaps/raw_source_map';
 | |
| import {SegmentMarker} from '../../src/sourcemaps/segment_marker';
 | |
| import {computeStartOfLinePositions, ensureOriginalSegmentLinks, extractOriginalSegments, findLastMappingIndexBefore, Mapping, parseMappings, SourceFile} from '../../src/sourcemaps/source_file';
 | |
| 
 | |
| runInEachFileSystem(() => {
 | |
|   describe('SourceFile and utilities', () => {
 | |
|     let _: typeof absoluteFrom;
 | |
| 
 | |
|     beforeEach(() => {
 | |
|       _ = absoluteFrom;
 | |
|     });
 | |
| 
 | |
|     describe('parseMappings()', () => {
 | |
|       it('should be an empty array for source files with no source map', () => {
 | |
|         const mappings = parseMappings(null, [], []);
 | |
|         expect(mappings).toEqual([]);
 | |
|       });
 | |
| 
 | |
|       it('should be empty array for source files with no source map mappings', () => {
 | |
|         const rawSourceMap: RawSourceMap = {mappings: '', names: [], sources: [], version: 3};
 | |
|         const mappings = parseMappings(rawSourceMap, [], []);
 | |
|         expect(mappings).toEqual([]);
 | |
|       });
 | |
| 
 | |
|       it('should parse the mappings from the raw source map', () => {
 | |
|         const rawSourceMap: RawSourceMap = {
 | |
|           mappings: encode([[[0, 0, 0, 0], [6, 0, 0, 3]]]),
 | |
|           names: [],
 | |
|           sources: ['a.js'],
 | |
|           version: 3
 | |
|         };
 | |
|         const originalSource = new SourceFile(_('/foo/src/a.js'), 'abcdefg', null, false, []);
 | |
|         const mappings = parseMappings(rawSourceMap, [originalSource], [0, 8]);
 | |
|         expect(mappings).toEqual([
 | |
|           {
 | |
|             generatedSegment: {line: 0, column: 0, position: 0, next: undefined},
 | |
|             originalSource,
 | |
|             originalSegment: {line: 0, column: 0, position: 0, next: undefined},
 | |
|             name: undefined
 | |
|           },
 | |
|           {
 | |
|             generatedSegment: {line: 0, column: 6, position: 6, next: undefined},
 | |
|             originalSource,
 | |
|             originalSegment: {line: 0, column: 3, position: 3, next: undefined},
 | |
|             name: undefined
 | |
|           },
 | |
|         ]);
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     describe('extractOriginalSegments()', () => {
 | |
|       it('should return an empty Map for source files with no source map', () => {
 | |
|         expect(extractOriginalSegments(parseMappings(null, [], []))).toEqual(new Map());
 | |
|       });
 | |
| 
 | |
|       it('should be empty Map for source files with no source map mappings', () => {
 | |
|         const rawSourceMap: RawSourceMap = {mappings: '', names: [], sources: [], version: 3};
 | |
|         expect(extractOriginalSegments(parseMappings(rawSourceMap, [], []))).toEqual(new Map());
 | |
|       });
 | |
| 
 | |
|       it('should parse the segments in ascending order of original position from the raw source map',
 | |
|          () => {
 | |
|            const originalSource = new SourceFile(_('/foo/src/a.js'), 'abcdefg', null, false, []);
 | |
|            const rawSourceMap: RawSourceMap = {
 | |
|              mappings: encode([[[0, 0, 0, 0], [2, 0, 0, 3], [4, 0, 0, 2]]]),
 | |
|              names: [],
 | |
|              sources: ['a.js'],
 | |
|              version: 3
 | |
|            };
 | |
|            const originalSegments =
 | |
|                extractOriginalSegments(parseMappings(rawSourceMap, [originalSource], [0, 8]));
 | |
|            expect(originalSegments.get(originalSource)).toEqual([
 | |
|              {line: 0, column: 0, position: 0, next: undefined},
 | |
|              {line: 0, column: 2, position: 2, next: undefined},
 | |
|              {line: 0, column: 3, position: 3, next: undefined},
 | |
|            ]);
 | |
|          });
 | |
| 
 | |
|       it('should create separate arrays for each original source file', () => {
 | |
|         const sourceA = new SourceFile(_('/foo/src/a.js'), 'abcdefg', null, false, []);
 | |
|         const sourceB = new SourceFile(_('/foo/src/b.js'), '1234567', null, false, []);
 | |
|         const rawSourceMap: RawSourceMap = {
 | |
|           mappings:
 | |
|               encode([[[0, 0, 0, 0], [2, 1, 0, 3], [4, 0, 0, 2], [5, 1, 0, 5], [6, 1, 0, 2]]]),
 | |
|           names: [],
 | |
|           sources: ['a.js', 'b.js'],
 | |
|           version: 3
 | |
|         };
 | |
|         const originalSegments =
 | |
|             extractOriginalSegments(parseMappings(rawSourceMap, [sourceA, sourceB], [0, 8]));
 | |
|         expect(originalSegments.get(sourceA)).toEqual([
 | |
|           {line: 0, column: 0, position: 0, next: undefined},
 | |
|           {line: 0, column: 2, position: 2, next: undefined},
 | |
|         ]);
 | |
|         expect(originalSegments.get(sourceB)).toEqual([
 | |
|           {line: 0, column: 2, position: 2, next: undefined},
 | |
|           {line: 0, column: 3, position: 3, next: undefined},
 | |
|           {line: 0, column: 5, position: 5, next: undefined},
 | |
|         ]);
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     describe('findLastMappingIndexBefore', () => {
 | |
|       it('should find the highest mapping index that has a segment marker below the given one if there is not an exact match',
 | |
|          () => {
 | |
|            const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
 | |
|            const marker4: SegmentMarker = {line: 0, column: 40, position: 40, next: marker5};
 | |
|            const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
 | |
|            const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
 | |
|            const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
 | |
|            const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
 | |
|                marker => ({generatedSegment: marker} as Mapping));
 | |
| 
 | |
|            const marker: SegmentMarker = {line: 0, column: 35, position: 35, next: undefined};
 | |
|            const index = findLastMappingIndexBefore(mappings, marker, /* exclusive */ false, 0);
 | |
|            expect(index).toEqual(2);
 | |
|          });
 | |
| 
 | |
|       it('should find the highest mapping index that has a segment marker (when there are duplicates) below the given one if there is not an exact match',
 | |
|          () => {
 | |
|            const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
 | |
|            const marker4: SegmentMarker = {line: 0, column: 30, position: 30, next: marker5};
 | |
|            const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
 | |
|            const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
 | |
|            const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
 | |
|            const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
 | |
|                marker => ({generatedSegment: marker} as Mapping));
 | |
| 
 | |
|            const marker: SegmentMarker = {line: 0, column: 35, position: 35, next: undefined};
 | |
|            const index = findLastMappingIndexBefore(mappings, marker, /* exclusive */ false, 0);
 | |
|            expect(index).toEqual(3);
 | |
|          });
 | |
| 
 | |
|       it('should find the last mapping if the segment marker is higher than all of them', () => {
 | |
|         const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
 | |
|         const marker4: SegmentMarker = {line: 0, column: 40, position: 40, next: marker5};
 | |
|         const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
 | |
|         const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
 | |
|         const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
 | |
|         const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
 | |
|             marker => ({generatedSegment: marker} as Mapping));
 | |
| 
 | |
|         const marker: SegmentMarker = {line: 0, column: 60, position: 60, next: undefined};
 | |
| 
 | |
|         const index = findLastMappingIndexBefore(mappings, marker, /* exclusive */ false, 0);
 | |
|         expect(index).toEqual(4);
 | |
|       });
 | |
| 
 | |
|       it('should return -1 if the segment marker is lower than all of them', () => {
 | |
|         const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
 | |
|         const marker4: SegmentMarker = {line: 0, column: 40, position: 40, next: marker5};
 | |
|         const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
 | |
|         const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
 | |
|         const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
 | |
|         const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
 | |
|             marker => ({generatedSegment: marker} as Mapping));
 | |
| 
 | |
|         const marker: SegmentMarker = {line: 0, column: 5, position: 5, next: undefined};
 | |
| 
 | |
|         const index = findLastMappingIndexBefore(mappings, marker, /* exclusive */ false, 0);
 | |
|         expect(index).toEqual(-1);
 | |
|       });
 | |
| 
 | |
|       describe('[exact match inclusive]', () => {
 | |
|         it('should find the matching segment marker mapping index if there is only one of them',
 | |
|            () => {
 | |
|              const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
 | |
|              const marker4: SegmentMarker = {line: 0, column: 40, position: 40, next: marker5};
 | |
|              const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
 | |
|              const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
 | |
|              const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
 | |
| 
 | |
|              const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
 | |
|                  marker => ({generatedSegment: marker} as Mapping));
 | |
|              const index = findLastMappingIndexBefore(mappings, marker3, /* exclusive */ false, 0);
 | |
|              expect(index).toEqual(2);
 | |
|            });
 | |
| 
 | |
|         it('should find the highest matching segment marker mapping index if there is more than one of them',
 | |
|            () => {
 | |
|              const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
 | |
|              const marker4: SegmentMarker = {line: 0, column: 30, position: 30, next: marker5};
 | |
|              const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
 | |
|              const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
 | |
|              const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
 | |
| 
 | |
|              const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
 | |
|                  marker => ({generatedSegment: marker} as Mapping));
 | |
|              const index = findLastMappingIndexBefore(mappings, marker3, /* exclusive */ false, 0);
 | |
|              expect(index).toEqual(3);
 | |
|            });
 | |
|       });
 | |
| 
 | |
|       describe('[exact match exclusive]', () => {
 | |
|         it('should find the preceding mapping index if there is a matching segment marker', () => {
 | |
|           const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
 | |
|           const marker4: SegmentMarker = {line: 0, column: 40, position: 40, next: marker5};
 | |
|           const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
 | |
|           const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
 | |
|           const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
 | |
| 
 | |
|           const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
 | |
|               marker => ({generatedSegment: marker} as Mapping));
 | |
|           const index = findLastMappingIndexBefore(mappings, marker3, /* exclusive */ true, 0);
 | |
|           expect(index).toEqual(1);
 | |
|         });
 | |
| 
 | |
|         it('should find the highest preceding mapping index if there is more than one matching segment marker',
 | |
|            () => {
 | |
|              const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
 | |
|              const marker4: SegmentMarker = {line: 0, column: 30, position: 30, next: marker5};
 | |
|              const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
 | |
|              const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
 | |
|              const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
 | |
| 
 | |
|              const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
 | |
|                  marker => ({generatedSegment: marker} as Mapping));
 | |
|              const index = findLastMappingIndexBefore(mappings, marker3, /* exclusive */ false, 0);
 | |
|              expect(index).toEqual(3);
 | |
|            });
 | |
|       });
 | |
| 
 | |
|       describe('[with lowerIndex hint', () => {
 | |
|         it('should find the highest mapping index above the lowerIndex hint that has a segment marker below the given one if there is not an exact match',
 | |
|            () => {
 | |
|              const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
 | |
|              const marker4: SegmentMarker = {line: 0, column: 40, position: 40, next: marker5};
 | |
|              const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
 | |
|              const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
 | |
|              const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
 | |
|              const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
 | |
|                  marker => ({generatedSegment: marker} as Mapping));
 | |
| 
 | |
|              const marker: SegmentMarker = {line: 0, column: 35, position: 35, next: undefined};
 | |
|              const index = findLastMappingIndexBefore(mappings, marker, /* exclusive */ false, 1);
 | |
|              expect(index).toEqual(2);
 | |
|            });
 | |
| 
 | |
|         it('should return the lowerIndex mapping index if there is a single exact match and we are not exclusive',
 | |
|            () => {
 | |
|              const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
 | |
|              const marker4: SegmentMarker = {line: 0, column: 40, position: 40, next: marker5};
 | |
|              const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
 | |
|              const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
 | |
|              const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
 | |
|              const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
 | |
|                  marker => ({generatedSegment: marker} as Mapping));
 | |
| 
 | |
|              const marker: SegmentMarker = {line: 0, column: 30, position: 30, next: undefined};
 | |
|              const index = findLastMappingIndexBefore(mappings, marker, /* exclusive */ false, 2);
 | |
|              expect(index).toEqual(2);
 | |
|            });
 | |
| 
 | |
|         it('should return the lowerIndex mapping index if there are multiple exact matches and we are not exclusive',
 | |
|            () => {
 | |
|              const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
 | |
|              const marker4: SegmentMarker = {line: 0, column: 30, position: 30, next: marker5};
 | |
|              const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
 | |
|              const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
 | |
|              const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
 | |
|              const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
 | |
|                  marker => ({generatedSegment: marker} as Mapping));
 | |
| 
 | |
|              const marker: SegmentMarker = {line: 0, column: 30, position: 30, next: undefined};
 | |
|              const index = findLastMappingIndexBefore(mappings, marker, /* exclusive */ false, 3);
 | |
|              expect(index).toEqual(3);
 | |
|            });
 | |
| 
 | |
|         it('should return -1 if the segment marker is lower than the lowerIndex hint', () => {
 | |
|           const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
 | |
|           const marker4: SegmentMarker = {line: 0, column: 40, position: 40, next: marker5};
 | |
|           const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
 | |
|           const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
 | |
|           const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
 | |
|           const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
 | |
|               marker => ({generatedSegment: marker} as Mapping));
 | |
| 
 | |
|           const marker: SegmentMarker = {line: 0, column: 25, position: 25, next: undefined};
 | |
| 
 | |
|           const index = findLastMappingIndexBefore(mappings, marker, /* exclusive */ false, 2);
 | |
|           expect(index).toEqual(-1);
 | |
|         });
 | |
| 
 | |
|         it('should return -1 if the segment marker is equal to the lowerIndex hint and we are exclusive',
 | |
|            () => {
 | |
|              const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
 | |
|              const marker4: SegmentMarker = {line: 0, column: 40, position: 40, next: marker5};
 | |
|              const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
 | |
|              const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
 | |
|              const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
 | |
|              const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
 | |
|                  marker => ({generatedSegment: marker} as Mapping));
 | |
| 
 | |
|              const marker: SegmentMarker = {line: 0, column: 30, position: 30, next: undefined};
 | |
| 
 | |
|              const index = findLastMappingIndexBefore(mappings, marker, /* exclusive */ true, 2);
 | |
|              expect(index).toEqual(-1);
 | |
|            });
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     describe('ensureOriginalSegmentLinks', () => {
 | |
|       it('should add `next` properties to each segment that point to the next segment in the same source file',
 | |
|          () => {
 | |
|            const sourceA = new SourceFile(_('/foo/src/a.js'), 'abcdefg', null, false, []);
 | |
|            const sourceB = new SourceFile(_('/foo/src/b.js'), '1234567', null, false, []);
 | |
|            const rawSourceMap: RawSourceMap = {
 | |
|              mappings:
 | |
|                  encode([[[0, 0, 0, 0], [2, 1, 0, 3], [4, 0, 0, 2], [5, 1, 0, 5], [6, 1, 0, 2]]]),
 | |
|              names: [],
 | |
|              sources: ['a.js', 'b.js'],
 | |
|              version: 3
 | |
|            };
 | |
|            const mappings = parseMappings(rawSourceMap, [sourceA, sourceB], [0, 8]);
 | |
|            ensureOriginalSegmentLinks(mappings);
 | |
|            expect(mappings[0].originalSegment.next).toBe(mappings[2].originalSegment);
 | |
|            expect(mappings[1].originalSegment.next).toBe(mappings[3].originalSegment);
 | |
|            expect(mappings[2].originalSegment.next).toBeUndefined();
 | |
|            expect(mappings[3].originalSegment.next).toBeUndefined();
 | |
|            expect(mappings[4].originalSegment.next).toBe(mappings[1].originalSegment);
 | |
|          });
 | |
|     });
 | |
| 
 | |
|     describe('SourceFile', () => {
 | |
|       describe('flattenedMappings', () => {
 | |
|         it('should be an empty array for source files with no source map', () => {
 | |
|           const sourceFile =
 | |
|               new SourceFile(_('/foo/src/index.js'), 'index contents', null, false, []);
 | |
|           expect(sourceFile.flattenedMappings).toEqual([]);
 | |
|         });
 | |
| 
 | |
|         it('should be empty array for source files with no source map mappings', () => {
 | |
|           const rawSourceMap: RawSourceMap = {mappings: '', names: [], sources: [], version: 3};
 | |
|           const sourceFile =
 | |
|               new SourceFile(_('/foo/src/index.js'), 'index contents', rawSourceMap, false, []);
 | |
|           expect(sourceFile.flattenedMappings).toEqual([]);
 | |
|         });
 | |
| 
 | |
|         it('should be the same as non-flat mappings if there is only one level of source map',
 | |
|            () => {
 | |
|              const rawSourceMap: RawSourceMap = {
 | |
|                mappings: encode([[[0, 0, 0, 0], [6, 0, 0, 3]]]),
 | |
|                names: [],
 | |
|                sources: ['a.js'],
 | |
|                version: 3
 | |
|              };
 | |
|              const originalSource = new SourceFile(_('/foo/src/a.js'), 'abcdefg', null, false, []);
 | |
|              const sourceFile = new SourceFile(
 | |
|                  _('/foo/src/index.js'), 'abc123defg', rawSourceMap, false, [originalSource]);
 | |
|              expect(removeOriginalSegmentLinks(sourceFile.flattenedMappings))
 | |
|                  .toEqual(parseMappings(rawSourceMap, [originalSource], [0, 11]));
 | |
|            });
 | |
| 
 | |
|         it('should merge mappings from flattened original source files', () => {
 | |
|           const cSource = new SourceFile(_('/foo/src/c.js'), 'bcd123', null, false, []);
 | |
|           const dSource = new SourceFile(_('/foo/src/d.js'), 'aef', null, false, []);
 | |
| 
 | |
|           const bSourceMap: RawSourceMap = {
 | |
|             mappings: encode([[[0, 1, 0, 0], [1, 0, 0, 0], [4, 1, 0, 1]]]),
 | |
|             names: [],
 | |
|             sources: ['c.js', 'd.js'],
 | |
|             version: 3
 | |
|           };
 | |
|           const bSource =
 | |
|               new SourceFile(_('/foo/src/b.js'), 'abcdef', bSourceMap, false, [cSource, dSource]);
 | |
| 
 | |
|           const aSourceMap: RawSourceMap = {
 | |
|             mappings: encode([[[0, 0, 0, 0], [2, 0, 0, 3], [4, 0, 0, 2], [5, 0, 0, 5]]]),
 | |
|             names: [],
 | |
|             sources: ['b.js'],
 | |
|             version: 3
 | |
|           };
 | |
|           const aSource =
 | |
|               new SourceFile(_('/foo/src/a.js'), 'abdecf', aSourceMap, false, [bSource]);
 | |
| 
 | |
|           expect(removeOriginalSegmentLinks(aSource.flattenedMappings)).toEqual([
 | |
|             {
 | |
|               generatedSegment: {line: 0, column: 0, position: 0, next: undefined},
 | |
|               originalSource: dSource,
 | |
|               originalSegment: {line: 0, column: 0, position: 0, next: undefined},
 | |
|               name: undefined
 | |
|             },
 | |
|             {
 | |
|               generatedSegment: {line: 0, column: 1, position: 1, next: undefined},
 | |
|               originalSource: cSource,
 | |
|               originalSegment: {line: 0, column: 0, position: 0, next: undefined},
 | |
|               name: undefined
 | |
|             },
 | |
|             {
 | |
|               generatedSegment: {line: 0, column: 2, position: 2, next: undefined},
 | |
|               originalSource: cSource,
 | |
|               originalSegment: {line: 0, column: 2, position: 2, next: undefined},
 | |
|               name: undefined
 | |
|             },
 | |
|             {
 | |
|               generatedSegment: {line: 0, column: 3, position: 3, next: undefined},
 | |
|               originalSource: dSource,
 | |
|               originalSegment: {line: 0, column: 1, position: 1, next: undefined},
 | |
|               name: undefined
 | |
|             },
 | |
|             {
 | |
|               generatedSegment: {line: 0, column: 4, position: 4, next: undefined},
 | |
|               originalSource: cSource,
 | |
|               originalSegment: {line: 0, column: 1, position: 1, next: undefined},
 | |
|               name: undefined
 | |
|             },
 | |
|             {
 | |
|               generatedSegment: {line: 0, column: 5, position: 5, next: undefined},
 | |
|               originalSource: dSource,
 | |
|               originalSegment: {line: 0, column: 2, position: 2, next: undefined},
 | |
|               name: undefined
 | |
|             },
 | |
|           ]);
 | |
|         });
 | |
| 
 | |
|         it('should ignore mappings to missing source files', () => {
 | |
|           const bSourceMap: RawSourceMap = {
 | |
|             mappings: encode([[[1, 0, 0, 0], [4, 0, 0, 3], [4, 0, 0, 6], [5, 0, 0, 7]]]),
 | |
|             names: [],
 | |
|             sources: ['c.js'],
 | |
|             version: 3
 | |
|           };
 | |
|           const bSource = new SourceFile(_('/foo/src/b.js'), 'abcdef', bSourceMap, false, [null]);
 | |
|           const aSourceMap: RawSourceMap = {
 | |
|             mappings: encode([[[0, 0, 0, 0], [2, 0, 0, 3], [4, 0, 0, 2], [5, 0, 0, 5]]]),
 | |
|             names: [],
 | |
|             sources: ['b.js'],
 | |
|             version: 3
 | |
|           };
 | |
|           const aSource =
 | |
|               new SourceFile(_('/foo/src/a.js'), 'abdecf', aSourceMap, false, [bSource]);
 | |
| 
 | |
|           // These flattened mappings are just the mappings from a to b.
 | |
|           // (The mappings to c are dropped since there is no source file to map to.)
 | |
|           expect(removeOriginalSegmentLinks(aSource.flattenedMappings))
 | |
|               .toEqual(parseMappings(aSourceMap, [bSource], [0, 7]));
 | |
|         });
 | |
| 
 | |
|         /**
 | |
|          * Clean out the links between original segments of each of the given `mappings`.
 | |
|          *
 | |
|          * @param mappings the mappings whose segments are to be cleaned.
 | |
|          */
 | |
|         function removeOriginalSegmentLinks(mappings: Mapping[]) {
 | |
|           for (const mapping of mappings) {
 | |
|             mapping.originalSegment.next = undefined;
 | |
|           }
 | |
|           return mappings;
 | |
|         }
 | |
|       });
 | |
| 
 | |
|       describe('renderFlattenedSourceMap()', () => {
 | |
|         it('should convert the flattenedMappings into a raw source-map object', () => {
 | |
|           const cSource = new SourceFile(_('/foo/src/c.js'), 'bcd123e', null, false, []);
 | |
|           const bToCSourceMap: RawSourceMap = {
 | |
|             mappings: encode([[[1, 0, 0, 0], [4, 0, 0, 3], [4, 0, 0, 6], [5, 0, 0, 7]]]),
 | |
|             names: [],
 | |
|             sources: ['c.js'],
 | |
|             version: 3
 | |
|           };
 | |
|           const bSource =
 | |
|               new SourceFile(_('/foo/src/b.js'), 'abcdef', bToCSourceMap, false, [cSource]);
 | |
|           const aToBSourceMap: RawSourceMap = {
 | |
|             mappings: encode([[[0, 0, 0, 0], [2, 0, 0, 3], [4, 0, 0, 2], [5, 0, 0, 5]]]),
 | |
|             names: [],
 | |
|             sources: ['b.js'],
 | |
|             version: 3
 | |
|           };
 | |
|           const aSource =
 | |
|               new SourceFile(_('/foo/src/a.js'), 'abdecf', aToBSourceMap, false, [bSource]);
 | |
| 
 | |
|           const aTocSourceMap = aSource.renderFlattenedSourceMap();
 | |
|           expect(aTocSourceMap.version).toEqual(3);
 | |
|           expect(aTocSourceMap.file).toEqual('a.js');
 | |
|           expect(aTocSourceMap.names).toEqual([]);
 | |
|           expect(aTocSourceMap.sourceRoot).toBeUndefined();
 | |
|           expect(aTocSourceMap.sources).toEqual(['c.js']);
 | |
|           expect(aTocSourceMap.sourcesContent).toEqual(['bcd123e']);
 | |
|           expect(aTocSourceMap.mappings).toEqual(encode([
 | |
|             [[1, 0, 0, 0], [2, 0, 0, 2], [3, 0, 0, 3], [3, 0, 0, 6], [4, 0, 0, 1], [5, 0, 0, 7]]
 | |
|           ]));
 | |
|         });
 | |
| 
 | |
|         it('should handle mappings that map from lines outside of the actual content lines', () => {
 | |
|           const bSource = new SourceFile(_('/foo/src/b.js'), 'abcdef', null, false, []);
 | |
|           const aToBSourceMap: RawSourceMap = {
 | |
|             mappings: encode([
 | |
|               [[0, 0, 0, 0], [2, 0, 0, 3], [4, 0, 0, 2], [5, 0, 0, 5]],
 | |
|               [
 | |
|                 [0, 0, 0, 0],  // Extra mapping from a non-existent line
 | |
|               ]
 | |
|             ]),
 | |
|             names: [],
 | |
|             sources: ['b.js'],
 | |
|             version: 3
 | |
|           };
 | |
|           const aSource =
 | |
|               new SourceFile(_('/foo/src/a.js'), 'abdecf', aToBSourceMap, false, [bSource]);
 | |
| 
 | |
|           const aTocSourceMap = aSource.renderFlattenedSourceMap();
 | |
|           expect(aTocSourceMap.version).toEqual(3);
 | |
|           expect(aTocSourceMap.file).toEqual('a.js');
 | |
|           expect(aTocSourceMap.names).toEqual([]);
 | |
|           expect(aTocSourceMap.sourceRoot).toBeUndefined();
 | |
|           expect(aTocSourceMap.sources).toEqual(['b.js']);
 | |
|           expect(aTocSourceMap.sourcesContent).toEqual(['abcdef']);
 | |
|           expect(aTocSourceMap.mappings).toEqual(aToBSourceMap.mappings);
 | |
|         });
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     describe('computeStartOfLinePositions()', () => {
 | |
|       it('should compute the cumulative length of each line in the given string', () => {
 | |
|         expect(computeStartOfLinePositions('')).toEqual([0]);
 | |
|         expect(computeStartOfLinePositions('abc')).toEqual([0]);
 | |
|         expect(computeStartOfLinePositions('\n')).toEqual([0, 1]);
 | |
|         expect(computeStartOfLinePositions('\n\n')).toEqual([0, 1, 2]);
 | |
|         expect(computeStartOfLinePositions('abc\n')).toEqual([0, 4]);
 | |
|         expect(computeStartOfLinePositions('\nabc')).toEqual([0, 1]);
 | |
|         expect(computeStartOfLinePositions('abc\ndefg')).toEqual([0, 4]);
 | |
|         expect(computeStartOfLinePositions('abc\r\n')).toEqual([0, 4]);
 | |
|         expect(computeStartOfLinePositions('abc\r\ndefg')).toEqual([0, 4]);
 | |
|       });
 | |
|     });
 | |
|   });
 | |
| });
 |