From fe748dca7f6028232bba27db091fd8de2db27e90 Mon Sep 17 00:00:00 2001 From: mshanemc Date: Fri, 7 Jun 2024 11:43:13 -0500 Subject: [PATCH 1/5] refactor: prefer standardColors --- src/reporters/runReporter.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/reporters/runReporter.ts b/src/reporters/runReporter.ts index 1cdc3bcc..22e41e70 100644 --- a/src/reporters/runReporter.ts +++ b/src/reporters/runReporter.ts @@ -8,7 +8,7 @@ import os from 'node:os'; import { ExecuteAnonymousResponse } from '@salesforce/apex-node'; import { Messages } from '@salesforce/core'; -import { colorError, colorSuccess } from '../utils.js'; +import { StandardColors } from '@salesforce/sf-plugins-core'; import { ExecuteResult } from '../commands/apex/run.js'; Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); @@ -19,8 +19,8 @@ export default class RunReporter { const outputText: string[] = []; if (response.success) { outputText.push( - colorSuccess(messages.getMessage('executeCompileSuccess')), - colorSuccess(messages.getMessage('executeRuntimeSuccess')), + StandardColors.success(messages.getMessage('executeCompileSuccess')), + StandardColors.success(messages.getMessage('executeRuntimeSuccess')), '', response.logs ?? '' ); @@ -31,14 +31,14 @@ export default class RunReporter { const diagnostic = response.diagnostic[0]; if (!response.compiled) { outputText.push( - colorError(`Error: Line: ${diagnostic.lineNumber}, Column: ${diagnostic.columnNumber}`), - colorError(`Error: ${diagnostic.compileProblem}\n`) + StandardColors.error(`Error: Line: ${diagnostic.lineNumber}, Column: ${diagnostic.columnNumber}`), + StandardColors.error(`Error: ${diagnostic.compileProblem}\n`) ); } else { outputText.push( - colorSuccess(messages.getMessage('executeCompileSuccess')), - colorError(`Error: ${diagnostic.exceptionMessage}`), - colorError(`Error: ${diagnostic.exceptionStackTrace}`), + StandardColors.success(messages.getMessage('executeCompileSuccess')), + StandardColors.error(`Error: ${diagnostic.exceptionMessage}`), + StandardColors.error(`Error: ${diagnostic.exceptionStackTrace}`), '', response.logs ?? '' ); From fa3eb91f2812e1a1820107a4ead6a636852bae86 Mon Sep 17 00:00:00 2001 From: mshanemc Date: Wed, 12 Jun 2024 20:21:14 -0500 Subject: [PATCH 2/5] feat: refactor log colorization logic --- messages/flags.md | 7 ++ messages/list.md | 40 -------- messages/report.md | 8 -- messages/runtest.md | 4 - package.json | 9 +- src/commands/apex/get/log.ts | 2 +- src/commands/apex/get/test.ts | 18 +--- src/commands/apex/list/log.ts | 75 ++++++--------- src/commands/apex/run/test.ts | 19 +--- src/commands/apex/tail/log.ts | 7 +- src/flags.ts | 28 ++++++ src/legacyColorization.ts | 78 --------------- src/logColorize.ts | 57 +++++++++++ src/reporters/testReporter.ts | 3 +- src/utils.ts | 39 -------- test/utils.test.ts | 21 ++-- yarn.lock | 175 ++++++++-------------------------- 17 files changed, 189 insertions(+), 401 deletions(-) create mode 100644 messages/flags.md create mode 100644 src/flags.ts delete mode 100644 src/legacyColorization.ts create mode 100644 src/logColorize.ts delete mode 100644 src/utils.ts diff --git a/messages/flags.md b/messages/flags.md new file mode 100644 index 00000000..868d02e7 --- /dev/null +++ b/messages/flags.md @@ -0,0 +1,7 @@ +# flags.result-format.summary + +Format of the test results. + +# flags.code-coverage.summary + +Retrieve code coverage results. diff --git a/messages/list.md b/messages/list.md index 41d6f967..0c771b7f 100644 --- a/messages/list.md +++ b/messages/list.md @@ -21,43 +21,3 @@ To fetch a specific log from your org, obtain the ID from this command's output, # noDebugLogsFound No debug logs found in org - -# appColHeader - -APPLICATION - -# durationColHeader - -DURATION (MS) - -# idColHeader - -ID - -# locationColHeader - -LOCATION - -# sizeColHeader - -SIZE (B) - -# userColHeader - -LOG USER - -# operationColHeader - -OPERATION - -# requestColHeader - -REQUEST - -# timeColHeader - -START TIME - -# statusColHeader - -STATUS diff --git a/messages/report.md b/messages/report.md index 8d38eddc..69009000 100644 --- a/messages/report.md +++ b/messages/report.md @@ -28,14 +28,6 @@ Provide a test run ID to display test results for an enqueued or completed async ID of the test run. -# flags.result-format.summary - -Format of the results. - -# flags.code-coverage.summary - -Retrieve code coverage results. - # flags.output-dir.summary Directory in which to store test result files. diff --git a/messages/runtest.md b/messages/runtest.md index 7128bc90..7b9cde8a 100644 --- a/messages/runtest.md +++ b/messages/runtest.md @@ -34,10 +34,6 @@ NOTE: The testRunCoverage value (JSON and JUnit result formats) is a percentage <%= config.bin %> <%= command.id %> --test-level RunLocalTests --output-dir --target-org me@my.org -# flags.result-format.summary - -Format of the test results. - # flags.class-names.summary Apex test class names to run; default is all classes. diff --git a/package.json b/package.json index ade8b104..2b5615d8 100644 --- a/package.json +++ b/package.json @@ -7,19 +7,16 @@ "dependencies": { "@oclif/core": "^4", "@salesforce/apex-node": "^6.1.2", - "@salesforce/core": "^7.3.10", + "@salesforce/core": "^7.3.12", "@salesforce/kit": "^3.1.2", - "@salesforce/sf-plugins-core": "^10.0.0", - "chalk": "^5.3.0", - "color-convert": "^2.0.1", - "color-name": "^2.0.0" + "@salesforce/sf-plugins-core": "^10.0.1", + "ansis": "^3.2.0" }, "devDependencies": { "@oclif/plugin-command-snapshot": "^5.2.0", "@salesforce/cli-plugins-testkit": "^5.3.9", "@salesforce/dev-scripts": "^10.1.0", "@salesforce/plugin-command-reference": "^3.0.89", - "@types/color-convert": "^2.0.3", "eslint-plugin-sf-plugin": "^1.18.5", "oclif": "^4.12.1", "ts-node": "^10.9.2", diff --git a/src/commands/apex/get/log.ts b/src/commands/apex/get/log.ts index a13322f8..891475cf 100644 --- a/src/commands/apex/get/log.ts +++ b/src/commands/apex/get/log.ts @@ -14,7 +14,7 @@ import { SfCommand, } from '@salesforce/sf-plugins-core'; import { Messages } from '@salesforce/core'; -import { colorLogs } from '../../../utils.js'; +import { colorLogs } from '../../../logColorize.js'; Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-apex', 'get'); diff --git a/src/commands/apex/get/test.ts b/src/commands/apex/get/test.ts index f3f53509..054f4286 100644 --- a/src/commands/apex/get/test.ts +++ b/src/commands/apex/get/test.ts @@ -16,7 +16,7 @@ import { } from '@salesforce/sf-plugins-core'; import { Messages } from '@salesforce/core'; import { RunResult, TestReporter } from '../../../reporters/index.js'; -import { resultFormat } from '../../../utils.js'; +import { codeCoverageFlag, resultFormatFlag } from '../../../flags.js'; Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-apex', 'report'); @@ -40,26 +40,14 @@ export default class Test extends SfCommand { startsWith: '707', length: 'both', }), - 'code-coverage': Flags.boolean({ - aliases: ['codecoverage'], - deprecateAliases: true, - char: 'c', - summary: messages.getMessage('flags.code-coverage.summary'), - }), + 'code-coverage': codeCoverageFlag, 'output-dir': Flags.directory({ aliases: ['outputdir', 'output-directory'], deprecateAliases: true, char: 'd', summary: messages.getMessage('flags.output-dir.summary'), }), - 'result-format': Flags.string({ - deprecateAliases: true, - aliases: ['resultformat'], - char: 'r', - summary: messages.getMessage('flags.result-format.summary'), - options: resultFormat, - default: 'human', - }), + 'result-format': resultFormatFlag, }; public async run(): Promise { diff --git a/src/commands/apex/list/log.ts b/src/commands/apex/list/log.ts index e8eef9ab..4e6b8789 100644 --- a/src/commands/apex/list/log.ts +++ b/src/commands/apex/list/log.ts @@ -18,6 +18,7 @@ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-apex', 'list'); export type LogListResult = LogRecord[]; +type LogForTable = Omit & { DurationMilliseconds: string; User: string }; export default class Log extends SfCommand { public static readonly summary = messages.getMessage('summary'); @@ -35,61 +36,45 @@ export default class Log extends SfCommand { public async run(): Promise { const { flags } = await this.parse(Log); - const conn = flags['target-org'].getConnection(flags['api-version']); - const logService = new LogService(conn); - const logRecords = await logService.getLogRecords(); + const logService = new LogService(flags['target-org'].getConnection(flags['api-version'])); + const logRecords = (await logService.getLogRecords()).map(formatStartTime); if (logRecords.length === 0) { this.log(messages.getMessage('noDebugLogsFound')); return []; } - logRecords.map((logRecord) => { - logRecord.StartTime = this.formatTime(logRecord.StartTime); - }); - if (!flags.json) { // while not required to prevent table output, save a few iterations if only printing json - const cleanLogs = logRecords.map((logRecord) => ({ - app: logRecord.Application, - duration: String(logRecord.DurationMilliseconds), - id: logRecord.Id, - location: logRecord.Location, - size: String(logRecord.LogLength), - user: logRecord.LogUser.Name, - operation: logRecord.Operation, - request: logRecord.Request, - time: logRecord.StartTime, - status: logRecord.Status, - })); - - this.table( - cleanLogs, - { - app: { header: messages.getMessage('appColHeader') }, - duration: { header: messages.getMessage('durationColHeader') }, - id: { header: messages.getMessage('idColHeader') }, - location: { header: messages.getMessage('locationColHeader') }, - size: { header: messages.getMessage('sizeColHeader') }, - user: { header: messages.getMessage('userColHeader') }, - operation: { header: messages.getMessage('operationColHeader') }, - request: { header: messages.getMessage('requestColHeader') }, - time: { header: messages.getMessage('timeColHeader') }, - status: { header: messages.getMessage('statusColHeader') }, - }, - { 'no-truncate': true } - ); + this.table(logRecords.map(formatForTable), tableHeaders, { 'no-truncate': true }); } return logRecords; } - - // eslint-disable-next-line class-methods-use-this - private formatTime(time: string): string { - const milliIndex = time.indexOf('.'); - if (milliIndex !== -1) { - return time.substring(0, milliIndex) + time.substring(milliIndex + 4); - } - return time; - } } + +const formatForTable = (logRecord: LogRecord): LogForTable => ({ + ...logRecord, + DurationMilliseconds: String(logRecord.DurationMilliseconds), + User: logRecord.LogUser.Name, +}); + +const formatStartTime = (lr: LogRecord): LogRecord => ({ ...lr, StartTime: formatTime(lr.StartTime) }); + +const formatTime = (time: string): string => { + const msIndex = time.indexOf('.'); + return msIndex !== -1 ? time.substring(0, msIndex) + time.substring(msIndex + 4) : time; +}; + +const tableHeaders = { + Application: { header: 'Application' }, + DurationMilliseconds: { header: 'Duration (ms)' }, + Id: { header: 'Id' }, + Location: { header: 'Location' }, + LogLength: { header: 'Size (B)' }, + User: { header: 'Log User' }, + Operation: { header: 'Operation' }, + Request: { header: 'Request' }, + StartTime: { header: 'Start Time' }, + Status: { header: 'Status' }, +}; diff --git a/src/commands/apex/run/test.ts b/src/commands/apex/run/test.ts index 8a0eda78..abeda81e 100644 --- a/src/commands/apex/run/test.ts +++ b/src/commands/apex/run/test.ts @@ -17,9 +17,8 @@ import { } from '@salesforce/sf-plugins-core'; import { Messages, SfError } from '@salesforce/core'; import { Duration } from '@salesforce/kit'; - import { RunResult, TestReporter } from '../../../reporters/index.js'; -import { resultFormat } from '../../../utils.js'; +import { codeCoverageFlag, resultFormatFlag } from '../../../flags.js'; Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-apex', 'runtest'); @@ -38,12 +37,7 @@ export default class Test extends SfCommand { 'target-org': requiredOrgFlagWithDeprecations, 'api-version': orgApiVersionFlagWithDeprecations, loglevel, - 'code-coverage': Flags.boolean({ - aliases: ['codecoverage'], - deprecateAliases: true, - char: 'c', - summary: messages.getMessage('flags.code-coverage.summary'), - }), + 'code-coverage': codeCoverageFlag, 'output-dir': Flags.directory({ aliases: ['outputdir', 'output-directory'], deprecateAliases: true, @@ -66,14 +60,7 @@ export default class Test extends SfCommand { description: messages.getMessage('flags.class-names.description'), exclusive: exclusiveTestSpecifiers.filter((specifier) => specifier !== 'class-names'), }), - 'result-format': Flags.string({ - deprecateAliases: true, - aliases: ['resultformat'], - char: 'r', - summary: messages.getMessage('flags.result-format.summary'), - options: resultFormat, - default: 'human', - }), + 'result-format': resultFormatFlag, 'suite-names': arrayWithDeprecation({ deprecateAliases: true, aliases: ['suitenames'], diff --git a/src/commands/apex/tail/log.ts b/src/commands/apex/tail/log.ts index a75ec91c..2d72ecf4 100644 --- a/src/commands/apex/tail/log.ts +++ b/src/commands/apex/tail/log.ts @@ -14,7 +14,7 @@ import { loglevel, } from '@salesforce/sf-plugins-core'; import { Connection, Messages } from '@salesforce/core'; -import { colorizeLog } from '../../../legacyColorization.js'; +import { colorLogs } from '../../../logColorize.js'; Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-apex', 'tail'); @@ -66,10 +66,11 @@ export default class Log extends SfCommand { this.log(messages.getMessage('finishedTailing')); } + // the colorize function used to be async, but not isn't. Preserving the public method signature + // eslint-disable-next-line @typescript-eslint/require-await public async logTailer(fullLog: string): Promise { if (fullLog) { - const output = this.color ? await colorizeLog(fullLog) : fullLog; - this.log(output); + this.log(this.color ? colorLogs(fullLog) : fullLog); } } diff --git a/src/flags.ts b/src/flags.ts new file mode 100644 index 00000000..9032972a --- /dev/null +++ b/src/flags.ts @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023, salesforce.com, inc. + * All rights reserved. + * 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 { Messages } from '@salesforce/core'; +import { Flags } from '@salesforce/sf-plugins-core'; + +Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); +const messages = Messages.loadMessages('@salesforce/plugin-apex', 'flags'); + +export const resultFormatFlag = Flags.string({ + deprecateAliases: true, + aliases: ['resultformat'], + char: 'r', + summary: messages.getMessage('flags.result-format.summary'), + options: ['human', 'tap', 'junit', 'json'] as const, + default: 'human', +}); + +export const codeCoverageFlag = Flags.boolean({ + aliases: ['codecoverage'], + deprecateAliases: true, + char: 'c', + summary: messages.getMessage('flags.code-coverage.summary'), +}); diff --git a/src/legacyColorization.ts b/src/legacyColorization.ts deleted file mode 100644 index 102e38b2..00000000 --- a/src/legacyColorization.ts +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2021, salesforce.com, inc. - * All rights reserved. - * 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 { readFile } from 'node:fs/promises'; -import chalk from 'chalk'; -import convert from 'color-convert'; -import colorName from 'color-name'; -import { Logger } from '@salesforce/core'; - -type ColorMap = Record< - 'CONSTRUCTOR_' | 'EXCEPTION_' | 'FATAL_' | 'METHOD_' | 'SOQL_' | 'USER_' | 'VARIABLE_', - keyof typeof colorName ->; - -const DEFAULT_COLOR_MAP: ColorMap = { - CONSTRUCTOR_: 'magenta', - EXCEPTION_: 'red', - FATAL_: 'red', - METHOD_: 'blue', - SOQL_: 'yellow', - USER_: 'green', - VARIABLE_: 'darkcyan', -}; - -/** - * @description this is a holdover from the toolbelt API, which allows for custom colorization of the logs. - * @param log - full debug log retrieved from an org. - * @returns colorized log - */ -export async function colorizeLog(log: string): Promise { - const logger = await Logger.child('apexLogApi', { tag: 'tail' }); - let colorMap = DEFAULT_COLOR_MAP; - - const localColorMapFile = process.env.SFDX_APEX_LOG_COLOR_MAP; - if (localColorMapFile) { - try { - colorMap = JSON.parse(await readFile(localColorMapFile, 'utf-8')) as ColorMap; - } catch (err) { - logger.warn(`Color registry not found: ${localColorMapFile}`); - } - } - - const logLines = log.split(/\n/g); - if (!logLines || logLines.length < 1) { - logger.warn('colorizeLog unable to split logLines'); - return log; - } - - const line1 = chalk.bold(logLines.shift()); - - return [ - line1, - ...logLines.map((logLine) => { - for (const [key, color] of Object.entries(colorMap)) { - if (logLine.includes(`|${key}`)) { - const hex = convert.keyword.hex(color); - const colorFn = chalk.hex(hex); - - if (typeof colorFn !== 'function') { - logger.warn(`Color ${color} is not supported`); - return logLine; - } - - const count = (logLine.match(/\|/g) ?? []).length; - if (count === 1) { - return colorFn(logLine); - } - const first = logLine.indexOf('|', logLine.indexOf('|') + 1); - return `${colorFn(logLine.substring(0, first))}${logLine.substring(first)}`; - } - } - return logLine; - }), - ].join('\n'); -} diff --git a/src/logColorize.ts b/src/logColorize.ts new file mode 100644 index 00000000..867d2fc1 --- /dev/null +++ b/src/logColorize.ts @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020, salesforce.com, inc. + * All rights reserved. + * 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 { StandardColors } from '@salesforce/sf-plugins-core'; +import ansis from 'ansis'; + +/** these color the entire line if the matching content is found */ +const lineColorMap = [ + ['CONSTRUCTOR_', ansis.magenta], + ['EXCEPTION_', StandardColors.error], + ['FATAL_', StandardColors.error], + ['METHOD_', ansis.blue], + ['SOQL_', StandardColors.warning], + ['USER_', StandardColors.success], + ['VARIABLE_', ansis.bold.cyan], +] as const; + +/** these color matching pieces of content within a line */ +const contentColorMap = [ + [new RegExp(/\b([\w]+\.)+(\w)+\b/g), ansis.blueBright], + [new RegExp(/\b(DEBUG)\b/g), ansis.bold.cyan], + [new RegExp(/\b(HINT|INFO|INFORMATION)\b/g), StandardColors.success], + [new RegExp(/\b(WARNING|WARN)\b/g), StandardColors.warning], + [new RegExp(/\b(ERROR|FAILURE|FAIL)\b/g), StandardColors.error], + [new RegExp(/\b([a-zA-Z.]*Exception)\b/g), StandardColors.error], + [new RegExp(/"[^"]*"/g), StandardColors.error], + [new RegExp(/\b([0-9]+|true|false|null)\b/g), ansis.blueBright], +] as const; + +const colorEntireLineIfMatch = + ([matchThis, colorFn]: readonly [string, ansis.Ansis]) => + (log: string): string => + log.includes(matchThis) ? colorFn(log) : log; + +/** apply a single color to a single log's matching content */ +const colorLogMatchingContent = + ([regex, colorFn]: readonly [RegExp, ansis.Ansis]) => + (log: string): string => + log.replace(regex, (match) => colorFn(match)); + +const [colorFn1, ...colorFns] = [ + ...lineColorMap.map(colorEntireLineIfMatch), + ...contentColorMap.map(colorLogMatchingContent), +]; + +/** one or more functions that have the same signature, returns one composed function that does them all sequentially */ +export const compose = (fn1: (a: R) => R, ...fns: Array<(a: R) => R>): ((a: R) => R) => + fns.reduce((prevFn, nextFn) => (value) => prevFn(nextFn(value)), fn1); + +/** all colorizers in one */ +const allColorizers = compose(colorFn1, ...colorFns); + +export const colorLogs = (log: string): string => allColorizers(log); diff --git a/src/reporters/testReporter.ts b/src/reporters/testReporter.ts index 1f199127..087b7d85 100644 --- a/src/reporters/testReporter.ts +++ b/src/reporters/testReporter.ts @@ -18,9 +18,10 @@ import { import { Ux } from '@salesforce/sf-plugins-core'; import { Connection, Messages } from '@salesforce/core'; import { Duration } from '@salesforce/kit'; -import { FAILURE_EXIT_CODE } from '../utils.js'; import { JsonReporter, RunResult } from './jsonReporter.js'; +const FAILURE_EXIT_CODE = 100; + Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-apex', 'runtest'); diff --git a/src/utils.ts b/src/utils.ts deleted file mode 100644 index adc68fca..00000000 --- a/src/utils.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2020, salesforce.com, inc. - * All rights reserved. - * 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 chalk from 'chalk'; -export const FAILURE_EXIT_CODE = 100; -export const colorSuccess = chalk.bold.green; -export const colorError = chalk.bold.red; - -export const resultFormat = ['human', 'tap', 'junit', 'json']; - -const colorMap = new Map([ - [new RegExp(/\b([\w]+\.)+(\w)+\b/g), chalk.blueBright], - [new RegExp(/\b(DEBUG)\b/g), chalk.bold.cyan], - [new RegExp(/\b(HINT|INFO|INFORMATION)\b/g), chalk.bold.green], - [new RegExp(/\b(WARNING|WARN)\b/g), chalk.bold.yellow], - [new RegExp(/\b(ERROR|FAILURE|FAIL)\b/g), chalk.bold.red], - [new RegExp(/\b([a-zA-Z.]*Exception)\b/g), chalk.bold.red], - [new RegExp(/"[^"]*"/g), chalk.bold.red], - [new RegExp(/\b([0-9]+|true|false|null)\b/g), chalk.blueBright], -]); - -function replace(regex: RegExp, word: string): string { - const color = colorMap.get(regex); - if (!color) { - throw new Error('Error retrieving colors'); - } - return word.replace(regex, (match) => `${color(match)}`); -} - -export function colorLogs(log: string): string { - for (const c of colorMap.keys()) { - log = replace(c, log); - } - return log; -} diff --git a/test/utils.test.ts b/test/utils.test.ts index 0272ff4b..d493d594 100644 --- a/test/utils.test.ts +++ b/test/utils.test.ts @@ -4,19 +4,20 @@ * 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 { expect } from 'chai'; -import { colorLogs } from '../src/utils.js'; +import { expect, config } from 'chai'; +import { colorLogs } from '../src/logColorize.js'; +config.truncateThreshold = 0; -describe('Colorize Logs', () => { - it('should color time/date format correctly', async () => { +describe.only('Colorize Logs', () => { + it('should color time/date format correctly', () => { const testData = '12:47:29.584'; const coloredData = colorLogs(testData); expect(coloredData).to.eql( - '\u001b[94m12\u001b[39m:\u001b[94m47\u001b[39m:\u001b[94m29.\u001b[94m584\u001b[39m\u001b[39m' + '\u001b[94m12\u001b[39m:\u001b[94m47\u001b[39m:\u001b[94m29\u001b[39m.\u001b[94m584\u001b[39m' ); }); - it('should color exception message correctly', async () => { + it('should color exception message correctly', () => { const testData = '$CalloutInTestmethodException: Methods defined as TestMethod do not support Web service callouts"'; const coloredData = colorLogs(testData); @@ -25,25 +26,25 @@ describe('Colorize Logs', () => { ); }); - it('should color debug message correctly', async () => { + it('should color debug message correctly', () => { const testData = 'SYSTEM,DEBUG;VALIDATION'; const coloredData = colorLogs(testData); expect(coloredData).to.eql('SYSTEM,\u001b[1m\u001b[36mDEBUG\u001b[39m\u001b[22m;VALIDATION'); }); - it('should color basic strings correctly', async () => { + it('should color basic strings correctly', () => { const testData = 'testdevhub@ria.com'; const coloredData = colorLogs(testData); expect(coloredData).to.eql('testdevhub@\u001b[94mria.com\u001b[39m'); }); - it('should color info text correctly', async () => { + it('should color info text correctly', () => { const testData = 'APEX_PROFILING,INFO;'; const coloredData = colorLogs(testData); expect(coloredData).to.eql('APEX_PROFILING,\u001b[1m\u001b[32mINFO\u001b[39m\u001b[22m;'); }); - it('should color warn text correctly', async () => { + it('should color warn text correctly', () => { const testData = 'APEX_PROFILING,WARN;'; const coloredData = colorLogs(testData); expect(coloredData).to.eql('APEX_PROFILING,\u001b[1m\u001b[33mWARN\u001b[39m\u001b[22m;'); diff --git a/yarn.lock b/yarn.lock index b7c054c0..9f87647e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1639,22 +1639,22 @@ wordwrap "^1.0.0" wrap-ansi "^7.0.0" -"@oclif/core@^4", "@oclif/core@^4.0.0-beta.12", "@oclif/core@^4.0.0-beta.13": - version "4.0.2" - resolved "https://registry.yarnpkg.com/@oclif/core/-/core-4.0.2.tgz#e6b15c4397e52b31fde9b7695f537c20b56634ed" - integrity sha512-0r+JwE1FbVlEYNQlLonMULnZb6rKR0RqT8eUgKeJTb5cILhsKUjlZf2NLIX4GP3SZrK8POwGGLcztmj42hZYiw== +"@oclif/core@^4", "@oclif/core@^4.0.0-beta.12", "@oclif/core@^4.0.0-beta.13", "@oclif/core@^4.0.3": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@oclif/core/-/core-4.0.6.tgz#05958a928591567b7fe90638e0ee8df9e07eb3ff" + integrity sha512-z/4YUVQsf2pHsXRze5etbmvAYDhoUhIzpM6oJGEdsdWfvQJ6YQBogH7TdX/ItuGda6+vpfXg/4U1CtPexSF+bA== dependencies: ansi-escapes "^4.3.2" ansis "^3.1.1" clean-stack "^3.0.1" cli-spinners "^2.9.2" - cosmiconfig "^9.0.0" debug "^4.3.5" ejs "^3.1.10" get-package-type "^0.1.0" globby "^11.1.0" indent-string "^4.0.0" is-wsl "^2.2.0" + lilconfig "^3.1.2" minimatch "^9.0.4" string-width "^4.2.3" supports-color "^8" @@ -1742,17 +1742,18 @@ strip-ansi "6.0.1" ts-retry-promise "^0.8.1" -"@salesforce/core@^7.3.10": - version "7.3.10" - resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-7.3.10.tgz#83da85c4e93ca625e2c13118aad9c1df2931bc0f" - integrity sha512-kEKoqkmhWNoiucAE3Ylv6FpC4iVgk4aE0dmcwSmNrMjxSbtjQJGUybprfO/itrLJv+56eM7/4FARQQ2gDbRzQQ== +"@salesforce/core@^7.3.10", "@salesforce/core@^7.3.12", "@salesforce/core@^7.3.9": + version "7.3.12" + resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-7.3.12.tgz#9138980db21566c467f35afe9192f33bf77f160c" + integrity sha512-a53KYv2xaJpmFlN4haI7ewaMpRqdRwaqbm11wLn0il6+LNR1/2zkRdqE3opdTW6aXNvVecNu0YQj5/u3Uz3oPw== dependencies: "@jsforce/jsforce-node" "^3.2.0" - "@salesforce/kit" "^3.1.1" + "@salesforce/kit" "^3.1.2" "@salesforce/schemas" "^1.9.0" "@salesforce/ts-types" "^2.0.9" ajv "^8.15.0" change-case "^4.1.2" + fast-levenshtein "^3.0.0" faye "^1.4.0" form-data "^4.0.0" js2xmlparser "^4.0.1" @@ -1765,29 +1766,6 @@ semver "^7.6.2" ts-retry-promise "^0.8.1" -"@salesforce/core@^7.3.9": - version "7.3.9" - resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-7.3.9.tgz#8abe2b3e2393989d11e92b7a6b96043fc9d5b9c8" - integrity sha512-eJqDiA5b7wU50Ee/xjmGzSnHrNVJ8S77B7enfX30gm7gxU3i3M3QeBdiV6XAOPLSIL96DseofP6Tv6c+rljlKA== - dependencies: - "@jsforce/jsforce-node" "^3.2.0" - "@salesforce/kit" "^3.1.1" - "@salesforce/schemas" "^1.9.0" - "@salesforce/ts-types" "^2.0.9" - ajv "^8.13.0" - change-case "^4.1.2" - faye "^1.4.0" - form-data "^4.0.0" - js2xmlparser "^4.0.1" - jsonwebtoken "9.0.2" - jszip "3.10.1" - pino "^8.21.0" - pino-abstract-transport "^1.1.0" - pino-pretty "^10.3.1" - proper-lockfile "^4.1.2" - semver "^7.6.2" - ts-retry-promise "^0.7.1" - "@salesforce/dev-config@^4.1.0": version "4.1.0" resolved "https://registry.yarnpkg.com/@salesforce/dev-config/-/dev-config-4.1.0.tgz#e529576466d074e7a5f1441236510fef123da01e" @@ -1825,13 +1803,13 @@ typescript "^5.4.3" wireit "^0.14.4" -"@salesforce/kit@^3.1.1", "@salesforce/kit@^3.1.2": - version "3.1.2" - resolved "https://registry.yarnpkg.com/@salesforce/kit/-/kit-3.1.2.tgz#270741c54c70969df19ef17f8979b4ef1fa664b2" - integrity sha512-si+ddvZDgx9q5czxAANuK5xhz3pv+KGspQy1wyia/7HDPKadA0QZkLTzUnO1Ju4Mux32CNHEb2y9lw9jj+eVTA== +"@salesforce/kit@^3.1.1", "@salesforce/kit@^3.1.2", "@salesforce/kit@^3.1.3": + version "3.1.3" + resolved "https://registry.yarnpkg.com/@salesforce/kit/-/kit-3.1.3.tgz#b2d3f2f4700cdd9b70e1c559c7b68d2a595ad75b" + integrity sha512-uGiG8wOyPciba63WFPazs7nJFBPdOkjVTot8h3Zt+K6kh4+8XgfHI9lOa4NVXtZpuOnBI4Zklbcu3R3V1mZYsg== dependencies: "@salesforce/ts-types" "^2.0.9" - tslib "^2.6.2" + tslib "^2.6.3" "@salesforce/plugin-command-reference@^3.0.89": version "3.0.89" @@ -1857,18 +1835,18 @@ resolved "https://registry.yarnpkg.com/@salesforce/schemas/-/schemas-1.9.0.tgz#ba477a112653a20b4edcf989c61c57bdff9aa3ca" integrity sha512-LiN37zG5ODT6z70sL1fxF7BQwtCX9JOWofSU8iliSNIM+WDEeinnoFtVqPInRSNt8I0RiJxIKCrqstsmQRBNvA== -"@salesforce/sf-plugins-core@^10.0.0": - version "10.0.0" - resolved "https://registry.yarnpkg.com/@salesforce/sf-plugins-core/-/sf-plugins-core-10.0.0.tgz#712b38cf101ab95866e757c2738ffc3ddd27ded5" - integrity sha512-Y18aDrz376Ekza45nfCjpyiI+np1oY9Cc7DxNAYiP37c0lstTajVsgz6wvDvt6p6QGEX//nnqcz/NaMlry/INw== +"@salesforce/sf-plugins-core@^10.0.1": + version "10.0.1" + resolved "https://registry.yarnpkg.com/@salesforce/sf-plugins-core/-/sf-plugins-core-10.0.1.tgz#8df8e3b7a10f8ba75906c5d58eb3a7df32e42eb3" + integrity sha512-FsbZKshTgyHYO1KNuEuNGhzLj5diuh7lMElNkT4xfmwGjciDEIBtZf/aMAdN9AYpIj/TkAvi7Xnxs1gMHPOGNQ== dependencies: "@inquirer/confirm" "^3.1.9" "@inquirer/password" "^2.1.9" - "@oclif/core" "^4" - "@salesforce/core" "^7.3.10" - "@salesforce/kit" "^3.1.2" + "@oclif/core" "^4.0.3" + "@salesforce/core" "^7.3.12" + "@salesforce/kit" "^3.1.3" "@salesforce/ts-types" "^2.0.9" - ansis "^3.1.1" + ansis "^3.2.0" cli-progress "^3.12.0" natural-orderby "^3.0.2" slice-ansi "^7.1.0" @@ -2847,18 +2825,6 @@ dependencies: "@types/node" "*" -"@types/color-convert@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@types/color-convert/-/color-convert-2.0.3.tgz#e93f5c991eda87a945058b47044f5f0008b0dce9" - integrity sha512-2Q6wzrNiuEvYxVQqhh7sXM2mhIhvZR/Paq4FdsQkOMgWsCIkKvSGj8Le1/XalulrmgOzPMqNa0ix+ePY4hTrfg== - dependencies: - "@types/color-name" "*" - -"@types/color-name@*": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.3.tgz#c488ac2e519c9795faa0d54e8156d54e66adc4e6" - integrity sha512-87W6MJCKZYDhLAx/J1ikW8niMvmGRyY+rpUxWpL1cO7F8Uu5CHuQoFv+R0/L5pgNdW4jTyda42kv60uwVIPjLw== - "@types/glob@~7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" @@ -3130,7 +3096,7 @@ ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.11.0, ajv@^8.13.0, ajv@^8.15.0: +ajv@^8.11.0, ajv@^8.15.0: version "8.16.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.16.0.tgz#22e2a92b94f005f7e0f9c9d39652ef0b8f6f0cb4" integrity sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw== @@ -3736,11 +3702,6 @@ color-name@^1.0.0, color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -color-name@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-2.0.0.tgz#03ff6b1b5aec9bb3cf1ed82400c2790dfcd01d2d" - integrity sha512-SbtvAMWvASO5TE2QP07jHBMXKafgdZz8Vrsrn96fiL+O92/FN/PLARzUW5sKt013fjAprK2d2iCn2hk2Xb5oow== - color-string@^1.9.0: version "1.9.1" resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" @@ -3872,16 +3833,6 @@ cosmiconfig@^8.0.0, cosmiconfig@^8.3.6: parse-json "^5.2.0" path-type "^4.0.0" -cosmiconfig@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-9.0.0.tgz#34c3fc58287b915f3ae905ab6dc3de258b55ad9d" - integrity sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg== - dependencies: - env-paths "^2.2.1" - import-fresh "^3.3.0" - js-yaml "^4.1.0" - parse-json "^5.2.0" - create-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" @@ -4158,11 +4109,6 @@ entities@^4.2.0, entities@^4.5.0: resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== -env-paths@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" - integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== - error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" @@ -4911,18 +4857,7 @@ glob@8.1.0, glob@^8.0.3: minimatch "^5.0.1" once "^1.3.0" -glob@^10.3.10: - version "10.3.10" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b" - integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== - dependencies: - foreground-child "^3.1.0" - jackspeak "^2.3.5" - minimatch "^9.0.1" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" - path-scurry "^1.10.1" - -glob@^10.3.16: +glob@^10.3.10, glob@^10.3.16: version "10.4.1" resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.1.tgz#0cfb01ab6a6b438177bfe6a58e2576f6efe909c2" integrity sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw== @@ -5591,15 +5526,7 @@ istanbul-lib-source-maps@^4.0.0: istanbul-lib-coverage "^3.0.0" source-map "^0.6.1" -istanbul-reports@^3.0.2: - version "3.1.6" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.6.tgz#2544bcab4768154281a2f0870471902704ccaa1a" - integrity sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg== - dependencies: - html-escaper "^2.0.0" - istanbul-lib-report "^3.0.0" - -istanbul-reports@^3.1.7: +istanbul-reports@^3.0.2, istanbul-reports@^3.1.7: version "3.1.7" resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== @@ -5607,15 +5534,6 @@ istanbul-reports@^3.1.7: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jackspeak@^2.3.5: - version "2.3.6" - resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" - integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== - dependencies: - "@isaacs/cliui" "^8.0.2" - optionalDependencies: - "@pkgjs/parseargs" "^0.11.0" - jackspeak@^3.1.2: version "3.4.0" resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.0.tgz#a75763ff36ad778ede6a156d8ee8b124de445b4a" @@ -5857,6 +5775,11 @@ lie@~3.3.0: dependencies: immediate "~3.0.5" +lilconfig@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.2.tgz#e4a7c3cb549e3a606c8dcc32e5ae1005e62c05cb" + integrity sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow== + lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" @@ -6024,7 +5947,7 @@ lowercase-keys@^3.0.0: resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2" integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ== -lru-cache@^10.0.1, lru-cache@^10.2.0, "lru-cache@^9.1.1 || ^10.0.0": +lru-cache@^10.0.1, lru-cache@^10.2.0: version "10.2.2" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.2.tgz#48206bc114c1252940c41b25b41af5b545aca878" integrity sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ== @@ -6192,7 +6115,7 @@ minimatch@^5.0.1: dependencies: brace-expansion "^2.0.1" -minimatch@^9.0.1, minimatch@^9.0.3, minimatch@^9.0.4: +minimatch@^9.0.3, minimatch@^9.0.4: version "9.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== @@ -6213,12 +6136,7 @@ minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0": - version "7.0.4" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" - integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== - -minipass@^7.1.2: +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== @@ -6689,14 +6607,6 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-scurry@^1.10.1: - version "1.10.1" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698" - integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ== - dependencies: - lru-cache "^9.1.1 || ^10.0.0" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" - path-scurry@^1.11.1: version "1.11.1" resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" @@ -6747,7 +6657,7 @@ picomatch@^3.0.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-3.0.1.tgz#817033161def55ec9638567a2f3bbc876b3e7516" integrity sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag== -pino-abstract-transport@^1.0.0, pino-abstract-transport@^1.1.0, pino-abstract-transport@^1.2.0: +pino-abstract-transport@^1.0.0, pino-abstract-transport@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz#97f9f2631931e242da531b5c66d3079c12c9d1b5" integrity sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q== @@ -7748,11 +7658,6 @@ ts-node@^10.8.1, ts-node@^10.9.2: v8-compile-cache-lib "^3.0.1" yn "3.1.1" -ts-retry-promise@^0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/ts-retry-promise/-/ts-retry-promise-0.7.1.tgz#176d6eee6415f07b6c7c286d3657355e284a6906" - integrity sha512-NhHOCZ2AQORvH42hOPO5UZxShlcuiRtm7P2jIq2L2RY3PBxw2mLnUsEdHrIslVBFya1v5aZmrR55lWkzo13LrQ== - ts-retry-promise@^0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/ts-retry-promise/-/ts-retry-promise-0.8.1.tgz#ba90eb07cb03677fcbf78fe38e94c9183927e154" @@ -7773,10 +7678,10 @@ tslib@^1.11.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.3, tslib@^2.3.1, tslib@^2.5.0, tslib@^2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" - integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== +tslib@^2.0.3, tslib@^2.3.1, tslib@^2.5.0, tslib@^2.6.2, tslib@^2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" + integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== tunnel-agent@*, tunnel-agent@^0.6.0: version "0.6.0" From 4e519d1256e44c74ba9db72f628c3feeaaacfa8a Mon Sep 17 00:00:00 2001 From: mshanemc Date: Thu, 13 Jun 2024 13:29:16 -0500 Subject: [PATCH 3/5] test: resolve ut failures --- src/commands/apex/list/log.ts | 2 +- src/logColorize.ts | 45 +++++++-------- test/commands/apex/get/log.test.ts | 24 +++++--- test/commands/apex/list/log.test.ts | 87 +++++++++++------------------ test/utils.test.ts | 16 +++--- 5 files changed, 80 insertions(+), 94 deletions(-) diff --git a/src/commands/apex/list/log.ts b/src/commands/apex/list/log.ts index 4e6b8789..dc1a1a53 100644 --- a/src/commands/apex/list/log.ts +++ b/src/commands/apex/list/log.ts @@ -59,7 +59,7 @@ const formatForTable = (logRecord: LogRecord): LogForTable => ({ User: logRecord.LogUser.Name, }); -const formatStartTime = (lr: LogRecord): LogRecord => ({ ...lr, StartTime: formatTime(lr.StartTime) }); +export const formatStartTime = (lr: LogRecord): LogRecord => ({ ...lr, StartTime: formatTime(lr.StartTime) }); const formatTime = (time: string): string => { const msIndex = time.indexOf('.'); diff --git a/src/logColorize.ts b/src/logColorize.ts index 867d2fc1..0432d8a4 100644 --- a/src/logColorize.ts +++ b/src/logColorize.ts @@ -8,22 +8,16 @@ import { StandardColors } from '@salesforce/sf-plugins-core'; import ansis from 'ansis'; -/** these color the entire line if the matching content is found */ -const lineColorMap = [ - ['CONSTRUCTOR_', ansis.magenta], - ['EXCEPTION_', StandardColors.error], - ['FATAL_', StandardColors.error], - ['METHOD_', ansis.blue], - ['SOQL_', StandardColors.warning], - ['USER_', StandardColors.success], - ['VARIABLE_', ansis.bold.cyan], -] as const; - -/** these color matching pieces of content within a line */ +/** these color matching pieces of content within a log line */ const contentColorMap = [ + [new RegExp(/\|VARIABLE_\w*\|/g), ansis.bold.cyan], + [new RegExp(/\|METHOD_\w*\|/g), ansis.blue], + [new RegExp(/\|SOQL_\w*\|/g), StandardColors.warning], + [new RegExp(/\|CONSTRUCTOR_\w*\|/g), ansis.magenta], + [new RegExp(/\|USER\w*\|/g), StandardColors.success], [new RegExp(/\b([\w]+\.)+(\w)+\b/g), ansis.blueBright], [new RegExp(/\b(DEBUG)\b/g), ansis.bold.cyan], - [new RegExp(/\b(HINT|INFO|INFORMATION)\b/g), StandardColors.success], + [new RegExp(/\b(HINT|INFO|INFORMATION|EXCEPTION_\w*|FATAL_\w*)\b/g), StandardColors.success], [new RegExp(/\b(WARNING|WARN)\b/g), StandardColors.warning], [new RegExp(/\b(ERROR|FAILURE|FAIL)\b/g), StandardColors.error], [new RegExp(/\b([a-zA-Z.]*Exception)\b/g), StandardColors.error], @@ -31,27 +25,28 @@ const contentColorMap = [ [new RegExp(/\b([0-9]+|true|false|null)\b/g), ansis.blueBright], ] as const; -const colorEntireLineIfMatch = - ([matchThis, colorFn]: readonly [string, ansis.Ansis]) => - (log: string): string => - log.includes(matchThis) ? colorFn(log) : log; - /** apply a single color to a single log's matching content */ const colorLogMatchingContent = ([regex, colorFn]: readonly [RegExp, ansis.Ansis]) => (log: string): string => log.replace(regex, (match) => colorFn(match)); -const [colorFn1, ...colorFns] = [ - ...lineColorMap.map(colorEntireLineIfMatch), - ...contentColorMap.map(colorLogMatchingContent), -]; +const [colorFn1, ...colorFns] = [...contentColorMap.map(colorLogMatchingContent)]; /** one or more functions that have the same signature, returns one composed function that does them all sequentially */ export const compose = (fn1: (a: R) => R, ...fns: Array<(a: R) => R>): ((a: R) => R) => fns.reduce((prevFn, nextFn) => (value) => prevFn(nextFn(value)), fn1); /** all colorizers in one */ -const allColorizers = compose(colorFn1, ...colorFns); - -export const colorLogs = (log: string): string => allColorizers(log); +export const colorize = compose(colorFn1, ...colorFns); + +export const colorLogs = (log: string): string => { + const [head, ...tail] = log.split('\n'); + // the first line is bolded and not otherwise styles + return tail.length === 0 + ? ansis.bold(head) + : [ + ansis.bold(head), // the first line is bolded and not otherwise styles + colorize(tail.join('\n')), + ].join('\n'); +}; diff --git a/test/commands/apex/get/log.test.ts b/test/commands/apex/get/log.test.ts index 9725055f..830acad1 100644 --- a/test/commands/apex/get/log.test.ts +++ b/test/commands/apex/get/log.test.ts @@ -11,7 +11,11 @@ import { LogService } from '@salesforce/apex-node'; import { expect } from 'chai'; import { SfCommand } from '@salesforce/sf-plugins-core'; import { Org } from '@salesforce/core'; -import Log from '../../../../src/commands/apex/get/log.js'; +import ansis from 'ansis'; +import Log, { LogGetResult } from '../../../../src/commands/apex/get/log.js'; + +const strip = new ansis.Ansis().strip; +const logStripper = (log: LogGetResult[number]) => (typeof log === 'string' ? strip(log) : { log: strip(log.log) }); describe('apex:log:get', () => { let config: Config; @@ -36,6 +40,12 @@ describe('apex:log:get', () => { } }); + it('verify log stripper', () => { + expect(strip('\u001b[1mmyLog\u001b[22m\n')).to.equal('myLog\n'); + expect(logStripper('\u001b[1mmyLog\u001b[22m\n')).to.equal('myLog\n'); + expect(logStripper({ log: '\u001b[1mmyLog\u001b[22m\n' })).to.deep.equal({ log: 'myLog\n' }); + }); + it('0 logs to get', async () => { sandbox.stub(LogService.prototype, 'getLogs').resolves([]); const result = await Log.run([], config); @@ -59,17 +69,17 @@ describe('apex:log:get', () => { it('multiple results', async () => { sandbox.stub(LogService.prototype, 'getLogs').resolves([{ log: 'myLog' }, { log: 'myLog2' }]); - const result = await new Log([], config).run(); + const result = (await new Log([], config).run()).map(logStripper); expect(result).to.deep.equal([{ log: 'myLog' }, { log: 'myLog2' }]); - expect(logStub.firstCall.args[0]).to.equal('myLog'); - expect(logStub.secondCall.args[0]).to.equal('myLog2'); + expect(logStripper(logStub.firstCall.args[0] as string)).to.equal('myLog'); + expect(logStripper(logStub.secondCall.args[0] as string)).to.equal('myLog2'); }); it('multiple results --json', async () => { sandbox.stub(LogService.prototype, 'getLogs').resolves([{ log: 'myLog' }, { log: 'myLog2' }]); - const result = await new Log(['--json'], config).run(); + const result = (await new Log(['--json'], config).run()).map(logStripper); expect(result).to.deep.equal([{ log: 'myLog' }, { log: 'myLog2' }]); - expect(logStub.firstCall.args[0]).to.equal('myLog'); - expect(logStub.secondCall.args[0]).to.equal('myLog2'); + expect(logStripper(logStub.firstCall.args[0] as string)).to.equal('myLog'); + expect(logStripper(logStub.secondCall.args[0] as string)).to.equal('myLog2'); }); }); diff --git a/test/commands/apex/list/log.test.ts b/test/commands/apex/list/log.test.ts index 91a23e72..5ab14c75 100644 --- a/test/commands/apex/list/log.test.ts +++ b/test/commands/apex/list/log.test.ts @@ -10,7 +10,7 @@ import sinon from 'sinon'; import { SfCommand } from '@salesforce/sf-plugins-core'; import { Org } from '@salesforce/core'; import { expect } from 'chai'; -import Log from '../../../../src/commands/apex/list/log.js'; +import Log, { formatStartTime } from '../../../../src/commands/apex/list/log.js'; const rawLogResult = { status: 0, @@ -50,7 +50,7 @@ const rawLogResult = { const logRecords = [rawLogResult.result[0], rawLogResult.result[1]]; -describe('apex:log:list', () => { +describe.only('apex:log:list', () => { let config: Config; let sandbox: sinon.SinonSandbox; let logStub: sinon.SinonStub; @@ -83,66 +83,47 @@ describe('apex:log:list', () => { }); it('will list multiple logs', async () => { - sandbox.stub(LogService.prototype, 'getLogRecords').resolves(logRecords); - const result = await new Log([], config).run(); - expect(result).to.deep.equal(logRecords); + sandbox.stub(LogService.prototype, 'getLogRecords').resolves(structuredClone(logRecords)); + await new Log([], config).run(); expect(tableStub.firstCall.args[0]).to.deep.equal([ { - app: 'Unknown', - duration: '75', - id: '07L5tgg0005PGdTnEAL', - location: 'Unknown', - operation: 'API', - request: 'API', - size: '450', - status: 'Assertion Failed', - time: '2020-10-13T05:39:43+0000', - user: 'Test User', + Application: 'Unknown', + DurationMilliseconds: '75', + Id: '07L5tgg0005PGdTnEAL', + Location: 'Unknown', + Operation: 'API', + Request: 'API', + LogLength: 450, + Status: 'Assertion Failed', + StartTime: '2020-10-13T05:39:43+0000', + User: 'Test User', + LogUser: { + Name: 'Test User', + attributes: {}, + }, }, { - app: 'Unknown', - duration: '75', - id: '07L5tgg0005PGdTnFPL', - location: 'Unknown', - operation: 'API', - request: 'API', - size: '450', - status: 'Successful', - time: '2020-10-13T05:39:43+0000', - user: 'Test User2', + Application: 'Unknown', + DurationMilliseconds: '75', + Id: '07L5tgg0005PGdTnFPL', + Location: 'Unknown', + Operation: 'API', + Request: 'API', + LogLength: 450, + Status: 'Successful', + StartTime: '2020-10-13T05:39:43+0000', + User: 'Test User2', + LogUser: { + Name: 'Test User2', + attributes: {}, + }, }, ]); }); it('will list multiple logs --json', async () => { sandbox.stub(LogService.prototype, 'getLogRecords').resolves(logRecords); - const result = await new Log([], config).run(); - expect(result).to.deep.equal(logRecords); - expect(tableStub.firstCall.args[0]).to.deep.equal([ - { - app: 'Unknown', - duration: '75', - id: '07L5tgg0005PGdTnEAL', - location: 'Unknown', - operation: 'API', - request: 'API', - size: '450', - status: 'Assertion Failed', - time: '2020-10-13T05:39:43+0000', - user: 'Test User', - }, - { - app: 'Unknown', - duration: '75', - id: '07L5tgg0005PGdTnFPL', - location: 'Unknown', - operation: 'API', - request: 'API', - size: '450', - status: 'Successful', - time: '2020-10-13T05:39:43+0000', - user: 'Test User2', - }, - ]); + const result = await new Log(['--json'], config).run(); + expect(result).to.deep.equal(logRecords.map(formatStartTime)); }); }); diff --git a/test/utils.test.ts b/test/utils.test.ts index d493d594..7afc2bbf 100644 --- a/test/utils.test.ts +++ b/test/utils.test.ts @@ -5,13 +5,13 @@ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ import { expect, config } from 'chai'; -import { colorLogs } from '../src/logColorize.js'; +import { colorize } from '../src/logColorize.js'; config.truncateThreshold = 0; -describe.only('Colorize Logs', () => { +describe('Colorize Logs', () => { it('should color time/date format correctly', () => { const testData = '12:47:29.584'; - const coloredData = colorLogs(testData); + const coloredData = colorize(testData); expect(coloredData).to.eql( '\u001b[94m12\u001b[39m:\u001b[94m47\u001b[39m:\u001b[94m29\u001b[39m.\u001b[94m584\u001b[39m' ); @@ -20,7 +20,7 @@ describe.only('Colorize Logs', () => { it('should color exception message correctly', () => { const testData = '$CalloutInTestmethodException: Methods defined as TestMethod do not support Web service callouts"'; - const coloredData = colorLogs(testData); + const coloredData = colorize(testData); expect(coloredData).to.eql( '$\u001b[1m\u001b[31mCalloutInTestmethodException\u001b[39m\u001b[22m: Methods defined as TestMethod do not support Web service callouts"' ); @@ -28,25 +28,25 @@ describe.only('Colorize Logs', () => { it('should color debug message correctly', () => { const testData = 'SYSTEM,DEBUG;VALIDATION'; - const coloredData = colorLogs(testData); + const coloredData = colorize(testData); expect(coloredData).to.eql('SYSTEM,\u001b[1m\u001b[36mDEBUG\u001b[39m\u001b[22m;VALIDATION'); }); it('should color basic strings correctly', () => { const testData = 'testdevhub@ria.com'; - const coloredData = colorLogs(testData); + const coloredData = colorize(testData); expect(coloredData).to.eql('testdevhub@\u001b[94mria.com\u001b[39m'); }); it('should color info text correctly', () => { const testData = 'APEX_PROFILING,INFO;'; - const coloredData = colorLogs(testData); + const coloredData = colorize(testData); expect(coloredData).to.eql('APEX_PROFILING,\u001b[1m\u001b[32mINFO\u001b[39m\u001b[22m;'); }); it('should color warn text correctly', () => { const testData = 'APEX_PROFILING,WARN;'; - const coloredData = colorLogs(testData); + const coloredData = colorize(testData); expect(coloredData).to.eql('APEX_PROFILING,\u001b[1m\u001b[33mWARN\u001b[39m\u001b[22m;'); }); }); From bed5356aec5b7e179125ce2a115a2f22406e607b Mon Sep 17 00:00:00 2001 From: mshanemc Date: Thu, 13 Jun 2024 13:44:17 -0500 Subject: [PATCH 4/5] chore: remove wip test changes --- test/commands/apex/get/log.test.ts | 6 ------ test/commands/apex/list/log.test.ts | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/test/commands/apex/get/log.test.ts b/test/commands/apex/get/log.test.ts index 830acad1..59f126a1 100644 --- a/test/commands/apex/get/log.test.ts +++ b/test/commands/apex/get/log.test.ts @@ -40,12 +40,6 @@ describe('apex:log:get', () => { } }); - it('verify log stripper', () => { - expect(strip('\u001b[1mmyLog\u001b[22m\n')).to.equal('myLog\n'); - expect(logStripper('\u001b[1mmyLog\u001b[22m\n')).to.equal('myLog\n'); - expect(logStripper({ log: '\u001b[1mmyLog\u001b[22m\n' })).to.deep.equal({ log: 'myLog\n' }); - }); - it('0 logs to get', async () => { sandbox.stub(LogService.prototype, 'getLogs').resolves([]); const result = await Log.run([], config); diff --git a/test/commands/apex/list/log.test.ts b/test/commands/apex/list/log.test.ts index 5ab14c75..55843599 100644 --- a/test/commands/apex/list/log.test.ts +++ b/test/commands/apex/list/log.test.ts @@ -50,7 +50,7 @@ const rawLogResult = { const logRecords = [rawLogResult.result[0], rawLogResult.result[1]]; -describe.only('apex:log:list', () => { +describe('apex:log:list', () => { let config: Config; let sandbox: sinon.SinonSandbox; let logStub: sinon.SinonStub; From 8d3682d5f6a8a0071dbaacbef6838c8c72445f7d Mon Sep 17 00:00:00 2001 From: Cristian Dominguez <6853656+cristiand391@users.noreply.github.com> Date: Tue, 18 Jun 2024 12:58:37 -0300 Subject: [PATCH 5/5] fix(nuts): case-sensitive regex (#492) --- test/commands/apex/loggingCommands.nut.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/commands/apex/loggingCommands.nut.ts b/test/commands/apex/loggingCommands.nut.ts index d78f96ee..adf68898 100644 --- a/test/commands/apex/loggingCommands.nut.ts +++ b/test/commands/apex/loggingCommands.nut.ts @@ -85,7 +85,7 @@ describe('apex log *', () => { it('will list the debug logs', async () => { const result = execCmd('apex:list:log', { ensureExitCode: 0 }).shellOutput.stdout; expect(result).to.match( - / APPLICATION DURATION \(MS\) ID\s+LOCATION\s+SIZE \(B\) LOG USER\s+OPERATION REQUEST START TIME\s+STATUS / + / Application Duration \(ms\) Id\s+Location\s+Size \(B\) Log User\s+Operation Request Start Time\s+Status / ); expect(result).to.match(/User User Api\s+Api\s+\d{4}-\d{2}-.* Success /); });