node/test/parallel/test-source-map-api.js
2023-07-12 18:37:32 +00:00

249 lines
7.4 KiB
JavaScript

// 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()` should return undefined when no source map is found.
{
const files = [
__filename,
'',
'invalid-file',
];
for (const file of files) {
const sourceMap = findSourceMap(file);
assert.strictEqual(sourceMap, undefined);
}
}
// 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'));
const {
fileName,
lineNumber,
columnNumber,
} = sourceMap.findOrigin(1, 30);
assert.strictEqual(fileName, originalSource);
assert.strictEqual(lineNumber, 3);
assert.strictEqual(columnNumber, 6);
assert(Array.isArray(sourceMap.lineLengths));
assert(!sourceMap.lineLengths.some((len) => (typeof len !== 'number')));
}
// 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'));
const {
fileName,
lineNumber,
columnNumber,
} = sourceMap.findOrigin(
callSite.getLineNumber(),
callSite.getColumnNumber()
);
assert.strictEqual(fileName, originalSource);
assert.strictEqual(lineNumber, 18);
assert.strictEqual(columnNumber, 11);
}
// 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 lineLengths = readFileSync(
require.resolve('../fixtures/source-map/disk.map'), 'utf8'
).replace(/\n$/, '').split('\n').map((l) => l.length);
const sourceMap = new SourceMap(payload, { lineLengths });
const {
originalLine,
originalColumn,
originalSource
} = sourceMap.findEntry(0, 29);
assert.strictEqual(originalLine, 2);
assert.strictEqual(originalColumn, 4);
assert(originalSource.endsWith('disk.js'));
const sourceMapLineLengths = sourceMap.lineLengths;
for (let i = 0; i < sourceMapLineLengths.length; i++) {
assert.strictEqual(sourceMapLineLengths[i], lineLengths[i]);
}
assert.strictEqual(sourceMapLineLengths.length, lineLengths.length);
// 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() and findOrigin() must return empty object instead of
// error when receiving 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);
const origin = sourceMap.findOrigin(0, 5);
assert.strictEqual(typeof origin, 'object');
assert.strictEqual(Object.keys(origin).length, 0);
}
// SourceMap can be instantiated with Index Source Map V3 object as payload.
{
const payload = JSON.parse(readFileSync(
require.resolve('../fixtures/source-map/disk-index.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('section.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);
}
// 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);
}