From 44a23f423ba3a94c4532551c76de01af88ee0127 Mon Sep 17 00:00:00 2001 From: Hector Hernandez <39923391+hectorhdzg@users.noreply.github.com> Date: Tue, 26 May 2026 13:40:51 -0700 Subject: [PATCH 1/3] fix: remove invalid PURE literal annotations and add bundle validation tests --- AISKU/Tests/Unit/src/AISKUSize.Tests.ts | 27 +++++++++++++++++++ AISKU/src/internal/trace/spanUtils.ts | 4 +-- .../Unit/src/ai/AppInsightsCoreSize.Tests.ts | 27 +++++++++++++++++++ shared/AppInsightsCore/src/ext/extUtils.ts | 4 +-- 4 files changed, 58 insertions(+), 4 deletions(-) diff --git a/AISKU/Tests/Unit/src/AISKUSize.Tests.ts b/AISKU/Tests/Unit/src/AISKUSize.Tests.ts index f40aec3dd..ab473a702 100644 --- a/AISKU/Tests/Unit/src/AISKUSize.Tests.ts +++ b/AISKU/Tests/Unit/src/AISKUSize.Tests.ts @@ -92,6 +92,7 @@ export class AISKUSizeCheck extends AITestClass { public registerTests() { this.addRawFileSizeCheck(); this.addProdFileSizeCheck(); + this.addRolldownPureAnnotationCheck(); } constructor() { @@ -105,6 +106,32 @@ export class AISKUSizeCheck extends AITestClass { private addProdFileSizeCheck(): void { this._checkFileSize(true); } + + private addRolldownPureAnnotationCheck(): void { + this.testCase({ + name: "Test AISKU dist has valid PURE annotation placement for Rolldown", + test: () => { + let request = new Request(this.rawFilePath, { method: "GET" }); + return fetch(request).then((response) => { + if (!response.ok) { + Assert.ok(false, `fetch AISKU dist for PURE annotation check error: ${response.statusText}`); + return; + } + + return response.text().then((text) => { + // Rolldown only accepts PURE on call/new expressions; literals/null inside parens are invalid. + let invalidPurePattern = /\(\s*\/\*\s*[#@]__PURE__\s*\*\/\s*(?:"|null\b)/g; + let matches = text.match(invalidPurePattern) || []; + Assert.equal(0, matches.length, `Found ${matches.length} invalid PURE annotation placements in AISKU dist`); + }, (error: Error) => { + Assert.ok(false, `AISKU dist PURE annotation check response error: ${error}`); + }); + }).catch((error: Error) => { + Assert.ok(false, `AISKU dist PURE annotation check error: ${error}`); + }); + } + }); + } private _checkFileSize(isProd: boolean): void { let _filePath = isProd? this.prodFilePath : this.rawFilePath; diff --git a/AISKU/src/internal/trace/spanUtils.ts b/AISKU/src/internal/trace/spanUtils.ts index 9ba03d029..fff54454f 100644 --- a/AISKU/src/internal/trace/spanUtils.ts +++ b/AISKU/src/internal/trace/spanUtils.ts @@ -48,9 +48,9 @@ const MessageBusDestination = "message_bus.destination"; const TIME_SINCE_ENQUEUED = "timeSinceEnqueued"; const PORT_REGEX: ILazyValue = (/*#__PURE__*/ getLazy(() => new RegExp(/(https?)(:\/\/.*)(:\d+)(\S*)/))); -const HTTP_DOT = (/*#__PURE__*/ "http."); +const HTTP_DOT = "http."; -const _MS_PROCESSED_BY_METRICS_EXTRACTORS = (/* #__PURE__*/"_MS.ProcessedByMetricExtractors"); +const _MS_PROCESSED_BY_METRICS_EXTRACTORS = "_MS.ProcessedByMetricExtractors"; /** * Legacy HTTP semantic convention values diff --git a/shared/AppInsightsCore/Tests/Unit/src/ai/AppInsightsCoreSize.Tests.ts b/shared/AppInsightsCore/Tests/Unit/src/ai/AppInsightsCoreSize.Tests.ts index 8997e871d..5c885ac91 100644 --- a/shared/AppInsightsCore/Tests/Unit/src/ai/AppInsightsCoreSize.Tests.ts +++ b/shared/AppInsightsCore/Tests/Unit/src/ai/AppInsightsCoreSize.Tests.ts @@ -67,6 +67,7 @@ export class AppInsightsCoreSizeCheck extends AITestClass { public registerTests() { this.addRawFileSizeCheck(); this.addProdFileSizeCheck(); + this.addRolldownPureAnnotationCheck(); } constructor() { @@ -80,6 +81,32 @@ export class AppInsightsCoreSizeCheck extends AITestClass { private addProdFileSizeCheck(): void { this._fileSizeCheck(true); } + + private addRolldownPureAnnotationCheck(): void { + this.testCase({ + name: "Test applicationinsights-core dist has valid PURE annotation placement for Rolldown", + test: () => { + let request = new Request(this.rawFilePath, { method: "GET" }); + return fetch(request).then((response) => { + if (!response.ok) { + Assert.ok(false, `fetch applicationinsights-core dist for PURE annotation check error: ${response.statusText}`); + return; + } + + return response.text().then((text) => { + // Rolldown only accepts PURE on call/new expressions; literals/null inside parens are invalid. + let invalidPurePattern = /\(\s*\/\*\s*[#@]__PURE__\s*\*\/\s*(?:"|null\b)/g; + let matches = text.match(invalidPurePattern) || []; + Assert.equal(0, matches.length, `Found ${matches.length} invalid PURE annotation placements in AppInsightsCore dist`); + }, (error) => { + Assert.ok(false, `applicationinsights-core dist PURE annotation check response error: ${error}`); + }); + }).catch((error: Error) => { + Assert.ok(false, `applicationinsights-core dist PURE annotation check error: ${error}`); + }); + } + }); + } private _fileSizeCheck(isProd: boolean): void { let _filePath = isProd? this.prodFilePath : this.rawFilePath; diff --git a/shared/AppInsightsCore/src/ext/extUtils.ts b/shared/AppInsightsCore/src/ext/extUtils.ts index 9107aea2f..d1b7c7c28 100644 --- a/shared/AppInsightsCore/src/ext/extUtils.ts +++ b/shared/AppInsightsCore/src/ext/extUtils.ts @@ -19,7 +19,7 @@ import { isReactNative } from "../utils/EnvUtils"; /** * Identifies the version for the extended SDK */ -export const ExtVersion = "4.4.1"; +export const ExtVersion = "#extVersion#"; /** * Identifies the full version for the extended SDK @@ -61,7 +61,7 @@ const _fieldTypeEventPropMap = { */ // let _uaDisallowsSameSiteNone = null; -var uInt8ArraySupported: boolean | null = (/* #__PURE__*/ null); +var uInt8ArraySupported: boolean | null = null; // var _areCookiesAvailable: boolean | undefined; /** From ad95fbdf93eac3278399f02c35a37991d9f9a2dc Mon Sep 17 00:00:00 2001 From: Hector Hernandez <39923391+hectorhdzg@users.noreply.github.com> Date: Wed, 27 May 2026 16:21:43 -0700 Subject: [PATCH 2/3] Normalize PURE annotations in final rollup pass Keep legacy parenthesized PURE markers in source and canonicalize emitted bundle annotations as a final rollup plugin pass. Update AISKU and AppInsightsCore size tests to validate canonical PURE spacing in dist output. --- AISKU/Tests/Unit/src/AISKUSize.Tests.ts | 10 +++---- AISKU/src/internal/trace/spanUtils.ts | 4 +-- rollup.base.config.js | 26 +++++++++++++++++++ .../Unit/src/ai/AppInsightsCoreSize.Tests.ts | 10 +++---- shared/AppInsightsCore/src/ext/extUtils.ts | 2 +- 5 files changed, 39 insertions(+), 13 deletions(-) diff --git a/AISKU/Tests/Unit/src/AISKUSize.Tests.ts b/AISKU/Tests/Unit/src/AISKUSize.Tests.ts index ab473a702..87052898d 100644 --- a/AISKU/Tests/Unit/src/AISKUSize.Tests.ts +++ b/AISKU/Tests/Unit/src/AISKUSize.Tests.ts @@ -109,7 +109,7 @@ export class AISKUSizeCheck extends AITestClass { private addRolldownPureAnnotationCheck(): void { this.testCase({ - name: "Test AISKU dist has valid PURE annotation placement for Rolldown", + name: "Test AISKU dist canonicalizes PURE annotation spacing", test: () => { let request = new Request(this.rawFilePath, { method: "GET" }); return fetch(request).then((response) => { @@ -119,10 +119,10 @@ export class AISKUSizeCheck extends AITestClass { } return response.text().then((text) => { - // Rolldown only accepts PURE on call/new expressions; literals/null inside parens are invalid. - let invalidPurePattern = /\(\s*\/\*\s*[#@]__PURE__\s*\*\/\s*(?:"|null\b)/g; - let matches = text.match(invalidPurePattern) || []; - Assert.equal(0, matches.length, `Found ${matches.length} invalid PURE annotation placements in AISKU dist`); + // Validate the final bundle no longer contains spaced PURE comment forms. + let nonCanonicalPurePattern = /\(\s+\/\*\s*[#@]__PURE__\s*\*\/|\(\s*\/\*\s*[#@]__PURE__\s*\*\/\s+/g; + let matches = text.match(nonCanonicalPurePattern) || []; + Assert.equal(0, matches.length, `Found ${matches.length} non-canonical PURE annotations in AISKU dist`); }, (error: Error) => { Assert.ok(false, `AISKU dist PURE annotation check response error: ${error}`); }); diff --git a/AISKU/src/internal/trace/spanUtils.ts b/AISKU/src/internal/trace/spanUtils.ts index fff54454f..9ba03d029 100644 --- a/AISKU/src/internal/trace/spanUtils.ts +++ b/AISKU/src/internal/trace/spanUtils.ts @@ -48,9 +48,9 @@ const MessageBusDestination = "message_bus.destination"; const TIME_SINCE_ENQUEUED = "timeSinceEnqueued"; const PORT_REGEX: ILazyValue = (/*#__PURE__*/ getLazy(() => new RegExp(/(https?)(:\/\/.*)(:\d+)(\S*)/))); -const HTTP_DOT = "http."; +const HTTP_DOT = (/*#__PURE__*/ "http."); -const _MS_PROCESSED_BY_METRICS_EXTRACTORS = "_MS.ProcessedByMetricExtractors"; +const _MS_PROCESSED_BY_METRICS_EXTRACTORS = (/* #__PURE__*/"_MS.ProcessedByMetricExtractors"); /** * Legacy HTTP semantic convention values diff --git a/rollup.base.config.js b/rollup.base.config.js index 4b6f18efb..5f3690b5b 100644 --- a/rollup.base.config.js +++ b/rollup.base.config.js @@ -30,6 +30,26 @@ function doCleanup() { }) } +function fixPureAnnotations() { + const PURE_COMMENT_CANONICALIZE = /\(\s*\/\*\s*([#@])__PURE__\s*\*\/\s*/g; + + return { + name: "fix-pure-annotations", + renderChunk(code) { + let normalized = code.replace(PURE_COMMENT_CANONICALIZE, "(/*$1__PURE__*/"); + + if (normalized === code) { + return null; + } + + return { + code: normalized, + map: null + }; + } + }; +} + const getNamespace = (prefix, namespaces, baseName, rootName) => { var result = prefix + "var " + baseName + "=" + rootName; if (namespaces.length > 0) { @@ -361,6 +381,9 @@ const browserRollupConfigFactory = (isOneDs, banner, importCheckNames, targetTyp ); } + // Keep this as the final pass so all generated/included PURE comments are normalized. + browserRollupConfig.plugins.push(fixPureAnnotations()); + // console.log(`Browser: ${JSON.stringify(browserRollupConfig)}`); return browserRollupConfig; @@ -422,6 +445,9 @@ const nodeUmdRollupConfigFactory = (banner, importCheckNames, targetType, theNam ); } + // Keep this as the final pass so all generated/included PURE comments are normalized. + nodeRollupConfig.plugins.push(fixPureAnnotations()); + return nodeRollupConfig; }; diff --git a/shared/AppInsightsCore/Tests/Unit/src/ai/AppInsightsCoreSize.Tests.ts b/shared/AppInsightsCore/Tests/Unit/src/ai/AppInsightsCoreSize.Tests.ts index 5c885ac91..3037ed3c3 100644 --- a/shared/AppInsightsCore/Tests/Unit/src/ai/AppInsightsCoreSize.Tests.ts +++ b/shared/AppInsightsCore/Tests/Unit/src/ai/AppInsightsCoreSize.Tests.ts @@ -84,7 +84,7 @@ export class AppInsightsCoreSizeCheck extends AITestClass { private addRolldownPureAnnotationCheck(): void { this.testCase({ - name: "Test applicationinsights-core dist has valid PURE annotation placement for Rolldown", + name: "Test applicationinsights-core dist canonicalizes PURE annotation spacing", test: () => { let request = new Request(this.rawFilePath, { method: "GET" }); return fetch(request).then((response) => { @@ -94,10 +94,10 @@ export class AppInsightsCoreSizeCheck extends AITestClass { } return response.text().then((text) => { - // Rolldown only accepts PURE on call/new expressions; literals/null inside parens are invalid. - let invalidPurePattern = /\(\s*\/\*\s*[#@]__PURE__\s*\*\/\s*(?:"|null\b)/g; - let matches = text.match(invalidPurePattern) || []; - Assert.equal(0, matches.length, `Found ${matches.length} invalid PURE annotation placements in AppInsightsCore dist`); + // Validate the final bundle no longer contains spaced PURE comment forms. + let nonCanonicalPurePattern = /\(\s+\/\*\s*[#@]__PURE__\s*\*\/|\(\s*\/\*\s*[#@]__PURE__\s*\*\/\s+/g; + let matches = text.match(nonCanonicalPurePattern) || []; + Assert.equal(0, matches.length, `Found ${matches.length} non-canonical PURE annotations in AppInsightsCore dist`); }, (error) => { Assert.ok(false, `applicationinsights-core dist PURE annotation check response error: ${error}`); }); diff --git a/shared/AppInsightsCore/src/ext/extUtils.ts b/shared/AppInsightsCore/src/ext/extUtils.ts index d1b7c7c28..1a19eb2ca 100644 --- a/shared/AppInsightsCore/src/ext/extUtils.ts +++ b/shared/AppInsightsCore/src/ext/extUtils.ts @@ -61,7 +61,7 @@ const _fieldTypeEventPropMap = { */ // let _uaDisallowsSameSiteNone = null; -var uInt8ArraySupported: boolean | null = null; +var uInt8ArraySupported: boolean | null = (/* #__PURE__*/ null); // var _areCookiesAvailable: boolean | undefined; /** From 2cc1818882b5eaa164075e5b44df08840d12fa83 Mon Sep 17 00:00:00 2001 From: Hector Hernandez <39923391+hectorhdzg@users.noreply.github.com> Date: Wed, 27 May 2026 16:24:59 -0700 Subject: [PATCH 3/3] ci: skip puppeteer browser download in CI --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 52586982a..6fba0af93 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,6 +19,9 @@ jobs: runs-on: ubuntu-latest + env: + PUPPETEER_SKIP_DOWNLOAD: true + strategy: matrix: node-version: [ 18, 20, 22, 24 ]