Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[W-17847229] fix: add telemetry for oas generations #6110

Merged
merged 10 commits into from
Feb 26, 2025
Merged
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
28 changes: 12 additions & 16 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions packages/salesforcedx-apex-debugger/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
"@salesforce/salesforcedx-utils": "62.14.1",
"@vscode/debugadapter": "1.68.0",
"@vscode/debugprotocol": "1.68.0",
"async-lock": "1.0.0",
"async-lock": "1.4.1",
"faye": "1.1.2",
"request-light": "^0.7.0"
},
"devDependencies": {
"@salesforce/salesforcedx-test-utils-vscode": "62.14.1",
"@types/async-lock": "0.0.20",
"@types/async-lock": "1.4.2",
"@types/chai": "4.3.3",
"@types/jest": "^29.5.5",
"@types/mocha": "^5",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/

import { extractJsonObject } from '../helpers';
import { extractJson } from '../helpers';

/**
* Type that stores information about a successful diff operation
Expand Down Expand Up @@ -73,7 +73,7 @@ export class DiffResultParser {

constructor(stdout: string) {
try {
this.response = extractJsonObject(stdout);
this.response = extractJson(stdout);
} catch (e) {
const err = new Error('Error parsing diff result');
err.name = 'DiffResultParserFail';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/

import { extractJsonObject } from '../helpers';
import { extractJson } from '../helpers';

export type OrgCreateSuccessResult = {
status: number;
Expand All @@ -31,7 +31,7 @@ export class OrgCreateResultParser {
constructor(stdout: string) {
try {
if (stdout) {
this.response = extractJsonObject(stdout);
this.response = extractJson(stdout);
}
} catch (e) {
const err = new Error('Error parsing org create result');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/

import { extractJsonObject } from '../../helpers';
import { extractJson } from '../../helpers';

export const CONFLICT_ERROR_NAME = 'SourceConflictError';

Expand Down Expand Up @@ -39,7 +39,7 @@ export class ProjectDeployStartResultParser {

constructor(stdout: string) {
try {
this.response = extractJsonObject(stdout);
this.response = extractJson(stdout);
} catch (e) {
const err = new Error('Error parsing project deploy start result');
err.name = 'ProjectDeployStartParserFail';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/

import { extractJsonObject } from '../../helpers';
import { extractJson } from '../../helpers';

export const CONFLICT_ERROR_NAME = 'SourceConflictError';

Expand Down Expand Up @@ -39,7 +39,7 @@ export class ProjectRetrieveStartResultParser {

constructor(stdout: string) {
try {
this.response = extractJsonObject(stdout);
this.response = extractJson(stdout);
} catch (e) {
const err = new Error('Error parsing pull result');
err.name = 'ProjectRetrieveStartParserFail';
Expand Down
7 changes: 3 additions & 4 deletions packages/salesforcedx-utils-vscode/src/helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@ export { TraceFlagsRemover } from './traceFlagsRemover';
export {
asyncFilter,
difference,
extractJsonObject,
extractJsonString,
extractJson,
getJsonCandidate,
getMessageFromError,
containsJsonString,
isJsonString,
identifyJsonTypeInString,
isNullOrUndefined,
fileUtils
} from './utils';
Expand Down
101 changes: 81 additions & 20 deletions packages/salesforcedx-utils-vscode/src/helpers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,93 @@
import { basename } from 'path';
import { telemetryService } from '../telemetry';

export const isNullOrUndefined = (object: any): object is null | undefined => {
return object === null || object === undefined;
};

export const extractJsonObject = (str: string): Record<string, unknown> => {
const jsonString = extractJsonString(str);
return JSON.parse(jsonString) as Record<string, unknown>;
};

export const containsJsonString = (str: string): boolean => {
export const getJsonCandidate = (str: string): string | null => {
const firstCurly = str.indexOf('{');
const lastCurly = str.lastIndexOf('}');
return firstCurly !== -1 && lastCurly !== -1 && firstCurly < lastCurly;
const firstSquare = str.indexOf('[');
const lastSquare = str.lastIndexOf(']');

// Detect the correct JSON structure (object vs. array)
const isObject = firstCurly !== -1 && lastCurly !== -1 && firstCurly < lastCurly;
const isArray = firstSquare !== -1 && lastSquare !== -1 && firstSquare < lastSquare;

let jsonCandidate: string | null = null;

if (isObject && isArray) {
// If both are present, pick the one that appears first
jsonCandidate =
firstCurly < firstSquare ? str.slice(firstCurly, lastCurly + 1) : str.slice(firstSquare, lastSquare + 1);
} else if (isObject) {
jsonCandidate = str.slice(firstCurly, lastCurly + 1);
} else if (isArray) {
jsonCandidate = str.slice(firstSquare, lastSquare + 1);
}
return jsonCandidate;
};

export const isJsonString = (str: string): boolean => {
const firstCurly = str.indexOf('{');
const lastCurly = str.lastIndexOf('}');
return firstCurly === 0 && lastCurly === str.trimEnd().length - 1;
export const identifyJsonTypeInString = (str: string): 'object' | 'array' | 'primitive' | 'none' => {
str = str.trim(); // Remove leading/trailing whitespace

const jsonCandidate: string | null = getJsonCandidate(str);

// Check if the JSON candidate is a valid object or array
if (jsonCandidate) {
const stack: string[] = [];
for (let i = 0; i < jsonCandidate.length; i++) {
const char = jsonCandidate[i];
if (char === '{' || char === '[') {
stack.push(char);
} else if (char === '}' || char === ']') {
const last = stack.pop();
if ((char === '}' && last !== '{') || (char === ']' && last !== '[')) {
return 'none';
}
} else if (char === '"' && (i === 0 || jsonCandidate[i - 1] !== '\\')) {
// Skip over strings
i++;
while (i < jsonCandidate.length && (jsonCandidate[i] !== '"' || jsonCandidate[i - 1] === '\\')) {
i++;
}
}
}

if (stack.length === 0) {
if (jsonCandidate.startsWith('{') && jsonCandidate.endsWith('}')) {
return 'object';
} else if (jsonCandidate.startsWith('[') && jsonCandidate.endsWith(']')) {
return 'array';
}
}
}

// Check if the entire string is a valid JSON primitive
if (
/^"([^"\\]|\\.)*"$/.test(str) || // String
/^-?\d+(\.\d+)?([eE][+-]?\d+)?$/.test(str) || // Number
/^(true|false|null)$/.test(str)
) {
// Boolean or null
return 'primitive';
}

return 'none';
};

export const extractJsonString = (str: string): string => {
if (containsJsonString(str)) {
return str.substring(str.indexOf('{'), str.lastIndexOf('}') + 1);
export const extractJson = <T = any>(str: string): T => {
str = str.trim(); // Remove leading/trailing whitespace

const jsonCandidate: string | null = getJsonCandidate(str);
const jsonType = identifyJsonTypeInString(str);

if (!jsonCandidate || jsonType === 'none' || jsonType === 'primitive') {
throw new Error(`The string "${str}" does not contain an array or object.`);
}
throw new Error(`The string "${str}" does not contain valid JSON.`);
// Try parsing the detected JSON structure
return JSON.parse(jsonCandidate) as T; // Cast to generic type
};

export const isNullOrUndefined = (object: any): object is null | undefined => {
return object === null || object === undefined;
};

// There's a bug in VS Code where, after a file has been renamed,
Expand Down Expand Up @@ -91,7 +152,7 @@ export const asyncFilter = async <T>(arr: T[], callback: (value: T, index: numbe
export const fileUtils = {
flushFilePaths,
flushFilePath,
extractJsonObject
extractJson
};

export const stripAnsiInJson = (str: string, hasJson: boolean): string => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export class SettingsService {
}

public static isAdvancedSettingEnabledFor(extensionName: string, advancedSetting: AdvancedSettings): boolean {
return vscode.workspace.getConfiguration().get<string>(`${extensionName}.${ADVANCED}.${advancedSetting}`) === TRUE;
const setting = vscode.workspace.getConfiguration().get<string>(`${extensionName}.${ADVANCED}.${advancedSetting}`);
return setting === TRUE;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
* Licensed under the BSD 3-Clause license.
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
import { extractJsonObject, stripAnsiInJson } from '../../../src/helpers/utils';
import { extractJson, stripAnsiInJson } from '../../../src/helpers/utils';

describe('utils tests', () => {
describe('extractJsonObject unit tests', () => {
describe('extractJson unit tests', () => {
const initialValue = {
how: 'does',
it: true,
Expand All @@ -17,34 +17,40 @@ describe('utils tests', () => {
const jsonString = JSON.stringify(initialValue);

it('Should be able to parse a json string.', () => {
const result = extractJsonObject(jsonString);
const result = extractJson(jsonString);
expect(result).toStrictEqual(initialValue);
});
it('Should be able to parse a json string where valid json is embedded within.', () => {
const result = extractJsonObject(`now is the time${jsonString}for all good people`);
const result = extractJson(`now is the time${jsonString}for all good people`);
expect(result).toStrictEqual(initialValue);
});

it('Should throw error if argument is a simple text', () => {
const invalidJson = initialValue.how;
expect(() => extractJsonObject(invalidJson)).toThrow('The string "does" does not contain valid JSON.');
expect(() => extractJson(invalidJson)).toThrow('The string "does" does not contain an array or object.');
});

it('Should throw error if argument is invalid JSON string', () => {
const invalidJson = jsonString.substring(10);
expect(() => extractJsonObject(invalidJson)).toThrow(`The string "${invalidJson}" does not contain valid JSON.`);
expect(() => extractJson(invalidJson)).toThrow(
`The string "${invalidJson}" does not contain an array or object.`
);
});
it('Should throw error not enough curly braces', () => {
const invalidJson = '}';
expect(() => extractJsonObject(invalidJson)).toThrow(`The string "${invalidJson}" does not contain valid JSON.`);
expect(() => extractJson(invalidJson)).toThrow(
`The string "${invalidJson}" does not contain an array or object.`
);
});
it('Should throw error when curly braces not in correct order', () => {
const invalidJson = '}{';
expect(() => extractJsonObject(invalidJson)).toThrow(`The string "${invalidJson}" does not contain valid JSON.`);
expect(() => extractJson(invalidJson)).toThrow(
`The string "${invalidJson}" does not contain an array or object.`
);
});
it('Should throw error if JSON is invalid', () => {
const invalidJson = '{invalid}';
expect(() => extractJsonObject(invalidJson)).toThrow("Expected property name or '}' in JSON at position 1");
expect(() => extractJson(invalidJson)).toThrow("Expected property name or '}' in JSON at position 1");
});
});
describe('stripAnsiInJson', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@
"@salesforce/salesforcedx-apex-replay-debugger": "62.14.1",
"@salesforce/salesforcedx-utils": "62.14.1",
"@salesforce/salesforcedx-utils-vscode": "62.14.1",
"async-lock": "1.0.0",
"async-lock": "1.4.1",
"request-light": "^0.7.0",
"vscode-extension-telemetry": "0.0.17"
},
"devDependencies": {
"@salesforce/salesforcedx-test-utils-vscode": "62.14.1",
"@salesforce/ts-sinon": "1.4.0",
"@types/async-lock": "0.0.20",
"@types/async-lock": "1.4.2",
"@types/chai": "4.3.3",
"@types/mocha": "^5",
"@types/node": "^20.0.0",
Expand Down
Loading
Loading