From 8ba0d40d302060c49ef6b86d67e16fcaa4035419 Mon Sep 17 00:00:00 2001 From: Sebastian Alex Date: Thu, 30 Nov 2023 13:23:39 +0000 Subject: [PATCH 1/6] sourcemap-tools: attempt to add snippets and comments if they do not exist --- tools/sourcemap-tools/src/DebugIdGenerator.ts | 14 +++++++-- tools/sourcemap-tools/src/SourceProcessor.ts | 26 ++++++++++------- .../tests/DebugIdGenerator.spec.ts | 4 +-- .../tests/SourceProcessor.spec.ts | 29 ++++++++++++------- 4 files changed, 48 insertions(+), 25 deletions(-) diff --git a/tools/sourcemap-tools/src/DebugIdGenerator.ts b/tools/sourcemap-tools/src/DebugIdGenerator.ts index e15c320d..051ba0f7 100644 --- a/tools/sourcemap-tools/src/DebugIdGenerator.ts +++ b/tools/sourcemap-tools/src/DebugIdGenerator.ts @@ -15,7 +15,7 @@ export class DebugIdGenerator { const replaceAll = () => source.replace(oldDebugId, newDebugId); // Try to replace more safely first - const oldSourceSnippet = this.generateSourceSnippet(oldDebugId); + const oldSourceSnippet = this.generateSourceSnippet(oldDebugId).replace(/^;+|;+$/g, ''); if (source.indexOf(oldSourceSnippet) !== -1) { source = source.replace(oldSourceSnippet, this.generateSourceSnippet(newDebugId)); } else { @@ -32,7 +32,17 @@ export class DebugIdGenerator { return source; } - public getSourceDebugId(source: string): string | undefined { + public hasCodeSnippet(source: string, debugId: string) { + const sourceSnippet = this.generateSourceSnippet(debugId).replace(/^;+|;+$/g, ''); + return source.includes(sourceSnippet); + } + + public hasCommentSnippet(source: string, debugId: string) { + const commentSnippet = this.generateSourceComment(debugId); + return source.includes(commentSnippet); + } + + public getSourceDebugIdFromComment(source: string): string | undefined { const regex = new RegExp(`^//# ${SOURCE_DEBUG_ID_COMMENT}=(.+)$`, 'm'); const match = source.match(regex); if (!match) { diff --git a/tools/sourcemap-tools/src/SourceProcessor.ts b/tools/sourcemap-tools/src/SourceProcessor.ts index 89e00a28..c4b2d800 100644 --- a/tools/sourcemap-tools/src/SourceProcessor.ts +++ b/tools/sourcemap-tools/src/SourceProcessor.ts @@ -41,7 +41,7 @@ export class SourceProcessor { constructor(private readonly _debugIdGenerator: DebugIdGenerator) {} public isSourceProcessed(source: string): boolean { - return !!this._debugIdGenerator.getSourceDebugId(source); + return !!this._debugIdGenerator.getSourceDebugIdFromComment(source); } public isSourceMapProcessed(sourceMap: RawSourceMap): boolean { @@ -66,7 +66,7 @@ export class SourceProcessor { } public getSourceDebugId(source: string): string | undefined { - return this._debugIdGenerator.getSourceDebugId(source); + return this._debugIdGenerator.getSourceDebugIdFromComment(source); } public getSourceMapDebugId(sourceMap: RawSourceMap): string | undefined { @@ -93,29 +93,29 @@ export class SourceProcessor { source: string, sourceMap: RawSourceMap, debugId?: string, + force?: boolean, ): Promise { const sourceDebugId = this.getSourceDebugId(source); if (!debugId) { debugId = sourceDebugId ?? stringToUuid(source); } - let newSource: string | undefined; + let newSource = source; let offsetSourceMap: RawSourceMap | undefined; // If source has debug ID, but it is different, we need to only replace it if (sourceDebugId && debugId !== sourceDebugId) { newSource = this._debugIdGenerator.replaceDebugId(source, sourceDebugId, debugId); - } else if (!sourceDebugId) { + } + + if (force || !sourceDebugId || !this._debugIdGenerator.hasCodeSnippet(source, debugId)) { const sourceSnippet = this._debugIdGenerator.generateSourceSnippet(debugId); const shebang = source.match(/^(#!.+\n)/)?.[1]; - const sourceWithSnippet = shebang + newSource = shebang ? shebang + sourceSnippet + '\n' + source.substring(shebang.length) : sourceSnippet + '\n' + source; - const sourceComment = this._debugIdGenerator.generateSourceComment(debugId); - newSource = appendBeforeWhitespaces(sourceWithSnippet, '\n' + sourceComment); - // We need to offset the source map by amount of lines that we're inserting to the source code // Sourcemaps map code like this: // original code X:Y => generated code A:B @@ -126,8 +126,13 @@ export class SourceProcessor { offsetSourceMap = await this.offsetSourceMap(sourceMap, sourceSnippetNewlineCount + 1); } + if (force || !sourceDebugId || !this._debugIdGenerator.hasCommentSnippet(source, debugId)) { + const sourceComment = this._debugIdGenerator.generateSourceComment(debugId); + newSource = appendBeforeWhitespaces(newSource, '\n' + sourceComment); + } + const newSourceMap = this._debugIdGenerator.addSourceMapDebugId(offsetSourceMap ?? sourceMap, debugId); - return { debugId, source: newSource ?? source, sourceMap: newSourceMap }; + return { debugId, source: newSource, sourceMap: newSourceMap }; } /** @@ -142,6 +147,7 @@ export class SourceProcessor { sourcePath: string, sourceMapPath?: string, debugId?: string, + force?: boolean, ): ResultPromise { const sourceReadResult = await readFile(sourcePath); if (sourceReadResult.isErr()) { @@ -171,7 +177,7 @@ export class SourceProcessor { } const sourceMap = parseResult.data; - const processResult = await this.processSourceAndSourceMap(source, sourceMap, debugId); + const processResult = await this.processSourceAndSourceMap(source, sourceMap, debugId, force); return Ok({ ...processResult, sourcePath, diff --git a/tools/sourcemap-tools/tests/DebugIdGenerator.spec.ts b/tools/sourcemap-tools/tests/DebugIdGenerator.spec.ts index f1fc4fc9..595c3288 100644 --- a/tools/sourcemap-tools/tests/DebugIdGenerator.spec.ts +++ b/tools/sourcemap-tools/tests/DebugIdGenerator.spec.ts @@ -156,7 +156,7 @@ describe('DebugIdGenerator', () => { ].join('\n'); const debugIdGenerator = new DebugIdGenerator(); - const actual = debugIdGenerator.getSourceDebugId(source); + const actual = debugIdGenerator.getSourceDebugIdFromComment(source); expect(actual).toEqual(expected); }); @@ -167,7 +167,7 @@ describe('DebugIdGenerator', () => { ); const debugIdGenerator = new DebugIdGenerator(); - const actual = debugIdGenerator.getSourceDebugId(source); + const actual = debugIdGenerator.getSourceDebugIdFromComment(source); expect(actual).toBeUndefined(); }); diff --git a/tools/sourcemap-tools/tests/SourceProcessor.spec.ts b/tools/sourcemap-tools/tests/SourceProcessor.spec.ts index f69c8113..04b15fcc 100644 --- a/tools/sourcemap-tools/tests/SourceProcessor.spec.ts +++ b/tools/sourcemap-tools/tests/SourceProcessor.spec.ts @@ -36,11 +36,12 @@ function foo(){console.log("Hello World!")}foo();`; }; const processedSource = ( + debugIdGenerator: DebugIdGenerator, debugId: string, - ) => `;!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new Error).stack;n&&(e._btDebugIds=e._btDebugIds||{},e._btDebugIds[n]="${debugId}")}catch(e){}}(); + ) => `${debugIdGenerator.generateSourceSnippet(debugId)} (()=>{"use strict";console.log("Hello World!")})(); //# sourceMappingURL=source.js.map -//# debugId=${debugId} +${debugIdGenerator.generateSourceComment(debugId)} `; const processedSourceMap = (debugId: string) => ({ @@ -225,7 +226,7 @@ function foo(){console.log("Hello World!")}foo();`; await sourceProcessor.processSourceAndSourceMapFiles(sourcePath, sourceMapPath, debugId); - expect(processFn).toBeCalledWith(sourceContent, sourceMapContent, debugId); + expect(processFn).toBeCalledWith(sourceContent, sourceMapContent, debugId, undefined); }); it('should call process function with sourcemap detected from source', async () => { @@ -246,13 +247,14 @@ function foo(){console.log("Hello World!")}foo();`; await sourceProcessor.processSourceAndSourceMapFiles(sourcePath, undefined, debugId); - expect(processFn).toBeCalledWith(sourceContent, sourceMapContent, debugId); + expect(processFn).toBeCalledWith(sourceContent, sourceMapContent, debugId, undefined); }); it('should return unmodified source when source has debug ID', async () => { const debugId = randomUUID(); - const source = processedSource(debugId); - const sourceProcessor = new SourceProcessor(new DebugIdGenerator()); + const debugIdGenerator = new DebugIdGenerator(); + const source = processedSource(debugIdGenerator, debugId); + const sourceProcessor = new SourceProcessor(debugIdGenerator); const result = await sourceProcessor.processSourceAndSourceMap(source, processedSourceMap(debugId)); expect(result.source).toEqual(source); @@ -260,8 +262,9 @@ function foo(){console.log("Hello World!")}foo();`; it('should return unmodified source when source has same debug ID as provided', async () => { const debugId = randomUUID(); - const source = processedSource(debugId); - const sourceProcessor = new SourceProcessor(new DebugIdGenerator()); + const debugIdGenerator = new DebugIdGenerator(); + const source = processedSource(debugIdGenerator, debugId); + const sourceProcessor = new SourceProcessor(debugIdGenerator); const result = await sourceProcessor.processSourceAndSourceMap( source, processedSourceMap(debugId), @@ -273,8 +276,12 @@ function foo(){console.log("Hello World!")}foo();`; it("should return sourcemap with source's debug ID when source has debug ID", async () => { const debugId = randomUUID(); - const sourceProcessor = new SourceProcessor(new DebugIdGenerator()); - const result = await sourceProcessor.processSourceAndSourceMap(processedSource(debugId), sourceMap); + const debugIdGenerator = new DebugIdGenerator(); + const sourceProcessor = new SourceProcessor(debugIdGenerator); + const result = await sourceProcessor.processSourceAndSourceMap( + processedSource(debugIdGenerator, debugId), + sourceMap, + ); expect(result.sourceMap.debugId).toEqual(debugId); }); @@ -282,8 +289,8 @@ function foo(){console.log("Hello World!")}foo();`; it('should call replace debug ID when source has different debug ID than provided', async () => { const oldDebugId = randomUUID(); const newDebugId = randomUUID(); - const source = processedSource(oldDebugId); const debugIdGenerator = new DebugIdGenerator(); + const source = processedSource(debugIdGenerator, oldDebugId); const spy = jest.spyOn(debugIdGenerator, 'replaceDebugId'); From 4118fa9aa647c8ee4b69a0fabcf91255255918ef Mon Sep 17 00:00:00 2001 From: Sebastian Alex Date: Thu, 30 Nov 2023 13:24:00 +0000 Subject: [PATCH 2/6] cli: improve assets logging --- tools/cli/src/helpers/logs.ts | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/tools/cli/src/helpers/logs.ts b/tools/cli/src/helpers/logs.ts index 8315bdf3..7fc1a852 100644 --- a/tools/cli/src/helpers/logs.ts +++ b/tools/cli/src/helpers/logs.ts @@ -1,26 +1,21 @@ -import { Asset, log, LogLevel, ProcessAssetResult } from '@backtrace/sourcemap-tools'; +import { Asset, log, LogLevel } from '@backtrace/sourcemap-tools'; import { CliLogger } from '../logger'; import { SourceAndSourceMapPaths } from '../models/Asset'; export function createAssetLogger( logger: CliLogger, -): (level: LogLevel) => (message: string | ((t: T) => string)) => (asset: T) => T; +): (level: LogLevel) => (message: string | ((t: T) => string)) => (asset: T) => T; export function createAssetLogger( logger: CliLogger, level: LogLevel, -): (message: string | ((t: T) => string)) => (asset: T) => T; +): (message: string | ((t: T) => string)) => (asset: T) => T; export function createAssetLogger(logger: CliLogger, level?: LogLevel) { function logAsset(level: LogLevel) { const logFn = log(logger, level); - return function logAsset(message: string | ((t: T) => string)) { + return function logAsset(message: string | ((t: T) => string)) { return function logAsset(asset: T) { - return logFn( - (t) => - `${'name' in t ? t.name : t.asset.name}: ${ - typeof message === 'function' ? message(asset) : message - }`, - )(asset); + return logFn((t) => `${t.name}: ${typeof message === 'function' ? message(asset) : message}`)(asset); }; }; } @@ -32,4 +27,4 @@ export const logAssets = (logger: CliLogger, level: LogLevel) => (message: string) => (assets: T) => - log(logger, level)(`${assets.source.name}: ${message}`)(assets); + log(logger, level)(`${assets.source.name}:${assets.sourceMap?.name ?? '?'}: ${message}`)(assets); From 8b60e066247a5589c334a3705cf01a0ac880d72f Mon Sep 17 00:00:00 2001 From: Sebastian Alex Date: Thu, 30 Nov 2023 13:24:35 +0000 Subject: [PATCH 3/6] cli: trust sourceProcessor with finding sourcemap path --- tools/cli/src/helpers/common.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/cli/src/helpers/common.ts b/tools/cli/src/helpers/common.ts index d066f336..2f3e7243 100644 --- a/tools/cli/src/helpers/common.ts +++ b/tools/cli/src/helpers/common.ts @@ -119,7 +119,6 @@ function resolveSourceMapPath(sourceProcessor: SourceProcessor) { return pipe( asset.path, (path) => sourceProcessor.getSourceMapPathFromSourceFile(path), - R.map((result) => result ?? pathIfExists(`${asset.path}.map`)), R.map((path) => (path ? Ok(path) : Err('could not find source map for source'))), R.map((path) => ({ ...asset, From 6d93dd2f3a35b9f684de51f2aa75e28c37085b1c Mon Sep 17 00:00:00 2001 From: Sebastian Alex Date: Thu, 30 Nov 2023 13:24:55 +0000 Subject: [PATCH 4/6] cli: always process file with force passed to sourceProcessor --- tools/cli/src/sourcemaps/process.ts | 36 +++++++++++++---------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/tools/cli/src/sourcemaps/process.ts b/tools/cli/src/sourcemaps/process.ts index 4d2c9bfa..2da49c34 100644 --- a/tools/cli/src/sourcemaps/process.ts +++ b/tools/cli/src/sourcemaps/process.ts @@ -199,28 +199,24 @@ export function processSource(force: boolean) { sourceMapDebugId: getSourceMapDebugId(sourceAndSourceMap), }); - const shouldProcess = (sourceDebugId: string | undefined, sourceMapDebugId: string | undefined) => - force || !sourceDebugId || !sourceMapDebugId || sourceDebugId !== sourceMapDebugId; - return async function processSource(asset: SourceAndSourceMap): Promise { return pipe(asset, getDebugIds, ({ sourceDebugId, sourceMapDebugId }) => - shouldProcess(sourceDebugId, sourceMapDebugId) - ? pipe( - asset, - (asset) => - sourceProcessor.processSourceAndSourceMap( - asset.source.content, - asset.sourceMap.content, - sourceDebugId ?? sourceMapDebugId, - ), - (result) => - ({ - source: { ...asset.source, content: result.source }, - sourceMap: { ...asset.sourceMap, content: result.sourceMap }, - debugId: result.debugId, - } as ProcessedSourceAndSourceMap), - ) - : ({ ...asset, debugId: sourceDebugId } as ProcessedSourceAndSourceMap), + pipe( + asset, + (asset) => + sourceProcessor.processSourceAndSourceMap( + asset.source.content, + asset.sourceMap.content, + sourceDebugId ?? sourceMapDebugId, + force, + ), + (result) => + ({ + source: { ...asset.source, content: result.source }, + sourceMap: { ...asset.sourceMap, content: result.sourceMap }, + debugId: result.debugId, + } as ProcessedSourceAndSourceMap), + ), ); }; } From c2887d8173be2ab22544c16c56f93c08c0c7d283 Mon Sep 17 00:00:00 2001 From: Sebastian Alex Date: Thu, 30 Nov 2023 13:25:17 +0000 Subject: [PATCH 5/6] cli: fix unit tests --- .../entry1.js | 2 +- .../entry2.js | 2 +- .../entry1.js | 2 +- .../entry2.js | 2 +- .../processed-not-linked-sourcemaps/entry1.js | 2 +- .../processed-not-linked-sourcemaps/entry2.js | 2 +- .../tests/_files/processed-sources/entry1.js | 2 +- .../tests/_files/processed-sources/entry2.js | 2 +- .../_files/processed-with-sources/entry1.js | 2 +- .../_files/processed-with-sources/entry2.js | 2 +- tools/cli/tests/_files/processed/entry1.js | 2 +- tools/cli/tests/_files/processed/entry2.js | 2 +- tools/cli/tests/sourcemaps/process.spec.ts | 49 ++++++++++++++++--- 13 files changed, 54 insertions(+), 19 deletions(-) diff --git a/tools/cli/tests/_files/processed-directory-linked-sourcemaps/entry1.js b/tools/cli/tests/_files/processed-directory-linked-sourcemaps/entry1.js index 0ea660f7..9dacc1d3 100644 --- a/tools/cli/tests/_files/processed-directory-linked-sourcemaps/entry1.js +++ b/tools/cli/tests/_files/processed-directory-linked-sourcemaps/entry1.js @@ -1,4 +1,4 @@ -;!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new Error).stack;n&&(e._btDebugIds=e._btDebugIds||{},e._btDebugIds[n]="4fe9a5c9-ab48-b240-9469-04aa2db251b6")}catch(e){}}(); +;!function(){try{var k="_btDebugIds",u="undefined",v="4fe9a5c9-ab48-b240-9469-04aa2db251b6",a=function(x){try{x[k]=x[k]||{};x[k][n]=v}catch{}},n=(new Error).stack;n&&(u!=typeof window?a(window):u);n&&(u!=typeof global?a(global):u);n&&(u!=typeof self?a(self):u);n&&(u!=typeof globalThis?a(globalThis):u)}catch{}}(); function doSomething() { console.log('Done something'); } diff --git a/tools/cli/tests/_files/processed-directory-linked-sourcemaps/entry2.js b/tools/cli/tests/_files/processed-directory-linked-sourcemaps/entry2.js index 6c17bb4c..fcd75fcf 100644 --- a/tools/cli/tests/_files/processed-directory-linked-sourcemaps/entry2.js +++ b/tools/cli/tests/_files/processed-directory-linked-sourcemaps/entry2.js @@ -1,4 +1,4 @@ -;!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new Error).stack;n&&(e._btDebugIds=e._btDebugIds||{},e._btDebugIds[n]="d538bdaa-8149-8111-25f0-b5c0f472366a")}catch(e){}}(); +;!function(){try{var k="_btDebugIds",u="undefined",v="d538bdaa-8149-8111-25f0-b5c0f472366a",a=function(x){try{x[k]=x[k]||{};x[k][n]=v}catch{}},n=(new Error).stack;n&&(u!=typeof window?a(window):u);n&&(u!=typeof global?a(global):u);n&&(u!=typeof self?a(self):u);n&&(u!=typeof globalThis?a(globalThis):u)}catch{}}(); function doSomething() { console.log('Done something'); } diff --git a/tools/cli/tests/_files/processed-not-linked-different-name-sourcemaps/entry1.js b/tools/cli/tests/_files/processed-not-linked-different-name-sourcemaps/entry1.js index 06b37938..e2692f1f 100644 --- a/tools/cli/tests/_files/processed-not-linked-different-name-sourcemaps/entry1.js +++ b/tools/cli/tests/_files/processed-not-linked-different-name-sourcemaps/entry1.js @@ -1,4 +1,4 @@ -;!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new Error).stack;n&&(e._btDebugIds=e._btDebugIds||{},e._btDebugIds[n]="4fe9a5c9-ab48-b240-9469-04aa2db251b6")}catch(e){}}(); +;!function(){try{var k="_btDebugIds",u="undefined",v="4fe9a5c9-ab48-b240-9469-04aa2db251b6",a=function(x){try{x[k]=x[k]||{};x[k][n]=v}catch{}},n=(new Error).stack;n&&(u!=typeof window?a(window):u);n&&(u!=typeof global?a(global):u);n&&(u!=typeof self?a(self):u);n&&(u!=typeof globalThis?a(globalThis):u)}catch{}}(); function doSomething() { console.log('Done something'); } diff --git a/tools/cli/tests/_files/processed-not-linked-different-name-sourcemaps/entry2.js b/tools/cli/tests/_files/processed-not-linked-different-name-sourcemaps/entry2.js index 01807da2..8ab68139 100644 --- a/tools/cli/tests/_files/processed-not-linked-different-name-sourcemaps/entry2.js +++ b/tools/cli/tests/_files/processed-not-linked-different-name-sourcemaps/entry2.js @@ -1,4 +1,4 @@ -;!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new Error).stack;n&&(e._btDebugIds=e._btDebugIds||{},e._btDebugIds[n]="d538bdaa-8149-8111-25f0-b5c0f472366a")}catch(e){}}(); +;!function(){try{var k="_btDebugIds",u="undefined",v="d538bdaa-8149-8111-25f0-b5c0f472366a",a=function(x){try{x[k]=x[k]||{};x[k][n]=v}catch{}},n=(new Error).stack;n&&(u!=typeof window?a(window):u);n&&(u!=typeof global?a(global):u);n&&(u!=typeof self?a(self):u);n&&(u!=typeof globalThis?a(globalThis):u)}catch{}}(); function doSomething() { console.log('Done something'); } diff --git a/tools/cli/tests/_files/processed-not-linked-sourcemaps/entry1.js b/tools/cli/tests/_files/processed-not-linked-sourcemaps/entry1.js index 06b37938..e2692f1f 100644 --- a/tools/cli/tests/_files/processed-not-linked-sourcemaps/entry1.js +++ b/tools/cli/tests/_files/processed-not-linked-sourcemaps/entry1.js @@ -1,4 +1,4 @@ -;!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new Error).stack;n&&(e._btDebugIds=e._btDebugIds||{},e._btDebugIds[n]="4fe9a5c9-ab48-b240-9469-04aa2db251b6")}catch(e){}}(); +;!function(){try{var k="_btDebugIds",u="undefined",v="4fe9a5c9-ab48-b240-9469-04aa2db251b6",a=function(x){try{x[k]=x[k]||{};x[k][n]=v}catch{}},n=(new Error).stack;n&&(u!=typeof window?a(window):u);n&&(u!=typeof global?a(global):u);n&&(u!=typeof self?a(self):u);n&&(u!=typeof globalThis?a(globalThis):u)}catch{}}(); function doSomething() { console.log('Done something'); } diff --git a/tools/cli/tests/_files/processed-not-linked-sourcemaps/entry2.js b/tools/cli/tests/_files/processed-not-linked-sourcemaps/entry2.js index 01807da2..8ab68139 100644 --- a/tools/cli/tests/_files/processed-not-linked-sourcemaps/entry2.js +++ b/tools/cli/tests/_files/processed-not-linked-sourcemaps/entry2.js @@ -1,4 +1,4 @@ -;!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new Error).stack;n&&(e._btDebugIds=e._btDebugIds||{},e._btDebugIds[n]="d538bdaa-8149-8111-25f0-b5c0f472366a")}catch(e){}}(); +;!function(){try{var k="_btDebugIds",u="undefined",v="d538bdaa-8149-8111-25f0-b5c0f472366a",a=function(x){try{x[k]=x[k]||{};x[k][n]=v}catch{}},n=(new Error).stack;n&&(u!=typeof window?a(window):u);n&&(u!=typeof global?a(global):u);n&&(u!=typeof self?a(self):u);n&&(u!=typeof globalThis?a(globalThis):u)}catch{}}(); function doSomething() { console.log('Done something'); } diff --git a/tools/cli/tests/_files/processed-sources/entry1.js b/tools/cli/tests/_files/processed-sources/entry1.js index b794798d..c8d4c332 100644 --- a/tools/cli/tests/_files/processed-sources/entry1.js +++ b/tools/cli/tests/_files/processed-sources/entry1.js @@ -1,4 +1,4 @@ -;!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new Error).stack;n&&(e._btDebugIds=e._btDebugIds||{},e._btDebugIds[n]="4fe9a5c9-ab48-b240-9469-04aa2db251b6")}catch(e){}}(); +;!function(){try{var k="_btDebugIds",u="undefined",v="4fe9a5c9-ab48-b240-9469-04aa2db251b6",a=function(x){try{x[k]=x[k]||{};x[k][n]=v}catch{}},n=(new Error).stack;n&&(u!=typeof window?a(window):u);n&&(u!=typeof global?a(global):u);n&&(u!=typeof self?a(self):u);n&&(u!=typeof globalThis?a(globalThis):u)}catch{}}(); function doSomething() { console.log('Done something'); } diff --git a/tools/cli/tests/_files/processed-sources/entry2.js b/tools/cli/tests/_files/processed-sources/entry2.js index 37540d13..ed6bbbe9 100644 --- a/tools/cli/tests/_files/processed-sources/entry2.js +++ b/tools/cli/tests/_files/processed-sources/entry2.js @@ -1,4 +1,4 @@ -;!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new Error).stack;n&&(e._btDebugIds=e._btDebugIds||{},e._btDebugIds[n]="d538bdaa-8149-8111-25f0-b5c0f472366a")}catch(e){}}(); +;!function(){try{var k="_btDebugIds",u="undefined",v="d538bdaa-8149-8111-25f0-b5c0f472366a",a=function(x){try{x[k]=x[k]||{};x[k][n]=v}catch{}},n=(new Error).stack;n&&(u!=typeof window?a(window):u);n&&(u!=typeof global?a(global):u);n&&(u!=typeof self?a(self):u);n&&(u!=typeof globalThis?a(globalThis):u)}catch{}}(); function doSomething() { console.log('Done something'); } diff --git a/tools/cli/tests/_files/processed-with-sources/entry1.js b/tools/cli/tests/_files/processed-with-sources/entry1.js index b794798d..c8d4c332 100644 --- a/tools/cli/tests/_files/processed-with-sources/entry1.js +++ b/tools/cli/tests/_files/processed-with-sources/entry1.js @@ -1,4 +1,4 @@ -;!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new Error).stack;n&&(e._btDebugIds=e._btDebugIds||{},e._btDebugIds[n]="4fe9a5c9-ab48-b240-9469-04aa2db251b6")}catch(e){}}(); +;!function(){try{var k="_btDebugIds",u="undefined",v="4fe9a5c9-ab48-b240-9469-04aa2db251b6",a=function(x){try{x[k]=x[k]||{};x[k][n]=v}catch{}},n=(new Error).stack;n&&(u!=typeof window?a(window):u);n&&(u!=typeof global?a(global):u);n&&(u!=typeof self?a(self):u);n&&(u!=typeof globalThis?a(globalThis):u)}catch{}}(); function doSomething() { console.log('Done something'); } diff --git a/tools/cli/tests/_files/processed-with-sources/entry2.js b/tools/cli/tests/_files/processed-with-sources/entry2.js index 37540d13..ed6bbbe9 100644 --- a/tools/cli/tests/_files/processed-with-sources/entry2.js +++ b/tools/cli/tests/_files/processed-with-sources/entry2.js @@ -1,4 +1,4 @@ -;!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new Error).stack;n&&(e._btDebugIds=e._btDebugIds||{},e._btDebugIds[n]="d538bdaa-8149-8111-25f0-b5c0f472366a")}catch(e){}}(); +;!function(){try{var k="_btDebugIds",u="undefined",v="d538bdaa-8149-8111-25f0-b5c0f472366a",a=function(x){try{x[k]=x[k]||{};x[k][n]=v}catch{}},n=(new Error).stack;n&&(u!=typeof window?a(window):u);n&&(u!=typeof global?a(global):u);n&&(u!=typeof self?a(self):u);n&&(u!=typeof globalThis?a(globalThis):u)}catch{}}(); function doSomething() { console.log('Done something'); } diff --git a/tools/cli/tests/_files/processed/entry1.js b/tools/cli/tests/_files/processed/entry1.js index b794798d..c8d4c332 100644 --- a/tools/cli/tests/_files/processed/entry1.js +++ b/tools/cli/tests/_files/processed/entry1.js @@ -1,4 +1,4 @@ -;!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new Error).stack;n&&(e._btDebugIds=e._btDebugIds||{},e._btDebugIds[n]="4fe9a5c9-ab48-b240-9469-04aa2db251b6")}catch(e){}}(); +;!function(){try{var k="_btDebugIds",u="undefined",v="4fe9a5c9-ab48-b240-9469-04aa2db251b6",a=function(x){try{x[k]=x[k]||{};x[k][n]=v}catch{}},n=(new Error).stack;n&&(u!=typeof window?a(window):u);n&&(u!=typeof global?a(global):u);n&&(u!=typeof self?a(self):u);n&&(u!=typeof globalThis?a(globalThis):u)}catch{}}(); function doSomething() { console.log('Done something'); } diff --git a/tools/cli/tests/_files/processed/entry2.js b/tools/cli/tests/_files/processed/entry2.js index 37540d13..ed6bbbe9 100644 --- a/tools/cli/tests/_files/processed/entry2.js +++ b/tools/cli/tests/_files/processed/entry2.js @@ -1,4 +1,4 @@ -;!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new Error).stack;n&&(e._btDebugIds=e._btDebugIds||{},e._btDebugIds[n]="d538bdaa-8149-8111-25f0-b5c0f472366a")}catch(e){}}(); +;!function(){try{var k="_btDebugIds",u="undefined",v="d538bdaa-8149-8111-25f0-b5c0f472366a",a=function(x){try{x[k]=x[k]||{};x[k][n]=v}catch{}},n=(new Error).stack;n&&(u!=typeof window?a(window):u);n&&(u!=typeof global?a(global):u);n&&(u!=typeof self?a(self):u);n&&(u!=typeof globalThis?a(globalThis):u)}catch{}}(); function doSomething() { console.log('Done something'); } diff --git a/tools/cli/tests/sourcemaps/process.spec.ts b/tools/cli/tests/sourcemaps/process.spec.ts index 90710d24..509b8c0c 100644 --- a/tools/cli/tests/sourcemaps/process.spec.ts +++ b/tools/cli/tests/sourcemaps/process.spec.ts @@ -84,7 +84,12 @@ describe('process', () => { assert(result.isOk(), result.data as string); for (const source of Object.values(originalSources)) { - expect(spy).toBeCalledWith(source, expect.anything(), expectAnythingOrNothing()); + expect(spy).toBeCalledWith( + source, + expect.anything(), + expectAnythingOrNothing(), + expectAnythingOrNothing(), + ); } }), ); @@ -194,7 +199,12 @@ describe('process', () => { assert(result.isOk(), result.data as string); for (const source of Object.values(originalSources)) { - expect(spy).toBeCalledWith(source, expect.anything(), expectAnythingOrNothing()); + expect(spy).toBeCalledWith( + source, + expect.anything(), + expectAnythingOrNothing(), + expectAnythingOrNothing(), + ); } }), ); @@ -358,7 +368,12 @@ describe('process', () => { assert(result.isOk(), result.data as string); for (const source of Object.values(originalSources)) { - expect(spy).toBeCalledWith(source, expect.anything(), expectAnythingOrNothing()); + expect(spy).toBeCalledWith( + source, + expect.anything(), + expectAnythingOrNothing(), + expectAnythingOrNothing(), + ); } }), ); @@ -439,7 +454,12 @@ describe('process', () => { assert(result.isOk(), result.data as string); for (const source of Object.values(originalSources)) { - expect(spy).toBeCalledWith(source, expect.anything(), expectAnythingOrNothing()); + expect(spy).toBeCalledWith( + source, + expect.anything(), + expectAnythingOrNothing(), + expectAnythingOrNothing(), + ); } }), ); @@ -520,7 +540,12 @@ describe('process', () => { assert(result.isOk(), result.data as string); for (const source of Object.values(originalSources)) { - expect(spy).toBeCalledWith(source, expect.anything(), expectAnythingOrNothing()); + expect(spy).toBeCalledWith( + source, + expect.anything(), + expectAnythingOrNothing(), + expectAnythingOrNothing(), + ); } }), ); @@ -601,7 +626,12 @@ describe('process', () => { assert(result.isOk(), result.data as string); for (const source of Object.values(originalSources)) { - expect(spy).toBeCalledWith(source, expect.anything(), expectAnythingOrNothing()); + expect(spy).toBeCalledWith( + source, + expect.anything(), + expectAnythingOrNothing(), + expectAnythingOrNothing(), + ); } }), ); @@ -688,7 +718,12 @@ describe('process', () => { assert(result.isOk(), result.data as string); for (const source of Object.values(originalSources)) { - expect(spy).toBeCalledWith(source, expect.anything(), expectAnythingOrNothing()); + expect(spy).toBeCalledWith( + source, + expect.anything(), + expectAnythingOrNothing(), + expectAnythingOrNothing(), + ); } }), ); From aeacf955361ea97a98cbfc6c3bc0503919590f96 Mon Sep 17 00:00:00 2001 From: Sebastian Alex Date: Tue, 12 Dec 2023 10:54:51 +0000 Subject: [PATCH 6/6] sourcemap-tools: add doc about regexp in DebugIdGenerator --- tools/sourcemap-tools/src/DebugIdGenerator.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/sourcemap-tools/src/DebugIdGenerator.ts b/tools/sourcemap-tools/src/DebugIdGenerator.ts index 051ba0f7..cf6d1988 100644 --- a/tools/sourcemap-tools/src/DebugIdGenerator.ts +++ b/tools/sourcemap-tools/src/DebugIdGenerator.ts @@ -2,6 +2,11 @@ export const SOURCE_DEBUG_ID_VARIABLE = '_btDebugIds'; export const SOURCE_DEBUG_ID_COMMENT = 'debugId'; export const SOURCEMAP_DEBUG_ID_KEY = 'debugId'; +/** + * Matches leading and trailing semicolons, e.g. in `;;foo;bar;;` + */ +const MATCH_SEMICOLONS_REGEX = /^;+|;+$/; + export class DebugIdGenerator { public generateSourceSnippet(uuid: string) { return `;!function(){try{var k="${SOURCE_DEBUG_ID_VARIABLE}",u="undefined",v="${uuid}",a=function(x){try{x[k]=x[k]||{};x[k][n]=v}catch{}},n=(new Error).stack;n&&(u!=typeof window?a(window):u);n&&(u!=typeof global?a(global):u);n&&(u!=typeof self?a(self):u);n&&(u!=typeof globalThis?a(globalThis):u)}catch{}}();`; @@ -15,7 +20,7 @@ export class DebugIdGenerator { const replaceAll = () => source.replace(oldDebugId, newDebugId); // Try to replace more safely first - const oldSourceSnippet = this.generateSourceSnippet(oldDebugId).replace(/^;+|;+$/g, ''); + const oldSourceSnippet = this.generateSourceSnippet(oldDebugId).replace(MATCH_SEMICOLONS_REGEX, ''); if (source.indexOf(oldSourceSnippet) !== -1) { source = source.replace(oldSourceSnippet, this.generateSourceSnippet(newDebugId)); } else { @@ -33,7 +38,7 @@ export class DebugIdGenerator { } public hasCodeSnippet(source: string, debugId: string) { - const sourceSnippet = this.generateSourceSnippet(debugId).replace(/^;+|;+$/g, ''); + const sourceSnippet = this.generateSourceSnippet(debugId).replace(MATCH_SEMICOLONS_REGEX, ''); return source.includes(sourceSnippet); }