From 0931d9b6c9324faeda6cf1893fd03112199e8bd0 Mon Sep 17 00:00:00 2001 From: Shazron Abdullah <36107+shazron@users.noreply.github.com> Date: Thu, 26 Mar 2026 01:49:24 +0800 Subject: [PATCH 1/5] chore: update @oclif/core to v4 and @adobe/eslint-config-aio-lib-config to v5 - Update @oclif/core from ^2.8.12 to ^4.9.0 (closes #129) - Replace removed ux.table with a new src/utils/table.js utility - Rename ux:cli import alias to ux across all command files - Update jest.setup.js: remove obsolete @oclif/core/lib/cli-ux mocks, add mockConfig stub for Command.parse() which now requires this.config - Add test/utils/table.test.js for full branch coverage - Update @adobe/eslint-config-aio-lib-config from ^4.0.0 to 5.0.0 - Upgrade eslint to v9, add neostandard, upgrade eslint-plugin-jest - Replace .eslintrc.json with eslint.config.js (ESLint 9 flat config) - Remove replaced packages: eslint-config-oclif, eslint-config-standard, eslint-plugin-import, eslint-plugin-n, eslint-plugin-node, eslint-plugin-promise, eslint-plugin-standard - Remove now-invalid eslint-disable comment from validator.js Co-Authored-By: Claude Sonnet 4.6 --- .eslintrc.json | 18 ----- e2e/.eslintrc.json | 5 -- eslint.config.js | 48 ++++++++++++++ package.json | 16 ++--- src/commands/event/eventmetadata/create.js | 6 +- src/commands/event/eventmetadata/delete.js | 10 +-- src/commands/event/eventmetadata/get.js | 6 +- src/commands/event/eventmetadata/list.js | 9 +-- src/commands/event/eventmetadata/update.js | 6 +- src/commands/event/provider/create.js | 6 +- src/commands/event/provider/delete.js | 6 +- src/commands/event/provider/get.js | 6 +- src/commands/event/provider/list.js | 9 +-- src/commands/event/provider/update.js | 6 +- src/commands/event/registration/create.js | 6 +- src/commands/event/registration/delete.js | 6 +- src/commands/event/registration/get.js | 6 +- src/commands/event/registration/list.js | 9 +-- src/utils/table.js | 57 ++++++++++++++++ src/utils/validator.js | 1 - test/jest.setup.js | 44 +++++-------- test/utils/table.test.js | 76 ++++++++++++++++++++++ 22 files changed, 253 insertions(+), 109 deletions(-) delete mode 100644 .eslintrc.json delete mode 100644 e2e/.eslintrc.json create mode 100644 eslint.config.js create mode 100644 src/utils/table.js create mode 100644 test/utils/table.test.js diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 1613426..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "extends": "@adobe/eslint-config-aio-lib-config", - "settings": { - "jsdoc": { - "ignorePrivate": true - } - }, - "rules": { - "jsdoc/tag-lines": [ - // The Error level should be `error`, `warn`, or `off` (or 2, 1, or 0) - "error", - "never", - { - "startLines": null - } - ] - } -} diff --git a/e2e/.eslintrc.json b/e2e/.eslintrc.json deleted file mode 100644 index ae74b09..0000000 --- a/e2e/.eslintrc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "rules": { - "node/no-unpublished-require": 0 - } -} diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..7e763d3 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,48 @@ +/* +Copyright 2020 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +const aioLibConfig = require('@adobe/eslint-config-aio-lib-config') +const pluginJest = require('eslint-plugin-jest') + +module.exports = [ + ...aioLibConfig, + { + settings: { + jsdoc: { + ignorePrivate: true + } + }, + rules: { + 'jsdoc/tag-lines': [ + 'error', + 'never', + { + startLines: null + } + ] + } + }, + { + files: ['test/**/*.js'], + ...pluginJest.configs['flat/recommended'], + rules: { + ...pluginJest.configs['flat/recommended'].rules + } + }, + { + files: ['e2e/**/*.js'], + ...pluginJest.configs['flat/recommended'], + rules: { + ...pluginJest.configs['flat/recommended'].rules, + 'n/no-unpublished-require': 'off' + } + } +] diff --git a/package.json b/package.json index 07ab660..410f649 100644 --- a/package.json +++ b/package.json @@ -16,33 +16,27 @@ "@adobe/aio-lib-env": "^3", "@adobe/aio-lib-events": "^4", "@adobe/aio-lib-ims": "^7", - "@oclif/core": "^2.8.12", + "@oclif/core": "^4.9.0", "inquirer": "^8.2.5", "js-yaml": "^4.1.0" }, "repository": "adobe/aio-cli-plugin-events", "devDependencies": { - "@adobe/eslint-config-aio-lib-config": "^4.0.0", + "@adobe/eslint-config-aio-lib-config": "^5.0.0", "@types/jest": "^29.5.3", "acorn": "^8.10.0", "babel-runtime": "^6.26.0", "chalk": "^4.0.0", "eol": "^0.9.1", - "eslint": "^8.57.1", - "eslint-config-oclif": "^4.0.0", - "eslint-config-standard": "^17.1.0", - "eslint-plugin-import": "^2.31.0", - "eslint-plugin-jest": "^27.9.0", + "eslint": "^9.39.4", + "eslint-plugin-jest": "^29.15.1", "eslint-plugin-jsdoc": "^48.11.0", - "eslint-plugin-n": "^15.7.0", - "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^6.6.0", - "eslint-plugin-standard": "^5.0.0", "execa": "^7.2.0", "jest": "^29.5.0", "jest-haste-map": "^29.5.0", "jest-junit": "^16.0.0", "jest-resolve": "^29.5.0", + "neostandard": "^0.13.0", "oclif": "^3.2.0", "stdout-stderr": "^0.1.13" }, diff --git a/src/commands/event/eventmetadata/create.js b/src/commands/event/eventmetadata/create.js index 42dc546..a3df820 100644 --- a/src/commands/event/eventmetadata/create.js +++ b/src/commands/event/eventmetadata/create.js @@ -11,7 +11,7 @@ governing permissions and limitations under the License. */ const BaseCommand = require('../../../BaseCommand.js') -const { Args, Flags, ux: cli } = require('@oclif/core') +const { Args, Flags, ux } = require('@oclif/core') const { sentenceValidatorWithMinOneChar, eventCodeValidator } = require('../../../utils/validator') const inquirer = require('inquirer') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:eventmetadata:create', { provider: 'debug' }) @@ -41,9 +41,9 @@ class EventmetadataCreateCommand extends BaseCommand { description: response.description } - cli.action.start('Creating Event Metadata') + ux.action.start('Creating Event Metadata') const eventmetadata = await this.eventClient.createEventMetadataForProvider(this.conf.org.id, this.conf.project.id, this.conf.workspace.id, args.providerId, eventMetadataPayload) - cli.action.stop() + ux.action.stop() if (flags.json) { this.printJson(eventmetadata) diff --git a/src/commands/event/eventmetadata/delete.js b/src/commands/event/eventmetadata/delete.js index cd107df..ece3ce7 100644 --- a/src/commands/event/eventmetadata/delete.js +++ b/src/commands/event/eventmetadata/delete.js @@ -11,7 +11,7 @@ governing permissions and limitations under the License. */ const BaseCommand = require('../../../BaseCommand.js') -const { Args, ux: cli } = require('@oclif/core') +const { Args, ux } = require('@oclif/core') const inquirer = require('inquirer') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:eventmetadata:delete', { provider: 'debug' }) @@ -29,10 +29,10 @@ class EventmetadataDeleteCommand extends BaseCommand { }]) if (response.delete) { - cli.action.start('Deleting ALL Event Metadata for provider') + ux.action.start('Deleting ALL Event Metadata for provider') await this.eventClient.deleteAllEventMetadata(this.conf.org.id, this.conf.project.id, this.conf.workspace.id, args.providerId) - cli.action.stop() + ux.action.stop() this.log('All event metadata of provider ' + args.providerId + ' has been deleted successfully') } else { this.log('Deletion operation has been cancelled. For more information on delete use --help') @@ -45,11 +45,11 @@ class EventmetadataDeleteCommand extends BaseCommand { }]) if (response.delete) { - cli.action.start('Deleting Event Metadata for provider') + ux.action.start('Deleting Event Metadata for provider') await this.eventClient.deleteEventMetadata(this.conf.org.id, this.conf.project.id, this.conf.workspace.id, args.providerId, args.eventCode) - cli.action.stop() + ux.action.stop() this.log(args.eventCode + ' event metadata of provider ' + args.providerId + ' has been deleted successfully') } else { this.log('Deletion operation has been cancelled. For more information on delete use --help') diff --git a/src/commands/event/eventmetadata/get.js b/src/commands/event/eventmetadata/get.js index cc3b91f..df4c53c 100644 --- a/src/commands/event/eventmetadata/get.js +++ b/src/commands/event/eventmetadata/get.js @@ -11,7 +11,7 @@ governing permissions and limitations under the License. */ const BaseCommand = require('../../../BaseCommand.js') -const { Args, Flags, ux: cli } = require('@oclif/core') +const { Args, Flags, ux } = require('@oclif/core') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:eventmetadata:get', { provider: 'debug' }) class EventmetadataGetCommand extends BaseCommand { @@ -20,10 +20,10 @@ class EventmetadataGetCommand extends BaseCommand { try { await this.initSdk() - cli.action.start('Fetching the event metadata for the provider') + ux.action.start('Fetching the event metadata for the provider') const eventmetadata = await this.eventClient.getEventMetadataForProvider(args.providerId, args.eventCode) - cli.action.stop() + ux.action.stop() if (flags.json) { this.printJson(eventmetadata) diff --git a/src/commands/event/eventmetadata/list.js b/src/commands/event/eventmetadata/list.js index 7d4c37d..4006f6c 100644 --- a/src/commands/event/eventmetadata/list.js +++ b/src/commands/event/eventmetadata/list.js @@ -11,7 +11,8 @@ governing permissions and limitations under the License. */ const BaseCommand = require('../../../BaseCommand.js') -const { Args, Flags, ux: cli } = require('@oclif/core') +const { Args, Flags, ux } = require('@oclif/core') +const { table } = require('../../../utils/table') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:eventmetadata:list', { provider: 'debug' }) class EventmetadataListCommand extends BaseCommand { @@ -19,9 +20,9 @@ class EventmetadataListCommand extends BaseCommand { const { args, flags } = await this.parse(EventmetadataListCommand) try { await this.initSdk() - cli.action.start('Fetching all Event Metadata for provider') + ux.action.start('Fetching all Event Metadata for provider') const eventmetadatas = await this.eventClient.getAllEventMetadataForProvider(args.providerId) - cli.action.stop() + ux.action.stop() if (flags.json) { this.printJson(eventmetadatas) } else if (flags.yml) { @@ -48,7 +49,7 @@ class EventmetadataListCommand extends BaseCommand { header: 'DESC' } } - cli.table(projects, columns) + table(projects, columns) } } diff --git a/src/commands/event/eventmetadata/update.js b/src/commands/event/eventmetadata/update.js index 05ea09d..4e10f13 100644 --- a/src/commands/event/eventmetadata/update.js +++ b/src/commands/event/eventmetadata/update.js @@ -11,7 +11,7 @@ governing permissions and limitations under the License. */ const BaseCommand = require('../../../BaseCommand.js') -const { Args, Flags, ux: cli } = require('@oclif/core') +const { Args, Flags, ux } = require('@oclif/core') const { sentenceValidatorWithMinOneChar } = require('../../../utils/validator') const inquirer = require('inquirer') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:eventmetadata:update', { provider: 'debug' }) @@ -37,9 +37,9 @@ class EventmetadataUpdateCommand extends BaseCommand { description: response.description } - cli.action.start('Updating Event Metadata for Provider') + ux.action.start('Updating Event Metadata for Provider') const eventmetadata = await this.eventClient.updateEventMetadataForProvider(this.conf.org.id, this.conf.project.id, this.conf.workspace.id, args.providerId, args.eventCode, eventMetadataPayload) - cli.action.stop() + ux.action.stop() if (flags.json) { this.printJson(eventmetadata) } else if (flags.yml) { diff --git a/src/commands/event/provider/create.js b/src/commands/event/provider/create.js index a410df8..3bdb9d7 100644 --- a/src/commands/event/provider/create.js +++ b/src/commands/event/provider/create.js @@ -11,7 +11,7 @@ governing permissions and limitations under the License. */ const BaseCommand = require('../../../BaseCommand.js') -const { Flags, ux: cli } = require('@oclif/core') +const { Flags, ux } = require('@oclif/core') const { sentenceValidatorWithMinOneChar, sentenceValidatorWithMinZeroChar } = require('../../../utils/validator') const inquirer = require('inquirer') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:provider:create', { provider: 'debug' }) @@ -40,9 +40,9 @@ class ProviderCreateCommand extends BaseCommand { docs_url: response.docs_url || undefined } - cli.action.start('Creating Event Provider') + ux.action.start('Creating Event Provider') const provider = await this.eventClient.createProvider(this.conf.org.id, this.conf.project.id, this.conf.workspace.id, providerPayload) - cli.action.stop() + ux.action.stop() if (flags.json) { this.printJson(provider) } else if (flags.yml) { diff --git a/src/commands/event/provider/delete.js b/src/commands/event/provider/delete.js index c990776..5ea5902 100644 --- a/src/commands/event/provider/delete.js +++ b/src/commands/event/provider/delete.js @@ -11,7 +11,7 @@ governing permissions and limitations under the License. */ const BaseCommand = require('../../../BaseCommand.js') -const { Args, ux: cli } = require('@oclif/core') +const { Args, ux } = require('@oclif/core') const inquirer = require('inquirer') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:provider:delete', { provider: 'debug' }) @@ -28,10 +28,10 @@ class ProviderDeleteCommand extends BaseCommand { }]) if (response.delete) { - cli.action.start('Deleting Event Provider') + ux.action.start('Deleting Event Provider') await this.eventClient.deleteProvider(this.conf.org.id, this.conf.project.id, this.conf.workspace.id, args.providerId) - cli.action.stop() + ux.action.stop() this.log('Provider ' + args.providerId + ' has been deleted successfully') } else { diff --git a/src/commands/event/provider/get.js b/src/commands/event/provider/get.js index f1e3323..93a4f5d 100644 --- a/src/commands/event/provider/get.js +++ b/src/commands/event/provider/get.js @@ -11,7 +11,7 @@ governing permissions and limitations under the License. */ const BaseCommand = require('../../../BaseCommand.js') -const { Args, Flags, ux: cli } = require('@oclif/core') +const { Args, Flags, ux } = require('@oclif/core') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:provider:get', { provider: 'debug' }) class ProviderGetCommand extends BaseCommand { @@ -20,10 +20,10 @@ class ProviderGetCommand extends BaseCommand { try { await this.initSdk() - cli.action.start('Fetching the Event Provider') + ux.action.start('Fetching the Event Provider') const provider = await this.eventClient.getProvider(args.providerId, flags.fetchEventMetadata) - cli.action.stop() + ux.action.stop() if (flags.json) { this.printJson(provider) diff --git a/src/commands/event/provider/list.js b/src/commands/event/provider/list.js index a2ea77e..d0860f1 100644 --- a/src/commands/event/provider/list.js +++ b/src/commands/event/provider/list.js @@ -11,7 +11,8 @@ governing permissions and limitations under the License. */ const BaseCommand = require('../../../BaseCommand.js') -const { Flags, ux: cli } = require('@oclif/core') +const { Flags, ux } = require('@oclif/core') +const { table } = require('../../../utils/table') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:provider:list', { provider: 'debug' }) class ProviderListCommand extends BaseCommand { @@ -19,7 +20,7 @@ class ProviderListCommand extends BaseCommand { const { flags } = await this.parse(ProviderListCommand) try { await this.initSdk() - cli.action.start('Fetching all Event Providers') + ux.action.start('Fetching all Event Providers') const options = { fetchEventMetadata: flags.fetchEventMetadata, filterBy: { @@ -29,7 +30,7 @@ class ProviderListCommand extends BaseCommand { } } const providers = await this.eventClient.getAllProviders(this.conf.org.id, options) - cli.action.stop() + ux.action.stop() if (flags.json) { this.printJson(providers) } else if (flags.yml) { @@ -61,7 +62,7 @@ class ProviderListCommand extends BaseCommand { header: 'DOCS' } } - cli.table(projects, columns) + table(projects, columns) } } diff --git a/src/commands/event/provider/update.js b/src/commands/event/provider/update.js index 0de2869..7710b0d 100644 --- a/src/commands/event/provider/update.js +++ b/src/commands/event/provider/update.js @@ -11,7 +11,7 @@ governing permissions and limitations under the License. */ const BaseCommand = require('../../../BaseCommand.js') -const { Args, Flags, ux: cli } = require('@oclif/core') +const { Args, Flags, ux } = require('@oclif/core') const { sentenceValidatorWithMinOneChar, sentenceValidatorWithMinZeroChar } = require('../../../utils/validator') const inquirer = require('inquirer') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:provider:update', { provider: 'debug' }) @@ -40,9 +40,9 @@ class ProviderUpdateCommand extends BaseCommand { docs_url: response.docs_url || undefined } - cli.action.start('Updating the Event Provider') + ux.action.start('Updating the Event Provider') const provider = await this.eventClient.updateProvider(this.conf.org.id, this.conf.project.id, this.conf.workspace.id, args.providerId, providerPayload) - cli.action.stop() + ux.action.stop() if (flags.json) { this.printJson(provider) } else if (flags.yml) { diff --git a/src/commands/event/registration/create.js b/src/commands/event/registration/create.js index 9f63662..6635bdf 100644 --- a/src/commands/event/registration/create.js +++ b/src/commands/event/registration/create.js @@ -10,7 +10,7 @@ OF ANY KIND, either express or implied. See the License for the specific languag governing permissions and limitations under the License. */ -const { Args, Flags, ux: cli } = require('@oclif/core') +const { Args, Flags, ux } = require('@oclif/core') const fs = require('fs') const BaseCommand = require('../../../BaseCommand') @@ -31,9 +31,9 @@ class CreateCommand extends BaseCommand { // other checks are performed by the server aioLogger.debug(`create event registration with body ${body}`) - cli.action.start('Creating new Event Registration') + ux.action.start('Creating new Event Registration') const registration = await this.eventClient.createRegistration(this.conf.org.id, this.conf.project.id, this.conf.workspace.id, body) - cli.action.stop() + ux.action.stop() aioLogger.debug(`create successful, id: ${registration.registration_id}, name: ${registration.name}`) if (flags.json) { diff --git a/src/commands/event/registration/delete.js b/src/commands/event/registration/delete.js index 282e171..3021d92 100644 --- a/src/commands/event/registration/delete.js +++ b/src/commands/event/registration/delete.js @@ -11,7 +11,7 @@ governing permissions and limitations under the License. */ const BaseCommand = require('../../../BaseCommand.js') -const { Args, ux: cli } = require('@oclif/core') +const { Args, ux } = require('@oclif/core') const inquirer = require('inquirer') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:registration:delete', { provider: 'debug' }) @@ -28,10 +28,10 @@ class DeleteCommand extends BaseCommand { }]) if (response.delete) { - cli.action.start('Deleting Registration') + ux.action.start('Deleting Registration') await this.eventClient.deleteRegistration(this.conf.org.id, this.conf.project.id, this.conf.workspace.id, args.registrationId) - cli.action.stop() + ux.action.stop() this.log('Registration ' + args.registrationId + ' has been deleted successfully') } else { diff --git a/src/commands/event/registration/get.js b/src/commands/event/registration/get.js index afcb5cf..8c177c1 100644 --- a/src/commands/event/registration/get.js +++ b/src/commands/event/registration/get.js @@ -10,7 +10,7 @@ OF ANY KIND, either express or implied. See the License for the specific languag governing permissions and limitations under the License. */ -const { Args, Flags, ux: cli } = require('@oclif/core') +const { Args, Flags, ux } = require('@oclif/core') const BaseCommand = require('../../../BaseCommand') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:registration:get', { provider: 'debug' }) @@ -23,9 +23,9 @@ class GetCommand extends BaseCommand { await this.initSdk() aioLogger.debug(`get registration: ${args.registrationId}`) - cli.action.start(`Retrieving Registration with id ${args.registrationId}`) + ux.action.start(`Retrieving Registration with id ${args.registrationId}`) const registration = await this.eventClient.getRegistration(this.conf.org.id, this.conf.project.id, this.conf.workspace.id, args.registrationId) - cli.action.stop() + ux.action.stop() aioLogger.debug(`get successful, name: ${registration.name}`) if (flags.json) { diff --git a/src/commands/event/registration/list.js b/src/commands/event/registration/list.js index a40b4f5..2c77ddd 100644 --- a/src/commands/event/registration/list.js +++ b/src/commands/event/registration/list.js @@ -9,7 +9,8 @@ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTA OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -const { Flags, ux: cli } = require('@oclif/core') +const { Flags, ux } = require('@oclif/core') +const { table } = require('../../../utils/table') const BaseCommand = require('../../../BaseCommand') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:registration:list', { provider: 'debug' }) @@ -22,9 +23,9 @@ class ListCommand extends BaseCommand { await this.initSdk() aioLogger.debug(`list registrations in the workspace ${this.conf.workspace.id}`) - cli.action.start(`Retrieving Registrations for the Workspace ${this.conf.workspace.id}`) + ux.action.start(`Retrieving Registrations for the Workspace ${this.conf.workspace.id}`) const registrationHalModel = await this.eventClient.getAllRegistrationsForWorkspace(this.conf.org.id, this.conf.project.id, this.conf.workspace.id) - cli.action.stop() + ux.action.stop() aioLogger.debug(`list successful, got ${registrationHalModel._embedded.registrations.length} elements with ids: ${registrationHalModel._embedded.registrations.map(r => r.id)}`) if (flags.json) { this.printJson(registrationHalModel) @@ -32,7 +33,7 @@ class ListCommand extends BaseCommand { this.printYaml(registrationHalModel) } else { // print formatted result - cli.table(registrationHalModel._embedded.registrations, { + table(registrationHalModel._embedded.registrations, { registration_id: { minWidth: 38, header: 'ID' }, name: { minWidth: 25, header: 'NAME' }, enabled: { minWidth: 10, header: 'ENABLED' }, diff --git a/src/utils/table.js b/src/utils/table.js new file mode 100644 index 0000000..40b05bf --- /dev/null +++ b/src/utils/table.js @@ -0,0 +1,57 @@ +/* +Copyright 2020 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +/** + * Renders a simple text table, compatible with the ux.table API removed in @oclif/core v4. + * + * @param {Array} data rows to display + * @param {object} columns column definitions: { key: { header, minWidth } } + * @param {object} options optional options: { printLine } + */ +function table (data, columns, options = {}) { + const printLine = options.printLine || console.log.bind(console) + const headerKeys = Object.keys(columns) + + const colWidths = headerKeys.map(key => { + const col = columns[key] + const header = col.header || key.toUpperCase() + let maxWidth = col.minWidth || header.length + + if (header.length > maxWidth) maxWidth = header.length + data.forEach(row => { + const strValue = String(row[key] ?? '') + if (strValue.length > maxWidth) maxWidth = strValue.length + }) + + const isLastColumn = headerKeys.indexOf(key) === headerKeys.length - 1 + if (col.minWidth && maxWidth === col.minWidth && !isLastColumn) { + maxWidth-- + } + return maxWidth + }) + + const headers = headerKeys.map((key, idx) => + (columns[key].header || key.toUpperCase()).padEnd(colWidths[idx], ' ') + ) + printLine(' ' + headers.join(' ') + ' ') + + const separator = colWidths.map(w => '─'.repeat(w)).join(' ') + printLine(' ' + separator + ' ') + + data.forEach(row => { + const values = headerKeys.map((key, idx) => + String(row[key] ?? '').padEnd(colWidths[idx], ' ') + ) + printLine(' ' + values.join(' ') + ' ') + }) +} + +module.exports = { table } diff --git a/src/utils/validator.js b/src/utils/validator.js index dbbcd44..111a171 100644 --- a/src/utils/validator.js +++ b/src/utils/validator.js @@ -19,7 +19,6 @@ governing permissions and limitations under the License. * @returns {string|boolean} message or error message */ function validator (input, regex, message) { - // eslint-disable-next-line no-useless-escape const valid = regex if (valid.test(input)) { return true diff --git a/test/jest.setup.js b/test/jest.setup.js index f6da9f9..e5648f8 100644 --- a/test/jest.setup.js +++ b/test/jest.setup.js @@ -10,27 +10,6 @@ OF ANY KIND, either express or implied. See the License for the specific languag governing permissions and limitations under the License. */ -jest.mock('@oclif/core/lib/cli-ux/config', () => ({ - fetch: jest.fn(() => Promise.resolve('{}')), - get: jest.fn(() => ({})), - set: jest.fn(), - clear: jest.fn() -})) - -jest.mock('@oclif/core/lib/util', () => { - const actual = jest.requireActual('@oclif/core/lib/util') - return { - ...actual, - requireJson: jest.fn((path) => { - try { - return actual.requireJson(path) - } catch (e) { - return {} - } - }) - } -}) - const mockUx = { action: { start: jest.fn(), @@ -75,20 +54,31 @@ const mockUx = { }) } +const mockConfig = { + runHook: jest.fn().mockResolvedValue({ successes: [], failures: [] }), + bin: 'aio', + userAgent: 'aio', + scopedEnvVar: jest.fn().mockReturnValue(undefined), + scopedEnvVarKey: jest.fn().mockReturnValue(''), + scopedEnvVarKeys: jest.fn().mockReturnValue([]), + theme: null +} + jest.mock('@oclif/core', () => { const actual = jest.requireActual('@oclif/core') + const originalParse = actual.Command.prototype.parse + actual.Command.prototype.parse = function (options, argv) { + if (!this.config) { + this.config = mockConfig + } + return originalParse.call(this, options, argv) + } return { ...actual, ux: mockUx } }) -jest.mock('@oclif/core/lib/cli-ux', () => ({ - ux: mockUx, - cli: mockUx, - default: mockUx -})) - const { stdout, stderr } = require('stdout-stderr') const fs = jest.requireActual('fs') const eol = require('eol') diff --git a/test/utils/table.test.js b/test/utils/table.test.js new file mode 100644 index 0000000..8cc628c --- /dev/null +++ b/test/utils/table.test.js @@ -0,0 +1,76 @@ +/* +Copyright 2020 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +const { table } = require('../../src/utils/table') + +describe('table utility', () => { + test('renders table with header and minWidth columns', () => { + const data = [{ id: 'ID01', label: 'LABEL01' }] + const columns = { + id: { header: 'ID', minWidth: 5 }, + label: { header: 'LABEL', minWidth: 10 } + } + const lines = [] + table(data, columns, { printLine: (l) => lines.push(l) }) + expect(lines).toHaveLength(3) + expect(lines[0]).toContain('ID') + expect(lines[0]).toContain('LABEL') + expect(lines[2]).toContain('ID01') + expect(lines[2]).toContain('LABEL01') + }) + + test('falls back to key.toUpperCase() when header is not provided', () => { + const data = [{ myKey: 'value' }] + const columns = { myKey: {} } + const lines = [] + table(data, columns, { printLine: (l) => lines.push(l) }) + expect(lines[0]).toContain('MYKEY') + }) + + test('falls back to header.length when minWidth is not provided', () => { + const data = [{ name: 'short' }] + const columns = { name: { header: 'LONGHEADER' } } + const lines = [] + table(data, columns, { printLine: (l) => lines.push(l) }) + expect(lines[0]).toContain('LONGHEADER') + }) + + test('handles null and undefined values in rows', () => { + const data = [{ id: null, label: undefined }] + const columns = { + id: { header: 'ID' }, + label: { header: 'LABEL' } + } + const lines = [] + table(data, columns, { printLine: (l) => lines.push(l) }) + expect(lines[2]).toBeDefined() + }) + + test('uses console.log when printLine is not provided', () => { + const spy = jest.spyOn(console, 'log').mockImplementation(() => {}) + const data = [{ id: 'x' }] + const columns = { id: { header: 'ID' } } + table(data, columns) + expect(spy).toHaveBeenCalled() + spy.mockRestore() + }) + + test('decrements maxWidth when minWidth equals maxWidth and not last column', () => { + const data = [{ a: 'x', b: 'y' }] + const columns = { + a: { header: 'A', minWidth: 5 }, + b: { header: 'B', minWidth: 5 } + } + const lines = [] + table(data, columns, { printLine: (l) => lines.push(l) }) + expect(lines).toHaveLength(3) + }) +}) From 059597e43e7c850b2b4c580894126ccee96be897 Mon Sep 17 00:00:00 2001 From: Shazron Abdullah <36107+shazron@users.noreply.github.com> Date: Thu, 26 Mar 2026 01:54:53 +0800 Subject: [PATCH 2/5] update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b356c3c..5a9efe2 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ package-lock.json playground/ oclif.manifest.json .idea +.claude From 17755ba06bf8e638bb60b3ea11b2f2d11afd31d9 Mon Sep 17 00:00:00 2001 From: Shazron Abdullah <36107+shazron@users.noreply.github.com> Date: Tue, 7 Apr 2026 19:19:17 +0800 Subject: [PATCH 3/5] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- eslint.config.js | 11 +++++------ src/commands/event/eventmetadata/list.js | 2 +- src/commands/event/provider/list.js | 2 +- test/utils/table.test.js | 17 +++++++++++++++++ 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index 7e763d3..a09361d 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -32,16 +32,15 @@ module.exports = [ }, { files: ['test/**/*.js'], - ...pluginJest.configs['flat/recommended'], - rules: { - ...pluginJest.configs['flat/recommended'].rules - } + ...pluginJest.configs['flat/recommended'] + }, + { + files: ['e2e/**/*.js'], + ...pluginJest.configs['flat/recommended'] }, { files: ['e2e/**/*.js'], - ...pluginJest.configs['flat/recommended'], rules: { - ...pluginJest.configs['flat/recommended'].rules, 'n/no-unpublished-require': 'off' } } diff --git a/src/commands/event/eventmetadata/list.js b/src/commands/event/eventmetadata/list.js index 4006f6c..24c99b7 100644 --- a/src/commands/event/eventmetadata/list.js +++ b/src/commands/event/eventmetadata/list.js @@ -49,7 +49,7 @@ class EventmetadataListCommand extends BaseCommand { header: 'DESC' } } - table(projects, columns) + table(projects, columns, { printLine: this.log.bind(this) }) } } diff --git a/src/commands/event/provider/list.js b/src/commands/event/provider/list.js index d0860f1..45ae89c 100644 --- a/src/commands/event/provider/list.js +++ b/src/commands/event/provider/list.js @@ -62,7 +62,7 @@ class ProviderListCommand extends BaseCommand { header: 'DOCS' } } - table(projects, columns) + table(projects, columns, { printLine: this.log.bind(this) }) } } diff --git a/test/utils/table.test.js b/test/utils/table.test.js index 8cc628c..98dbed2 100644 --- a/test/utils/table.test.js +++ b/test/utils/table.test.js @@ -72,5 +72,22 @@ describe('table utility', () => { const lines = [] table(data, columns, { printLine: (l) => lines.push(l) }) expect(lines).toHaveLength(3) + + // Verify that the non-last column's effective width is smaller than the last column's, + // reflecting the maxWidth decrement behavior. + const headerLine = lines[0] + const indexA = headerLine.indexOf('A') + const indexB = headerLine.indexOf('B') + + // Sanity checks: both headers should be present in the header line. + expect(indexA).toBeGreaterThanOrEqual(0) + expect(indexB).toBeGreaterThan(indexA) + + const firstColumnSpan = indexB - indexA + const secondColumnSpan = headerLine.length - indexB + + // Because maxWidth is decremented for non-last columns when minWidth === maxWidth, + // the first column's span should be strictly less than the second column's span. + expect(firstColumnSpan).toBeLessThan(secondColumnSpan) }) }) From 0f369e30ac90371b02ddb522c1531cb9e95db535 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 7 Apr 2026 11:25:23 +0000 Subject: [PATCH 4/5] fix: use map index in table.js, remove duplicate mockUx.table from jest.setup.js Agent-Logs-Url: https://github.com/adobe/aio-cli-plugin-events/sessions/88aa020c-1e01-4f0d-9223-390393b038e2 Co-authored-by: shazron <36107+shazron@users.noreply.github.com> --- src/utils/table.js | 4 ++-- test/jest.setup.js | 39 +-------------------------------------- 2 files changed, 3 insertions(+), 40 deletions(-) diff --git a/src/utils/table.js b/src/utils/table.js index 40b05bf..f70aca3 100644 --- a/src/utils/table.js +++ b/src/utils/table.js @@ -20,7 +20,7 @@ function table (data, columns, options = {}) { const printLine = options.printLine || console.log.bind(console) const headerKeys = Object.keys(columns) - const colWidths = headerKeys.map(key => { + const colWidths = headerKeys.map((key, idx) => { const col = columns[key] const header = col.header || key.toUpperCase() let maxWidth = col.minWidth || header.length @@ -31,7 +31,7 @@ function table (data, columns, options = {}) { if (strValue.length > maxWidth) maxWidth = strValue.length }) - const isLastColumn = headerKeys.indexOf(key) === headerKeys.length - 1 + const isLastColumn = idx === headerKeys.length - 1 if (col.minWidth && maxWidth === col.minWidth && !isLastColumn) { maxWidth-- } diff --git a/test/jest.setup.js b/test/jest.setup.js index e5648f8..153e286 100644 --- a/test/jest.setup.js +++ b/test/jest.setup.js @@ -14,44 +14,7 @@ const mockUx = { action: { start: jest.fn(), stop: jest.fn() - }, - table: jest.fn((data, columns, options) => { - const printLine = options?.printLine || console.log.bind(console) - const headerKeys = Object.keys(columns) - - const colWidths = headerKeys.map(key => { - const col = columns[key] - const header = col.header || key.toUpperCase() - let maxWidth = col.minWidth || header.length - - if (header.length > maxWidth) maxWidth = header.length - data.forEach(row => { - const strValue = String(row[key] ?? '') - if (strValue.length > maxWidth) maxWidth = strValue.length - }) - - const isLastColumn = headerKeys.indexOf(key) === headerKeys.length - 1 - if (col.minWidth && maxWidth === col.minWidth && !isLastColumn) { - maxWidth-- - } - return maxWidth - }) - - const headers = headerKeys.map((key, idx) => - (columns[key].header || key.toUpperCase()).padEnd(colWidths[idx], ' ') - ) - printLine(' ' + headers.join(' ') + ' ') - - const separator = colWidths.map(w => '─'.repeat(w)).join(' ') - printLine(' ' + separator + ' ') - - data.forEach(row => { - const values = headerKeys.map((key, idx) => - String(row[key] ?? '').padEnd(colWidths[idx], ' ') - ) - printLine(' ' + values.join(' ') + ' ') - }) - }) + } } const mockConfig = { From 470cd68dfb61dc52c0544651187806e5e508f92b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 7 Apr 2026 11:41:36 +0000 Subject: [PATCH 5/5] fix: update copyright year to 2026 in newly created files Agent-Logs-Url: https://github.com/adobe/aio-cli-plugin-events/sessions/f7431942-967f-48a6-ac9b-db5987b49d51 Co-authored-by: shazron <36107+shazron@users.noreply.github.com> --- eslint.config.js | 2 +- src/utils/table.js | 2 +- test/utils/table.test.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index a09361d..44c830d 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,5 +1,5 @@ /* -Copyright 2020 Adobe. All rights reserved. +Copyright 2026 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/utils/table.js b/src/utils/table.js index f70aca3..ac7d1f5 100644 --- a/src/utils/table.js +++ b/src/utils/table.js @@ -1,5 +1,5 @@ /* -Copyright 2020 Adobe. All rights reserved. +Copyright 2026 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/test/utils/table.test.js b/test/utils/table.test.js index 98dbed2..7517cc2 100644 --- a/test/utils/table.test.js +++ b/test/utils/table.test.js @@ -1,5 +1,5 @@ /* -Copyright 2020 Adobe. All rights reserved. +Copyright 2026 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0