Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
generateDebugId,
injectDebugIdIntoJs,
injectDebugIdIntoSourceMap,
stripDebugIdFromSourceMap,
} from '../../utils/debug-id';

/**
Expand Down Expand Up @@ -42,8 +43,10 @@ export function injectDebugIds(outputFiles: BuildOutputFile[]): void {
continue;
}

const id = generateDebugId(map.contents);
const mapText = map.text;
const mapTextForHash = stripDebugIdFromSourceMap(mapText);
const id = generateDebugId(mapTextForHash);
file.contents = encoder.encode(injectDebugIdIntoJs(file.text, id));
map.contents = encoder.encode(injectDebugIdIntoSourceMap(map.text, id));
map.contents = encoder.encode(injectDebugIdIntoSourceMap(mapText, id));
}
}
14 changes: 11 additions & 3 deletions packages/angular/build/src/utils/debug-id.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ export function generateDebugId(name: string | Uint8Array): string {
return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20, 32)}`;
}

/** Pattern matching an existing `//# debugId=<uuid>` comment anywhere in the file. */
const DEBUG_ID_COMMENT = /\n\/\/# debugId=[^\r\n]*\n?/;
/** Pattern matching an existing `//# debugId=<uuid>` comment at the end of the file. */
const DEBUG_ID_COMMENT = /(\n\/\/# debugId=[^\r\n]*)(\n\/\/# sourceMappingURL=[^\r\n]*)?(\s*)$/;

/** Pattern matching the `//# sourceMappingURL=` comment, used to position the debug-id line. */
const SOURCE_MAPPING_URL_COMMENT = /\n\/\/# sourceMappingURL=[^\r\n]*\s*$/;
Expand All @@ -58,7 +58,7 @@ export function injectDebugIdIntoJs(text: string, id: string): string {

// Replace any existing debugId comment to keep the operation idempotent.
if (DEBUG_ID_COMMENT.test(text)) {
return text.replace(DEBUG_ID_COMMENT, `\n${comment}\n`);
return text.replace(DEBUG_ID_COMMENT, (_, p1, p2, p3) => `\n${comment}${p2 || ''}${p3 || ''}`);
}

if (SOURCE_MAPPING_URL_COMMENT.test(text)) {
Expand Down Expand Up @@ -96,3 +96,11 @@ export function injectDebugIdIntoSourceMap(json: string, id: string): string {

return JSON.stringify(parsed, null, indent);
}

/**
* Strips any existing `debugId` field from the source map JSON string to restore
* the original JSON contents for deterministic/idempotent hashing.
*/
export function stripDebugIdFromSourceMap(json: string): string {
return json.replace(/,\s*"debugId"\s*:\s*"[^"]*"|\s*"debugId"\s*:\s*"[^"]*"\s*,?/g, '');
}
Comment thread
clydin marked this conversation as resolved.
41 changes: 40 additions & 1 deletion packages/angular/build/src/utils/debug-id_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@
* found in the LICENSE file at https://angular.dev/license
*/

import { generateDebugId, injectDebugIdIntoJs, injectDebugIdIntoSourceMap } from './debug-id';
import {
generateDebugId,
injectDebugIdIntoJs,
injectDebugIdIntoSourceMap,
stripDebugIdFromSourceMap,
} from './debug-id';

const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;

Expand Down Expand Up @@ -59,6 +64,17 @@ describe('debug-id', () => {
// Re-running with the same id is a no-op.
expect(injectDebugIdIntoJs(result, id)).toBe(result);
});

it('does not replace a debugId comment that is inside a string or template literal', () => {
const text =
'const t = `\n//# debugId=00000000-0000-5000-8000-000000000000\n`;\n//# sourceMappingURL=foo.js.map\n';
const result = injectDebugIdIntoJs(text, id);
expect(result).toBe(
'const t = `\n//# debugId=00000000-0000-5000-8000-000000000000\n`;\n' +
`//# debugId=${id}\n` +
'//# sourceMappingURL=foo.js.map\n',
);
});
});

describe('injectDebugIdIntoSourceMap', () => {
Expand Down Expand Up @@ -95,4 +111,27 @@ describe('debug-id', () => {
expect(injectDebugIdIntoSourceMap(malformed, id)).toBe(malformed);
});
});

describe('stripDebugIdFromSourceMap', () => {
it('removes the debugId field from pretty-printed source maps', () => {
const original = '{\n\t"version": 3,\n\t"mappings": ""\n}';
const updated =
'{\n\t"version": 3,\n\t"mappings": "",\n\t"debugId": "11111111-2222-5333-9444-555555555555"\n}';
expect(stripDebugIdFromSourceMap(updated)).toBe(original);
});

it('removes the debugId field from minified source maps', () => {
const original = '{"version":3,"mappings":""}';
const updated =
'{"version":3,"mappings":"","debugId":"11111111-2222-5333-9444-555555555555"}';
expect(stripDebugIdFromSourceMap(updated)).toBe(original);
});

it('removes the debugId field when it is the first property', () => {
const original = '{\n\t"version": 3,\n\t"mappings": ""\n}';
const updated =
'{\n\t"debugId": "11111111-2222-5333-9444-555555555555",\n\t"version": 3,\n\t"mappings": ""\n}';
expect(stripDebugIdFromSourceMap(updated)).toBe(original);
});
});
Comment thread
clydin marked this conversation as resolved.
});
Loading