1// Flags: --enable-source-maps 2'use strict'; 3 4const common = require('../common'); 5const assert = require('assert'); 6const { findSourceMap, SourceMap } = require('module'); 7const { readFileSync } = require('fs'); 8 9// It should throw with invalid args. 10{ 11 [1, true, 'foo'].forEach((invalidArg) => 12 assert.throws( 13 () => new SourceMap(invalidArg), 14 { 15 code: 'ERR_INVALID_ARG_TYPE', 16 name: 'TypeError', 17 message: 'The "payload" argument must be of type object.' + 18 common.invalidArgTypeHelper(invalidArg) 19 } 20 ) 21 ); 22} 23 24// findSourceMap() can lookup source-maps based on URIs, in the 25// non-exceptional case. 26{ 27 require('../fixtures/source-map/disk-relative-path.js'); 28 const sourceMap = findSourceMap( 29 require.resolve('../fixtures/source-map/disk-relative-path.js') 30 ); 31 const { 32 originalLine, 33 originalColumn, 34 originalSource 35 } = sourceMap.findEntry(0, 29); 36 assert.strictEqual(originalLine, 2); 37 assert.strictEqual(originalColumn, 4); 38 assert(originalSource.endsWith('disk.js')); 39} 40 41// findSourceMap() can be used in Error.prepareStackTrace() to lookup 42// source-map attached to error. 43{ 44 let callSite; 45 let sourceMap; 46 Error.prepareStackTrace = (error, trace) => { 47 const throwingRequireCallSite = trace[0]; 48 if (throwingRequireCallSite.getFileName().endsWith('typescript-throw.js')) { 49 sourceMap = findSourceMap(throwingRequireCallSite.getFileName()); 50 callSite = throwingRequireCallSite; 51 } 52 }; 53 try { 54 // Require a file that throws an exception, and has a source map. 55 require('../fixtures/source-map/typescript-throw.js'); 56 } catch (err) { 57 // eslint-disable-next-line no-unused-expressions 58 err.stack; // Force prepareStackTrace() to be called. 59 } 60 assert(callSite); 61 assert(sourceMap); 62 const { 63 generatedLine, 64 generatedColumn, 65 originalLine, 66 originalColumn, 67 originalSource 68 } = sourceMap.findEntry( 69 callSite.getLineNumber() - 1, 70 callSite.getColumnNumber() - 1 71 ); 72 73 assert.strictEqual(generatedLine, 19); 74 assert.strictEqual(generatedColumn, 14); 75 76 assert.strictEqual(originalLine, 17); 77 assert.strictEqual(originalColumn, 10); 78 assert(originalSource.endsWith('typescript-throw.ts')); 79} 80 81// SourceMap can be instantiated with Source Map V3 object as payload. 82{ 83 const payload = JSON.parse(readFileSync( 84 require.resolve('../fixtures/source-map/disk.map'), 'utf8' 85 )); 86 const sourceMap = new SourceMap(payload); 87 const { 88 originalLine, 89 originalColumn, 90 originalSource 91 } = sourceMap.findEntry(0, 29); 92 assert.strictEqual(originalLine, 2); 93 assert.strictEqual(originalColumn, 4); 94 assert(originalSource.endsWith('disk.js')); 95 // The stored payload should be a clone: 96 assert.strictEqual(payload.mappings, sourceMap.payload.mappings); 97 assert.notStrictEqual(payload, sourceMap.payload); 98 assert.strictEqual(payload.sources[0], sourceMap.payload.sources[0]); 99 assert.notStrictEqual(payload.sources, sourceMap.payload.sources); 100} 101 102// Test various known decodings to ensure decodeVLQ works correctly. 103{ 104 function makeMinimalMap(column) { 105 return { 106 sources: ['test.js'], 107 // Mapping from the 0th line, 0th column of the output file to the 0th 108 // source file, 0th line, ${column}th column. 109 mappings: `AAA${column}`, 110 }; 111 } 112 const knownDecodings = { 113 'A': 0, 114 'B': -2147483648, 115 'C': 1, 116 'D': -1, 117 'E': 2, 118 'F': -2, 119 120 // 2^31 - 1, maximum values 121 '+/////D': 2147483647, 122 '8/////D': 2147483646, 123 '6/////D': 2147483645, 124 '4/////D': 2147483644, 125 '2/////D': 2147483643, 126 '0/////D': 2147483642, 127 128 // -2^31 + 1, minimum values 129 '//////D': -2147483647, 130 '9/////D': -2147483646, 131 '7/////D': -2147483645, 132 '5/////D': -2147483644, 133 '3/////D': -2147483643, 134 '1/////D': -2147483642, 135 }; 136 137 for (const column in knownDecodings) { 138 const sourceMap = new SourceMap(makeMinimalMap(column)); 139 const { originalColumn } = sourceMap.findEntry(0, 0); 140 assert.strictEqual(originalColumn, knownDecodings[column]); 141 } 142} 143 144// Test that generated columns are sorted when a negative offset is 145// observed, see: https://github.com/mozilla/source-map/pull/92 146{ 147 function makeMinimalMap(generatedColumns, originalColumns) { 148 return { 149 sources: ['test.js'], 150 // Mapping from the 0th line, ${g}th column of the output file to the 0th 151 // source file, 0th line, ${column}th column. 152 mappings: generatedColumns.map((g, i) => `${g}AA${originalColumns[i]}`) 153 .join(',') 154 }; 155 } 156 // U = 10 157 // F = -2 158 // A = 0 159 // E = 2 160 const sourceMap = new SourceMap(makeMinimalMap( 161 ['U', 'F', 'F'], 162 ['A', 'E', 'E'] 163 )); 164 assert.strictEqual(sourceMap.findEntry(0, 6).originalColumn, 4); 165 assert.strictEqual(sourceMap.findEntry(0, 8).originalColumn, 2); 166 assert.strictEqual(sourceMap.findEntry(0, 10).originalColumn, 0); 167} 168