From e766c8669f4d0221de89b6346bbe6be2e083a647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?lz=2Esir=CE=94rthurmoney=28=29?= <95722332+sirarthurmoney@users.noreply.github.com> Date: Fri, 9 Feb 2024 16:49:55 -0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=97=9E=EF=B8=8F=20Adding=20in=20Default?= =?UTF-8?q?=20Colors=20to=20print=20outs=20(#381)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changeset/empty-lamps-marry.md | 7 + packages/io-devtools/package.json | 1 + packages/io-devtools/src/stdio/printer.ts | 67 +++++++-- .../src/tasks/oapp/peers.get.ts | 8 +- pnpm-lock.yaml | 3 + .../__snapshots__/config.check.test.ts.snap | 133 +++++++++++------- .../test/task/oapp/config.check.test.ts | 39 ++--- 7 files changed, 174 insertions(+), 84 deletions(-) create mode 100644 .changeset/empty-lamps-marry.md diff --git a/.changeset/empty-lamps-marry.md b/.changeset/empty-lamps-marry.md new file mode 100644 index 000000000..f149f476d --- /dev/null +++ b/.changeset/empty-lamps-marry.md @@ -0,0 +1,7 @@ +--- +"@layerzerolabs/ua-devtools-evm-hardhat-test": patch +"@layerzerolabs/ua-devtools-evm-hardhat": patch +"@layerzerolabs/io-devtools": patch +--- + +Adding in Default Colors to print outs diff --git a/packages/io-devtools/package.json b/packages/io-devtools/package.json index e4b37773d..250e766db 100644 --- a/packages/io-devtools/package.json +++ b/packages/io-devtools/package.json @@ -37,6 +37,7 @@ "test": "jest --ci" }, "dependencies": { + "chalk": "^4.1.2", "cli-table3": "^0.6.3", "logform": "^2.6.0", "prompts": "^2.4.2", diff --git a/packages/io-devtools/src/stdio/printer.ts b/packages/io-devtools/src/stdio/printer.ts index a98a9f1d8..741baa1ee 100644 --- a/packages/io-devtools/src/stdio/printer.ts +++ b/packages/io-devtools/src/stdio/printer.ts @@ -1,6 +1,16 @@ -import Table, { HorizontalTableRow } from 'cli-table3' +import Table, { HorizontalAlignment, HorizontalTableRow } from 'cli-table3' +import chalk from 'chalk' import type { ZodError } from 'zod' +type Preprocess = (value: string) => string +export const COLORS = { + TRUE: chalk.rgb(0, 153, 0), // GREEN + FALSE: chalk.rgb(255, 0, 0), // RED + NOT_APPLICABLE: chalk.rgb(255, 128, 0), // ORANGE + DEFAULT_KEY: chalk.rgb(255, 255, 255), // WHITE + DEFAULT_VALUE: chalk.rgb(167, 125, 255), // MAGENTA +} + /** * Returns a JSON-serialized version of a string, replacing all `BigInt` * instances with strings @@ -29,28 +39,41 @@ export const printJson = (obj: unknown, pretty = true): string => * @see {@link printRecord} * * @param value + * @param keyColor - color of keys in table (DEFAULT: WHITE) + * @param valueColor - color of values in table (DEFAULT: MAGENTA) * @returns */ -const printValue = (value: unknown): string => { +const printValue = ( + value: unknown, + keyColor: Preprocess = COLORS.DEFAULT_KEY, + valueColor: Preprocess = COLORS.DEFAULT_VALUE +): string => { switch (true) { case value == null: case value instanceof Date: case typeof value !== 'object': - return String(value) + return valueColor(String(value)) default: - return printRecord(value) + return printRecord(value, undefined, keyColor, valueColor) } } -export const printRecord = (obj: TRecord, title?: string | number): string => { +export const printRecord = ( + obj: TRecord, + title?: string | number, + keyColor: Preprocess = COLORS.DEFAULT_KEY, + valueColor: Preprocess = COLORS.DEFAULT_VALUE +): string => { const table = new Table({ wordWrap: true, wrapOnWordBoundary: false, }) const headers: HorizontalTableRow[] = title == null ? [] : [[{ content: title, colSpan: 2 }]] - const rows = Object.entries(obj).map(([key, value]): HorizontalTableRow => [key, printValue(value)]) + const rows = Object.entries(obj).map( + ([key, value]): HorizontalTableRow => [keyColor(key), printValue(value, keyColor, valueColor)] + ) return table.push(...headers, ...rows), table.toString() } @@ -63,20 +86,30 @@ export const printRecord = (obj: TRecord, title?: string * the property name. * * @param {Record} records - * @param {string[]} [header] + * @param {string[]} [headers] - header row if provided + * @param {boolean} [center] - center text if true + * @param {Preprocess} [keyColor=COLORS.DEFAULT_KEY] keyColor - color of keys in table + * @param {Preprocess} [valueColor=COLORS.DEFAULT_VALUE] valueColor - color of values in table * @returns {string} */ export const printCrossTable = >( records: TRecord[], - header?: string[] + headers?: string[], + center?: boolean, + keyColor: Preprocess = COLORS.DEFAULT_KEY, + valueColor: Preprocess = COLORS.DEFAULT_VALUE ): string => { const table = new Table({ - head: header ?? [], wordWrap: true, wrapOnWordBoundary: false, - style: { head: ['reset'] }, }) + // Set the colored headers if provided + const coloredHeaders = headers?.map((header) => keyColor(header)) ?? [] + table.push(coloredHeaders) + + table.options.colAligns = center ? (['left', ...records.map(() => 'center')] as HorizontalAlignment[]) : [] + // We'll gather all the properties of all the records in this array // // We do this in case some of the objects were missing any properties - @@ -94,10 +127,10 @@ export const printCrossTable = propertiesLeft.delete(property) // Get all the values and print them - const values = records.map((record) => record[property]).map(printValue) + const values = records.map((record) => printValue(record[property], keyColor, valueColor)) // Create a row with the property label first - const row = [property, ...values] + const row = [keyColor(property), ...values] // And add to the table table.push(row) @@ -110,9 +143,17 @@ export const printCrossTable = * Helper utility for printing out boolean values * * @param {boolean | null | undefined} value + * @param {Preprocess} [nullColor=COLORS.NOT_APPLICABLE] nullColor + * @param {Preprocess} [trueColor=COLORS.TRUE] trueColor + * @param {Preprocess} [falseColor=COLORS.FALSE] falseColor * @returns {string} */ -export const printBoolean = (value: boolean | null | undefined): string => (value == null ? '∅' : value ? '✓' : '⤫') +export const printBoolean = ( + value: boolean | null | undefined, + nullColor: Preprocess = COLORS.NOT_APPLICABLE, + trueColor: Preprocess = COLORS.TRUE, + falseColor: Preprocess = COLORS.FALSE +): string => (value == null ? nullColor('∅') : value ? trueColor('✓') : falseColor('⤫')) export const printZodErrors = (error: ZodError): string => { // Here we will go through all the errors and prefix them with the name diff --git a/packages/ua-devtools-evm-hardhat/src/tasks/oapp/peers.get.ts b/packages/ua-devtools-evm-hardhat/src/tasks/oapp/peers.get.ts index 316f19bcd..1e1b2dd7d 100644 --- a/packages/ua-devtools-evm-hardhat/src/tasks/oapp/peers.get.ts +++ b/packages/ua-devtools-evm-hardhat/src/tasks/oapp/peers.get.ts @@ -67,11 +67,11 @@ const action: ActionType = async ({ oappConfig: oappConfigPath, logLev }) console.log( - printCrossTable(peerNetworkMatrix, ['from → to', ...points.map(({ networkName }) => networkName)]), - `\n\t${printBoolean(true)} - Connected\n`, - `\t${printBoolean(false)} - Not Connected\n`, - `\t${printBoolean(undefined)} - Ignored` + printCrossTable(peerNetworkMatrix, ['from → to', ...points.map(({ networkName }) => networkName)], true) ) + console.log(` ${printBoolean(true)} - Connected`) + console.log(` ${printBoolean(false)} - Not Connected`) + console.log(` ${printBoolean(undefined)} - Ignored`) return peers } catch (error) { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 467b895b6..e484a866e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -619,6 +619,9 @@ importers: packages/io-devtools: dependencies: + chalk: + specifier: ^4.1.2 + version: 4.1.2 cli-table3: specifier: ^0.6.3 version: 0.6.3 diff --git a/tests/ua-devtools-evm-hardhat-test/test/task/oapp/__snapshots__/config.check.test.ts.snap b/tests/ua-devtools-evm-hardhat-test/test/task/oapp/__snapshots__/config.check.test.ts.snap index 65a08e122..1cceadc6e 100644 --- a/tests/ua-devtools-evm-hardhat-test/test/task/oapp/__snapshots__/config.check.test.ts.snap +++ b/tests/ua-devtools-evm-hardhat-test/test/task/oapp/__snapshots__/config.check.test.ts.snap @@ -2,7 +2,8 @@ exports[`task lz:oapp:peers:get should show a standard lzReceive setting for all pathways 1`] = ` [ - "┌───────────┬───────────────────────────────────────────────────────────┬───────────────────────────────────────────────────────────┐ + [ + "┌───────────┬───────────────────────────────────────────────────────────┬───────────────────────────────────────────────────────────┐ │ from → to │ britney │ vengaboys │ ├───────────┼───────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────┤ │ britney │ │ ┌────────────┬──────────────────────────────────────────┐ │ @@ -25,90 +26,112 @@ exports[`task lz:oapp:peers:get should show a standard lzReceive setting for all │ │ │ │ └─────────────────┴────────────────────┘ │ │ │ │ │ └────────────┴──────────────────────────────────────────┘ │ │ └───────────┴───────────────────────────────────────────────────────────┴───────────────────────────────────────────────────────────┘", + ], ] `; exports[`task lz:oapp:peers:get should show all chains are connected after running wire with three networks 1`] = ` [ - "┌───────────┬─────────┬───────────┬───────┐ + [ + "┌───────────┬─────────┬───────────┬───────┐ │ from → to │ britney │ vengaboys │ tango │ ├───────────┼─────────┼───────────┼───────┤ -│ britney │ ∅ │ ✓ │ ✓ │ +│ britney │ ∅ │ ✓ │ ✓ │ ├───────────┼─────────┼───────────┼───────┤ -│ vengaboys │ ✓ │ ∅ │ ✓ │ +│ vengaboys │ ✓ │ ∅ │ ✓ │ ├───────────┼─────────┼───────────┼───────┤ -│ tango │ ✓ │ ✓ │ ∅ │ +│ tango │ ✓ │ ✓ │ ∅ │ └───────────┴─────────┴───────────┴───────┘", - " - ✓ - Connected -", - " ⤫ - Not Connected -", - " ∅ - Ignored", + ], + [ + " ✓ - Connected", + ], + [ + " ⤫ - Not Connected", + ], + [ + " ∅ - Ignored", + ], ] `; exports[`task lz:oapp:peers:get should show all chains are connected after running wire with two networks 1`] = ` [ - "┌───────────┬─────────┬───────────┐ + [ + "┌───────────┬─────────┬───────────┐ │ from → to │ britney │ vengaboys │ ├───────────┼─────────┼───────────┤ -│ britney │ ∅ │ ✓ │ +│ britney │ ∅ │ ✓ │ ├───────────┼─────────┼───────────┤ -│ vengaboys │ ✓ │ ∅ │ +│ vengaboys │ ✓ │ ∅ │ └───────────┴─────────┴───────────┘", - " - ✓ - Connected -", - " ⤫ - Not Connected -", - " ∅ - Ignored", + ], + [ + " ✓ - Connected", + ], + [ + " ⤫ - Not Connected", + ], + [ + " ∅ - Ignored", + ], ] `; exports[`task lz:oapp:peers:get should show all chains are connected expect one after running wire with three networks 1`] = ` [ - "┌───────────┬─────────┬───────────┬───────┐ + [ + "┌───────────┬─────────┬───────────┬───────┐ │ from → to │ britney │ vengaboys │ tango │ ├───────────┼─────────┼───────────┼───────┤ -│ britney │ ∅ │ ✓ │ ✓ │ +│ britney │ ∅ │ ✓ │ ✓ │ ├───────────┼─────────┼───────────┼───────┤ -│ vengaboys │ ✓ │ ∅ │ ✓ │ +│ vengaboys │ ✓ │ ∅ │ ✓ │ ├───────────┼─────────┼───────────┼───────┤ -│ tango │ ∅ │ ✓ │ ∅ │ +│ tango │ ∅ │ ✓ │ ∅ │ └───────────┴─────────┴───────────┴───────┘", - " - ✓ - Connected -", - " ⤫ - Not Connected -", - " ∅ - Ignored", + ], + [ + " ✓ - Connected", + ], + [ + " ⤫ - Not Connected", + ], + [ + " ∅ - Ignored", + ], ] `; exports[`task lz:oapp:peers:get should show all chains are not connected expect one after running wire with three networks 1`] = ` [ - "┌───────────┬─────────┬───────────┬───────┐ + [ + "┌───────────┬─────────┬───────────┬───────┐ │ from → to │ britney │ vengaboys │ tango │ ├───────────┼─────────┼───────────┼───────┤ -│ britney │ ∅ │ ∅ │ ∅ │ +│ britney │ ∅ │ ∅ │ ∅ │ ├───────────┼─────────┼───────────┼───────┤ -│ vengaboys │ ✓ │ ∅ │ ∅ │ +│ vengaboys │ ✓ │ ∅ │ ∅ │ ├───────────┼─────────┼───────────┼───────┤ -│ tango │ ∅ │ ∅ │ ∅ │ +│ tango │ ∅ │ ∅ │ ∅ │ └───────────┴─────────┴───────────┴───────┘", - " - ✓ - Connected -", - " ⤫ - Not Connected -", - " ∅ - Ignored", + ], + [ + " ✓ - Connected", + ], + [ + " ⤫ - Not Connected", + ], + [ + " ∅ - Ignored", + ], ] `; exports[`task lz:oapp:peers:get should show different combined enforced options for all pathways 1`] = ` [ - "┌───────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + [ + "┌───────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ from → to │ britney │ vengaboys │ tango │ ├───────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ britney │ │ ┌────────────┬──────────────────────────────────────────┐ │ ┌────────────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ @@ -217,12 +240,14 @@ exports[`task lz:oapp:peers:get should show different combined enforced options │ │ │ │ │ └────────────────────┴───────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ │ └────────────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ └───────────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘", + ], ] `; exports[`task lz:oapp:peers:get should show enforced options for one pathway 1`] = ` [ - "┌───────────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬───────────┬───────┐ + [ + "┌───────────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬───────────┬───────┐ │ from → to │ britney │ vengaboys │ tango │ ├───────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────┼───────┤ │ britney │ │ │ │ @@ -247,23 +272,29 @@ exports[`task lz:oapp:peers:get should show enforced options for one pathway 1`] ├───────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────┼───────┤ │ tango │ │ │ │ └───────────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴───────────┴───────┘", + ], ] `; exports[`task lz:oapp:peers:get should show no chains are connected with two networks 1`] = ` [ - "┌───────────┬─────────┬───────────┐ + [ + "┌───────────┬─────────┬───────────┐ │ from → to │ britney │ vengaboys │ ├───────────┼─────────┼───────────┤ -│ britney │ ∅ │ ⤫ │ +│ britney │ ∅ │ ⤫ │ ├───────────┼─────────┼───────────┤ -│ vengaboys │ ⤫ │ ∅ │ +│ vengaboys │ ⤫ │ ∅ │ └───────────┴─────────┴───────────┘", - " - ✓ - Connected -", - " ⤫ - Not Connected -", - " ∅ - Ignored", + ], + [ + " ✓ - Connected", + ], + [ + " ⤫ - Not Connected", + ], + [ + " ∅ - Ignored", + ], ] `; diff --git a/tests/ua-devtools-evm-hardhat-test/test/task/oapp/config.check.test.ts b/tests/ua-devtools-evm-hardhat-test/test/task/oapp/config.check.test.ts index b940086c5..fd23b86bb 100644 --- a/tests/ua-devtools-evm-hardhat-test/test/task/oapp/config.check.test.ts +++ b/tests/ua-devtools-evm-hardhat-test/test/task/oapp/config.check.test.ts @@ -10,6 +10,8 @@ import { import { deployAndSetupDefaultEndpointV2 } from '../../__utils__/endpointV2' describe(`task ${TASK_LZ_OAPP_PEERS_GET}`, () => { + let consoleSpy: jest.SpyInstance + const CONFIGS_BASE_DIR = resolve(__dirname, '__data__', 'configs') const configPathFixture = (fileName: string): string => { const path = resolve(CONFIGS_BASE_DIR, fileName) @@ -23,68 +25,73 @@ describe(`task ${TASK_LZ_OAPP_PEERS_GET}`, () => { beforeEach(async () => { await deployOApp() + consoleSpy = jest.spyOn(console, 'log') + }) + + afterEach(() => { + consoleSpy.mockRestore() }) it('should show no chains are connected with two networks', async () => { - const consoleSpy = jest.spyOn(console, 'log') const oappConfig = configPathFixture('valid.config.connected.js') + consoleSpy.mockClear() await hre.run(TASK_LZ_OAPP_PEERS_GET, { oappConfig }) - expect(consoleSpy.mock.lastCall).toMatchSnapshot() + expect(consoleSpy.mock.calls).toMatchSnapshot() }) it('should show all chains are connected after running wire with two networks', async () => { - const consoleSpy = jest.spyOn(console, 'log') const oappConfig = configPathFixture('valid.config.connected.js') await hre.run(TASK_LZ_OAPP_WIRE, { oappConfig, ci: true }) + consoleSpy.mockClear() await hre.run(TASK_LZ_OAPP_PEERS_GET, { oappConfig }) - expect(consoleSpy.mock.lastCall).toMatchSnapshot() + expect(consoleSpy.mock.calls).toMatchSnapshot() }) it('should show all chains are connected after running wire with three networks', async () => { - const consoleSpy = jest.spyOn(console, 'log') const oappConfig = configPathFixture('valid.multi.network.config.connected.js') await hre.run(TASK_LZ_OAPP_WIRE, { oappConfig, ci: true }) + consoleSpy.mockClear() await hre.run(TASK_LZ_OAPP_PEERS_GET, { oappConfig }) - expect(consoleSpy.mock.lastCall).toMatchSnapshot() + expect(consoleSpy.mock.calls).toMatchSnapshot() }) it('should show all chains are connected expect one after running wire with three networks', async () => { - const consoleSpy = jest.spyOn(console, 'log') const oappConfig = configPathFixture('valid.multi.network.config.missing.connection.js') await hre.run(TASK_LZ_OAPP_WIRE, { oappConfig, ci: true }) await hre.run(TASK_LZ_OAPP_PEERS_GET, { oappConfig }) - expect(consoleSpy.mock.lastCall).toMatchSnapshot() + expect(consoleSpy.mock.calls).toMatchSnapshot() }) it('should show all chains are not connected expect one after running wire with three networks', async () => { - const consoleSpy = jest.spyOn(console, 'log') const oappConfig = configPathFixture('valid.multi.network.config.one.connection.js') await hre.run(TASK_LZ_OAPP_WIRE, { oappConfig, ci: true }) + consoleSpy.mockClear() + await hre.run(TASK_LZ_OAPP_PEERS_GET, { oappConfig }) - expect(consoleSpy.mock.lastCall).toMatchSnapshot() + expect(consoleSpy.mock.calls).toMatchSnapshot() }) it('should show enforced options for one pathway', async () => { - const consoleSpy = jest.spyOn(console, 'log') const oappConfig = configPathFixture('valid.multi.network.one.pathway.enforced.options.js') await hre.run(TASK_LZ_OAPP_WIRE, { oappConfig, ci: true }) + consoleSpy.mockClear() await hre.run(TASK_LZ_OAPP_ENFORCED_OPTS_GET, { oappConfig }) - expect(consoleSpy.mock.lastCall).toMatchSnapshot() + expect(consoleSpy.mock.calls).toMatchSnapshot() }) it('should show a standard lzReceive setting for all pathways', async () => { - const consoleSpy = jest.spyOn(console, 'log') const oappConfig = configPathFixture('valid.multi.network.lzreceive.enforced.options.js') await hre.run(TASK_LZ_OAPP_WIRE, { oappConfig, ci: true }) + consoleSpy.mockClear() await hre.run(TASK_LZ_OAPP_ENFORCED_OPTS_GET, { oappConfig }) - expect(consoleSpy.mock.lastCall).toMatchSnapshot() + expect(consoleSpy.mock.calls).toMatchSnapshot() }) it('should show different combined enforced options for all pathways', async () => { - const consoleSpy = jest.spyOn(console, 'log') const oappConfig = configPathFixture('valid.multi.network.enforced.options.js') await hre.run(TASK_LZ_OAPP_WIRE, { oappConfig, ci: true }) + consoleSpy.mockClear() await hre.run(TASK_LZ_OAPP_ENFORCED_OPTS_GET, { oappConfig }) - expect(consoleSpy.mock.lastCall).toMatchSnapshot() + expect(consoleSpy.mock.calls).toMatchSnapshot() }) })