| // Flags: --enable-source-maps |
| 'use strict'; |
| |
| const common = require('../common'); |
| const assert = require('assert'); |
| const { findSourceMap, SourceMap } = require('module'); |
| const { readFileSync } = require('fs'); |
| |
| // It should throw with invalid args. |
| { |
| [1, true, 'foo'].forEach((invalidArg) => |
| assert.throws( |
| () => new SourceMap(invalidArg), |
| { |
| code: 'ERR_INVALID_ARG_TYPE', |
| name: 'TypeError', |
| message: 'The "payload" argument must be of type object.' + |
| common.invalidArgTypeHelper(invalidArg) |
| } |
| ) |
| ); |
| } |
| |
| // findSourceMap() can lookup source-maps based on URIs, in the |
| // non-exceptional case. |
| { |
| require('../fixtures/source-map/disk-relative-path.js'); |
| const sourceMap = findSourceMap( |
| require.resolve('../fixtures/source-map/disk-relative-path.js') |
| ); |
| const { |
| originalLine, |
| originalColumn, |
| originalSource |
| } = sourceMap.findEntry(0, 29); |
| assert.strictEqual(originalLine, 2); |
| assert.strictEqual(originalColumn, 4); |
| assert(originalSource.endsWith('disk.js')); |
| } |
| |
| // findSourceMap() can be used in Error.prepareStackTrace() to lookup |
| // source-map attached to error. |
| { |
| let callSite; |
| let sourceMap; |
| Error.prepareStackTrace = (error, trace) => { |
| const throwingRequireCallSite = trace[0]; |
| if (throwingRequireCallSite.getFileName().endsWith('typescript-throw.js')) { |
| sourceMap = findSourceMap(throwingRequireCallSite.getFileName()); |
| callSite = throwingRequireCallSite; |
| } |
| }; |
| try { |
| // Require a file that throws an exception, and has a source map. |
| require('../fixtures/source-map/typescript-throw.js'); |
| } catch (err) { |
| // eslint-disable-next-line no-unused-expressions |
| err.stack; // Force prepareStackTrace() to be called. |
| } |
| assert(callSite); |
| assert(sourceMap); |
| const { |
| generatedLine, |
| generatedColumn, |
| originalLine, |
| originalColumn, |
| originalSource |
| } = sourceMap.findEntry( |
| callSite.getLineNumber() - 1, |
| callSite.getColumnNumber() - 1 |
| ); |
| |
| assert.strictEqual(generatedLine, 19); |
| assert.strictEqual(generatedColumn, 14); |
| |
| assert.strictEqual(originalLine, 17); |
| assert.strictEqual(originalColumn, 10); |
| assert(originalSource.endsWith('typescript-throw.ts')); |
| } |
| |
| // SourceMap can be instantiated with Source Map V3 object as payload. |
| { |
| const payload = JSON.parse(readFileSync( |
| require.resolve('../fixtures/source-map/disk.map'), 'utf8' |
| )); |
| const sourceMap = new SourceMap(payload); |
| const { |
| originalLine, |
| originalColumn, |
| originalSource |
| } = sourceMap.findEntry(0, 29); |
| assert.strictEqual(originalLine, 2); |
| assert.strictEqual(originalColumn, 4); |
| assert(originalSource.endsWith('disk.js')); |
| // The stored payload should be a clone: |
| assert.strictEqual(payload.mappings, sourceMap.payload.mappings); |
| assert.notStrictEqual(payload, sourceMap.payload); |
| assert.strictEqual(payload.sources[0], sourceMap.payload.sources[0]); |
| assert.notStrictEqual(payload.sources, sourceMap.payload.sources); |
| } |
| |
| // findEntry() must return empty object instead error when |
| // receive a malformed mappings. |
| { |
| const payload = JSON.parse(readFileSync( |
| require.resolve('../fixtures/source-map/disk.map'), 'utf8' |
| )); |
| payload.mappings = ';;;;;;;;;'; |
| |
| const sourceMap = new SourceMap(payload); |
| const result = sourceMap.findEntry(0, 5); |
| assert.strictEqual(typeof result, 'object'); |
| assert.strictEqual(Object.keys(result).length, 0); |
| } |
| |
| // Test various known decodings to ensure decodeVLQ works correctly. |
| { |
| function makeMinimalMap(column) { |
| return { |
| sources: ['test.js'], |
| // Mapping from the 0th line, 0th column of the output file to the 0th |
| // source file, 0th line, ${column}th column. |
| mappings: `AAA${column}`, |
| }; |
| } |
| const knownDecodings = { |
| 'A': 0, |
| 'B': -2147483648, |
| 'C': 1, |
| 'D': -1, |
| 'E': 2, |
| 'F': -2, |
| |
| // 2^31 - 1, maximum values |
| '+/////D': 2147483647, |
| '8/////D': 2147483646, |
| '6/////D': 2147483645, |
| '4/////D': 2147483644, |
| '2/////D': 2147483643, |
| '0/////D': 2147483642, |
| |
| // -2^31 + 1, minimum values |
| '//////D': -2147483647, |
| '9/////D': -2147483646, |
| '7/////D': -2147483645, |
| '5/////D': -2147483644, |
| '3/////D': -2147483643, |
| '1/////D': -2147483642, |
| }; |
| |
| for (const column in knownDecodings) { |
| const sourceMap = new SourceMap(makeMinimalMap(column)); |
| const { originalColumn } = sourceMap.findEntry(0, 0); |
| assert.strictEqual(originalColumn, knownDecodings[column]); |
| } |
| } |
| |
| // Test that generated columns are sorted when a negative offset is |
| // observed, see: https://github.com/mozilla/source-map/pull/92 |
| { |
| function makeMinimalMap(generatedColumns, originalColumns) { |
| return { |
| sources: ['test.js'], |
| // Mapping from the 0th line, ${g}th column of the output file to the 0th |
| // source file, 0th line, ${column}th column. |
| mappings: generatedColumns.map((g, i) => `${g}AA${originalColumns[i]}`) |
| .join(',') |
| }; |
| } |
| // U = 10 |
| // F = -2 |
| // A = 0 |
| // E = 2 |
| const sourceMap = new SourceMap(makeMinimalMap( |
| ['U', 'F', 'F'], |
| ['A', 'E', 'E'] |
| )); |
| assert.strictEqual(sourceMap.findEntry(0, 6).originalColumn, 4); |
| assert.strictEqual(sourceMap.findEntry(0, 8).originalColumn, 2); |
| assert.strictEqual(sourceMap.findEntry(0, 10).originalColumn, 0); |
| } |