From da4b63aff0be34b19ad21c9c3502eb02d4129781 Mon Sep 17 00:00:00 2001 From: isaacs Date: Wed, 14 Jun 2023 16:30:02 -0700 Subject: [PATCH] module: add SourceMap.lineLengths Fix: #48460 --- doc/api/module.md | 4 ++++ lib/internal/source_map/source_map.js | 17 ++++++++++++++++- lib/internal/source_map/source_map_cache.js | 2 +- test/parallel/test-source-map-api.js | 12 +++++++++++- 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/doc/api/module.md b/doc/api/module.md index 1d73e88ce6149d..5b98a6a1c2b0c1 100644 --- a/doc/api/module.md +++ b/doc/api/module.md @@ -274,6 +274,7 @@ added: #### `new SourceMap(payload)` * `payload` {Object} +* `lineLengths` {number\[]} Creates a new `sourceMap` instance. @@ -287,6 +288,9 @@ Creates a new `sourceMap` instance. * `mappings`: {string} * `sourceRoot`: {string} +`lineLengths` is an array of the length of each line in the +generated code. + #### `sourceMap.payload` * Returns: {Object} diff --git a/lib/internal/source_map/source_map.js b/lib/internal/source_map/source_map.js index 3112a026b643e2..8de57ad2b872ac 100644 --- a/lib/internal/source_map/source_map.js +++ b/lib/internal/source_map/source_map.js @@ -71,6 +71,7 @@ const { ArrayPrototypePush, ArrayPrototypeSlice, ArrayPrototypeSort, + ArrayLength, ObjectPrototypeHasOwnProperty, StringPrototypeCharAt, } = primordials; @@ -125,12 +126,13 @@ class SourceMap { #mappings = []; #sources = {}; #sourceContentByURL = {}; + #lineLengths = undefined; /** * @constructor * @param {SourceMapV3} payload */ - constructor(payload) { + constructor(payload, lineLengths) { if (!base64Map) { const base64Digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; @@ -140,6 +142,9 @@ class SourceMap { } this.#payload = cloneSourceMapV3(payload); this.#parseMappingPayload(); + if (ArrayIsArray(lineLengths) && ArrayLength(lineLengths)) { + this.#lineLengths = lineLengths; + } } /** @@ -149,6 +154,16 @@ class SourceMap { return cloneSourceMapV3(this.#payload); } + /** + * @return {number[] | undefined} line lengths of generated source code + */ + get lineLengths() { + if (this.#lineLengths) { + return ArrayPrototypeSlice(this.#lineLengths); + } + return undefined; + } + #parseMappingPayload = () => { if (this.#payload.sections) { this.#parseSections(this.#payload.sections); diff --git a/lib/internal/source_map/source_map_cache.js b/lib/internal/source_map/source_map_cache.js index ebe0288e436d90..a2a095aa24bd88 100644 --- a/lib/internal/source_map/source_map_cache.js +++ b/lib/internal/source_map/source_map_cache.js @@ -317,7 +317,7 @@ function findSourceMap(sourceURL) { } let sourceMap = entry.sourceMap; if (sourceMap === undefined) { - sourceMap = new SourceMap(entry.data); + sourceMap = new SourceMap(entry.data, entry.lineLengths); entry.sourceMap = sourceMap; } return sourceMap; diff --git a/test/parallel/test-source-map-api.js b/test/parallel/test-source-map-api.js index 2c6cf341339a53..17fc036dfe6680 100644 --- a/test/parallel/test-source-map-api.js +++ b/test/parallel/test-source-map-api.js @@ -57,6 +57,8 @@ const { readFileSync } = require('fs'); 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 @@ -116,7 +118,10 @@ const { readFileSync } = require('fs'); const payload = JSON.parse(readFileSync( require.resolve('../fixtures/source-map/disk.map'), 'utf8' )); - const sourceMap = new SourceMap(payload); + 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, @@ -125,6 +130,11 @@ const { readFileSync } = require('fs'); 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);