From 905394393143dfe8f318bfc89986bc91514d1f1e Mon Sep 17 00:00:00 2001 From: isaacs Date: Wed, 12 Jul 2023 11:37:32 -0700 Subject: [PATCH] module: add SourceMap.lineLengths Fix: #48460 PR-URL: https://github.com/nodejs/node/pull/48461 Fixes: https://github.com/nodejs/node/issues/48460 Reviewed-By: Chengzhong Wu --- doc/api/module.md | 6 +++++- lib/internal/source_map/source_map.js | 16 +++++++++++++++- lib/internal/source_map/source_map_cache.js | 2 +- test/parallel/test-source-map-api.js | 12 +++++++++++- 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/doc/api/module.md b/doc/api/module.md index 1d73e88ce6149d..8dd5fd4fa59f6c 100644 --- a/doc/api/module.md +++ b/doc/api/module.md @@ -271,9 +271,10 @@ added: - v12.17.0 --> -#### `new SourceMap(payload)` +#### `new SourceMap(payload[, { lineLengths }])` * `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 optional 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..9e63eabaacf665 100644 --- a/lib/internal/source_map/source_map.js +++ b/lib/internal/source_map/source_map.js @@ -125,12 +125,13 @@ class SourceMap { #mappings = []; #sources = {}; #sourceContentByURL = {}; + #lineLengths = undefined; /** * @constructor * @param {SourceMapV3} payload */ - constructor(payload) { + constructor(payload, { lineLengths } = { __proto__: null }) { if (!base64Map) { const base64Digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; @@ -140,6 +141,9 @@ class SourceMap { } this.#payload = cloneSourceMapV3(payload); this.#parseMappingPayload(); + if (ArrayIsArray(lineLengths) && lineLengths.length) { + this.#lineLengths = lineLengths; + } } /** @@ -149,6 +153,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..2813da21dfdc63 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, { lineLengths: 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..8c965891536072 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);