From 11b3b96bcd180813e5376cae5b9f7b16e33e4908 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 f3752f3f81a5b2..4bd36f66728bd7 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 8a441903bb9519..879df214d47a09 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 39d523b3e1500b..ddaa122f99eb5c 100644 --- a/test/parallel/test-source-map-api.js +++ b/test/parallel/test-source-map-api.js @@ -49,6 +49,8 @@ const { readFileSync } = require('fs'); assert.strictEqual(originalLine, 2); assert.strictEqual(originalColumn, 4); assert(originalSource.endsWith('disk.js')); + assert(Array.isArray(sourceMap.lineLengths)); + assert(!sourceMap.lineLengths.some((len) => (typeof len !== 'number'))); } // findSourceMap() can be used in Error.prepareStackTrace() to lookup @@ -96,7 +98,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, @@ -105,6 +110,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);