From 1ccad10dedacbcd88a6b5c8359695b8c029d5616 Mon Sep 17 00:00:00 2001 From: Daniel Ayala <14967941+danielayala94@users.noreply.github.com> Date: Wed, 8 Jan 2025 15:09:42 -0800 Subject: [PATCH] [Telemetry] Address package name limitations - Take 2 (#14259) * Introducing package name processing * Add trimming if string length > 100 * Change files --- ...-f67eede7-8e2c-46b7-9ce9-5d664dfcd76e.json | 7 +++ .../telemetry/src/telemetry.ts | 10 ++- .../telemetry/src/test/nameUtils.test.ts | 62 +++++++++++++++++++ .../telemetry/src/utils/nameUtils.ts | 18 ++++++ 4 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 change/@react-native-windows-telemetry-f67eede7-8e2c-46b7-9ce9-5d664dfcd76e.json create mode 100644 packages/@react-native-windows/telemetry/src/test/nameUtils.test.ts create mode 100644 packages/@react-native-windows/telemetry/src/utils/nameUtils.ts diff --git a/change/@react-native-windows-telemetry-f67eede7-8e2c-46b7-9ce9-5d664dfcd76e.json b/change/@react-native-windows-telemetry-f67eede7-8e2c-46b7-9ce9-5d664dfcd76e.json new file mode 100644 index 00000000000..bb7d5e44ef6 --- /dev/null +++ b/change/@react-native-windows-telemetry-f67eede7-8e2c-46b7-9ce9-5d664dfcd76e.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "Address package name limitations for telemetry", + "packageName": "@react-native-windows/telemetry", + "email": "14967941+danielayala94@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/packages/@react-native-windows/telemetry/src/telemetry.ts b/packages/@react-native-windows/telemetry/src/telemetry.ts index 00303817482..eb51e9e8cec 100644 --- a/packages/@react-native-windows/telemetry/src/telemetry.ts +++ b/packages/@react-native-windows/telemetry/src/telemetry.ts @@ -11,6 +11,7 @@ import * as basePropUtils from './utils/basePropUtils'; import * as versionUtils from './utils/versionUtils'; import * as errorUtils from './utils/errorUtils'; import * as projectUtils from './utils/projectUtils'; +import * as nameUtils from './utils/nameUtils'; export interface TelemetryOptions { setupString: string; @@ -246,10 +247,15 @@ export class Telemetry { return true; } - if (forceRefresh === true || !Telemetry.versionsProp[name]) { + // Process the package name to comply with the backend requirements + const packageName = nameUtils.isValidTelemetryPackageName(name) + ? name + : nameUtils.cleanTelemetryPackageName(name); + + if (forceRefresh === true || !Telemetry.versionsProp[packageName]) { const value = await getValue(); if (value) { - Telemetry.versionsProp[name] = value; + Telemetry.versionsProp[packageName] = value; return true; } } diff --git a/packages/@react-native-windows/telemetry/src/test/nameUtils.test.ts b/packages/@react-native-windows/telemetry/src/test/nameUtils.test.ts new file mode 100644 index 00000000000..e5c3cf49789 --- /dev/null +++ b/packages/@react-native-windows/telemetry/src/test/nameUtils.test.ts @@ -0,0 +1,62 @@ +/** + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * @format + */ + +import * as nameUtils from '../utils/nameUtils'; + +test('Verify telemetry package name is valid', () => { + expect(nameUtils.isValidTelemetryPackageName('package')).toBe(true); + expect(nameUtils.isValidTelemetryPackageName('@react')).toBe(false); + expect(nameUtils.isValidTelemetryPackageName('react-native')).toBe(false); + expect(nameUtils.isValidTelemetryPackageName('react_native')).toBe(true); + expect(nameUtils.isValidTelemetryPackageName('react_native/cli')).toBe(false); + + // Check for size limits. A valid package name has 100 characters or less. + expect( + nameUtils.isValidTelemetryPackageName( + 'react_native_react_native_react_native_react_native_react_native_react_native_react_native_react_nat', + ), + ).toBe(true); + expect( + nameUtils.isValidTelemetryPackageName( + 'react_native_react_native_react_native_react_native_react_native_react_native_react_native_react_nati', + ), + ).toBe(false); +}); + +test('Verify telemetry package name cleaning', () => { + expect(nameUtils.cleanTelemetryPackageName('package')).toBe('package'); + expect(nameUtils.cleanTelemetryPackageName('@react')).toBe('_react'); + expect(nameUtils.cleanTelemetryPackageName('react-native')).toBe( + 'react_native', + ); + expect(nameUtils.cleanTelemetryPackageName('react_native')).toBe( + 'react_native', + ); + expect(nameUtils.cleanTelemetryPackageName('react_native/cli')).toBe( + 'react_native_cli', + ); + expect(nameUtils.cleanTelemetryPackageName('@react-native-windows/cli')).toBe( + '_react_native_windows_cli', + ); + + expect( + nameUtils.cleanTelemetryPackageName( + 'react_native_react_native_react_native_react_native_react_native_react_native_react_native_react_nat', + ), + ).toBe( + 'react_native_react_native_react_native_react_native_react_native_react_native_react_native_react_nat', + ); + + // Truncate a package name with 101 characters, to the first 100. + expect( + nameUtils.cleanTelemetryPackageName( + 'react_native_react_native_react_native_react_native_react_native_react_native_react_native_react_nati', + ), + ).toBe( + 'react_native_react_native_react_native_react_native_react_native_react_native_react_native_react_nat', + ); +}); diff --git a/packages/@react-native-windows/telemetry/src/utils/nameUtils.ts b/packages/@react-native-windows/telemetry/src/utils/nameUtils.ts new file mode 100644 index 00000000000..31c5c563ce1 --- /dev/null +++ b/packages/@react-native-windows/telemetry/src/utils/nameUtils.ts @@ -0,0 +1,18 @@ +/** + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * @format + */ + +export function isValidTelemetryPackageName(name: string): boolean { + // Accepted characters: alphanumeric, underscore, dot, starts with letter. + // Size: 1-100 characters. + if (name.match(/^[a-zA-Z][a-zA-Z0-9_.]{0,99}$/gi)) { + return true; + } + return false; +} + +export function cleanTelemetryPackageName(str: string): string { + return str.replace(/[^a-zA-Z0-9_.]/g, '_').slice(0, 100); +}