diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 763d64e..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "@adobe/eslint-config-aio-lib-config", - "rules": { - "jsdoc/no-defaults": 0 - }, - "settings": { - "jsdoc": { - "ignorePrivate": true - } - }, - "parserOptions": { - "ecmaVersion": "latest" - } -} \ No newline at end of file diff --git a/.gitignore b/.gitignore index dcc42e5..856f5fd 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ node_modules /test-results.xml coverage/ junit.xml -package-lock.json \ No newline at end of file +package-lock.json +.claude diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..beba83c --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,27 @@ +/* + * Copyright 2022 Adobe Inc. 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 jestPlugin = require('eslint-plugin-jest') + +module.exports = [ + ...aioLibConfig, + { + files: ['test/**/*.js', 'jest.setup.js'], + ...jestPlugin.configs['flat/recommended'] + }, + { + rules: { + 'jsdoc/no-defaults': 'off' + } + } +] diff --git a/package.json b/package.json index 910cff3..1a8ddde 100644 --- a/package.json +++ b/package.json @@ -15,8 +15,9 @@ "@adobe/aio-lib-env": "^3", "@adobe/aio-lib-ims": "^7", "@adobe/aio-lib-templates": "^3", - "@oclif/core": "^1.9.3", + "@oclif/core": "^4.9.0", "chalk": "^4.1.2", + "cli-table3": "^0.6.5", "execa": "^4.1.0", "fs-extra": "^10.1.0", "inquirer": "^8.2.4", @@ -26,24 +27,17 @@ "yeoman-environment": "^4.2.1" }, "devDependencies": { - "@adobe/eslint-config-aio-lib-config": "^4.0.0", + "@adobe/eslint-config-aio-lib-config": "5.0.0", "@types/jest": "^28.1.5", - "acorn": "^7", "cross-env": "^7.0.3", "eol": "^0.9.1", - "eslint": "^8.57.1", - "eslint-config-oclif": "^3.1.0", - "eslint-config-standard": "^17.1.0", - "eslint-plugin-import": "^2.31.0", - "eslint-plugin-jest": "^27.9.0", + "eslint": "^9", + "eslint-plugin-jest": "^29", "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": "^4.0.1", "jest": "^29.7.0", "jest-junit": "^6.0.0", "jest-resolve": "^24.5.0", + "neostandard": "^0", "oclif": "^4.3.6", "stdout-stderr": "^0.1.9" }, @@ -72,8 +66,8 @@ "prepack": "oclif manifest && oclif readme --no-aliases", "postpack": "rm -f oclif.manifest.json", "version": "oclif readme && git add README.md", - "lint:check": "eslint --ext .js .", - "lint:fix": "eslint --ext .js --fix ." + "lint:check": "eslint .", + "lint:fix": "eslint --fix ." }, "jest": { "rootDir": ".", diff --git a/src/BaseCommand.js b/src/BaseCommand.js index 288303f..6afe570 100644 --- a/src/BaseCommand.js +++ b/src/BaseCommand.js @@ -55,6 +55,6 @@ BaseCommand.flags = { verbose: Flags.boolean({ char: 'v', description: 'Verbose output' }) } -BaseCommand.args = [] +BaseCommand.args = {} module.exports = BaseCommand diff --git a/src/commands/templates/discover.js b/src/commands/templates/discover.js index bd6f25a..cc9b9fd 100644 --- a/src/commands/templates/discover.js +++ b/src/commands/templates/discover.js @@ -12,7 +12,8 @@ const BaseCommand = require('../../BaseCommand') const ora = require('ora') -const { Flags, CliUx: { ux: cli } } = require('@oclif/core') +const { Flags } = require('@oclif/core') +const Table = require('cli-table3') const inquirer = require('inquirer') const { TEMPLATE_PACKAGE_JSON_KEY, readPackageJson } = require('../../lib/npm-helper') const { getTemplates } = require('../../lib/template-registry-helper') @@ -91,28 +92,19 @@ class DiscoverCommand extends BaseCommand { day: 'numeric' } - const columns = { - name: { - width: 10, - get: row => `${row.name}` - }, - version: { - minWidth: 10, - get: row => `${row.latestVersion}` - }, - description: { - get: row => `${row.description}` - }, - publishDate: { - header: 'Publish Date', - get: row => `${new Date(row.publishDate).toLocaleDateString('en', options)}` - }, - adobeRecommended: { - header: 'Adobe Recommended', - get: row => row.adobeRecommended ? 'yes' : '' - } + const table = new Table({ + head: ['Name', 'Version', 'Description', 'Publish Date', 'Adobe Recommended'] + }) + for (const row of templates) { + table.push([ + row.name, + row.latestVersion, + row.description, + new Date(row.publishDate).toLocaleDateString('en', options), + row.adobeRecommended ? 'yes' : '' + ]) } - cli.table(templates, columns) + this.log(table.toString()) } async run () { diff --git a/src/commands/templates/install.js b/src/commands/templates/install.js index 44a4f9d..7f10f2a 100644 --- a/src/commands/templates/install.js +++ b/src/commands/templates/install.js @@ -16,7 +16,7 @@ const { writeObjectToPackageJson, readPackageJson, getNpmDependency, processNpmP const { getTemplateRequiredServiceNames } = require('../../lib/template-helper') const ora = require('ora') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-app-templates:templates:install', { provider: 'debug' }) -const { Flags } = require('@oclif/core') +const { Args, Flags } = require('@oclif/core') // aio-lib-console-project-installation dependencies const path = require('path') @@ -45,7 +45,6 @@ class InstallCommand extends BaseCommand { } aioLogger.debug(`templateName: ${templateName}`) - // eslint-disable-next-line node/no-unsupported-features/es-syntax const yeoman = await import('yeoman-environment') const env = yeoman.createEnv() env.options = { skipInstall: !flags.install } @@ -144,13 +143,12 @@ InstallCommand.examples = [ InstallCommand.aliases = ['templates:i'] -InstallCommand.args = [ - { - name: 'path', +InstallCommand.args = { + path: Args.string({ description: 'path to the template (npm package name, file path, url). See examples', required: true - } -] + }) +} InstallCommand.flags = { ...BaseCommand.flags, diff --git a/src/commands/templates/remove.js b/src/commands/templates/remove.js index bca5129..c0eb00f 100644 --- a/src/commands/templates/remove.js +++ b/src/commands/templates/remove.js @@ -10,6 +10,7 @@ * governing permissions and limitations under the License. */ +const { Args } = require('@oclif/core') const BaseCommand = require('../../BaseCommand') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-app-templates:templates:remove', { provider: 'debug' }) const { removeTemplate } = require('../../lib/template-registry-helper') @@ -37,13 +38,12 @@ RemoveCommand.examples = [ RemoveCommand.aliases = ['templates:rm'] -RemoveCommand.args = [ - { - name: 'name', +RemoveCommand.args = { + name: Args.string({ description: 'The name of the package implementing the template on npmjs.com', required: true - } -] + }) +} RemoveCommand.flags = { ...BaseCommand.flags diff --git a/src/commands/templates/rollback.js b/src/commands/templates/rollback.js index 5dbda4e..75c7a0d 100644 --- a/src/commands/templates/rollback.js +++ b/src/commands/templates/rollback.js @@ -10,7 +10,8 @@ * governing permissions and limitations under the License. */ -const { Flags, CliUx: { ux: cli } } = require('@oclif/core') +const { Flags } = require('@oclif/core') +const Table = require('cli-table3') const BaseCommand = require('../../BaseCommand') const inquirer = require('inquirer') const { prompt } = require('../../lib/helper') @@ -24,18 +25,13 @@ class RollbackCommand extends BaseCommand { * @param {Array} templates the installed templates */ async __list (templates) { - const columns = { - template: { - width: 10, - get: row => `${row.name}` - }, - version: { - minWidth: 10, - get: row => `${row.version}` - } + const table = new Table({ + head: ['Template', 'Version'] + }) + for (const row of templates) { + table.push([row.name, row.version]) } - - cli.table(templates, columns) + this.log(table.toString()) } /** diff --git a/src/commands/templates/submit.js b/src/commands/templates/submit.js index dbd03d5..ee7c5f6 100644 --- a/src/commands/templates/submit.js +++ b/src/commands/templates/submit.js @@ -10,6 +10,7 @@ * governing permissions and limitations under the License. */ +const { Args } = require('@oclif/core') const BaseCommand = require('../../BaseCommand') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-app-templates:templates:submit', { provider: 'debug' }) const { addTemplate } = require('../../lib/template-registry-helper') @@ -39,18 +40,16 @@ SubmitCommand.examples = [ SubmitCommand.aliases = ['templates:sub'] -SubmitCommand.args = [ - { - name: 'name', +SubmitCommand.args = { + name: Args.string({ description: 'The name of the package implementing the template on npmjs.com', required: true - }, - { - name: 'githubRepoUrl', + }), + githubRepoUrl: Args.string({ description: "A link to the Github repository containing the package's source code", required: true - } -] + }) +} SubmitCommand.flags = { ...BaseCommand.flags diff --git a/src/commands/templates/uninstall.js b/src/commands/templates/uninstall.js index 85fb2d5..662982d 100644 --- a/src/commands/templates/uninstall.js +++ b/src/commands/templates/uninstall.js @@ -10,6 +10,7 @@ * governing permissions and limitations under the License. */ +const { Args } = require('@oclif/core') const BaseCommand = require('../../BaseCommand') const { runScript } = require('../../lib/helper') const { TEMPLATE_PACKAGE_JSON_KEY, writeObjectToPackageJson, readPackageJson } = require('../../lib/npm-helper') @@ -43,13 +44,12 @@ UninstallCommand.description = 'Uninstall an Adobe Developer App Builder templat UninstallCommand.aliases = ['templates:un'] -UninstallCommand.args = [ - { - name: 'package-name', +UninstallCommand.args = { + 'package-name': Args.string({ description: 'package name of the template', required: true - } -] + }) +} UninstallCommand.flags = { ...BaseCommand.flags diff --git a/test/BaseCommand.test.js b/test/BaseCommand.test.js index b63db38..f0b1593 100644 --- a/test/BaseCommand.test.js +++ b/test/BaseCommand.test.js @@ -50,6 +50,9 @@ test('login', async () => { test('catch', async () => { const cmd = new TheCommand([]) cmd.error = jest.fn() + cmd.config = { + runHook: jest.fn().mockResolvedValue({ successes: [], failures: [] }) + } await cmd.catch(new Error('fake error')) expect(cmd.error).toHaveBeenCalledWith('fake error') }) @@ -57,6 +60,9 @@ test('catch', async () => { test('will change error message when aio templates outside of the application root, verbose', async () => { const cmd = new TheCommand([]) cmd.error = jest.fn() + cmd.config = { + runHook: jest.fn().mockResolvedValue({ successes: [], failures: [] }) + } cmd.argv = ['-v'] const err = new Error('ENOENT: no such file or directory, open \'package.json\'') err.stack = 'mock-stack-trace' @@ -72,6 +78,9 @@ test('will change error message when aio templates outside of the application ro test('will change error message when aio templates outside of the application root', async () => { const cmd = new TheCommand([]) cmd.error = jest.fn() + cmd.config = { + runHook: jest.fn().mockResolvedValue({ successes: [], failures: [] }) + } const err = new Error('ENOENT: no such file or directory, open \'package.json\'') await cmd.catch(err) const errorList = [ diff --git a/test/commands/templates/discover.test.js b/test/commands/templates/discover.test.js index 40587b4..4fb1bec 100644 --- a/test/commands/templates/discover.test.js +++ b/test/commands/templates/discover.test.js @@ -73,9 +73,9 @@ const fakeSupportedOrgServices = [{ code: 'StockSDK', properties: {} }, { code: * @param {Array} splitOutput output split into an array */ function testAllTemplatesAreRendered (splitOutput) { - expect(splitOutput[2]).toMatch('foo') - expect(splitOutput[3]).toMatch('bar') - expect(splitOutput[4]).toMatch('baz') + expect(splitOutput[3]).toMatch('foo') + expect(splitOutput[5]).toMatch('bar') + expect(splitOutput[7]).toMatch('baz') } let command @@ -90,7 +90,8 @@ beforeEach(() => { command = new TheCommand([]) command.error = jest.fn() command.config = { - runCommand: jest.fn() + runCommand: jest.fn(), + runHook: jest.fn().mockResolvedValue({ successes: [], failures: [] }) } command.login = jest.fn() libEnv.getCliEnv.mockReset() @@ -130,7 +131,7 @@ test('flags', async () => { }) test('args', async () => { - expect(TheCommand.args).toEqual([]) + expect(TheCommand.args).toEqual({}) }) describe('sorting', () => { diff --git a/test/commands/templates/index.test.js b/test/commands/templates/index.test.js index 4c30bd5..26e452a 100644 --- a/test/commands/templates/index.test.js +++ b/test/commands/templates/index.test.js @@ -28,7 +28,7 @@ test('flags', async () => { }) test('args', async () => { - expect(TheCommand.args).toEqual([]) + expect(TheCommand.args).toEqual({}) }) describe('instance methods', () => { diff --git a/test/commands/templates/info.test.js b/test/commands/templates/info.test.js index 0b13d43..e0a3655 100644 --- a/test/commands/templates/info.test.js +++ b/test/commands/templates/info.test.js @@ -52,7 +52,7 @@ test('flags', async () => { }) test('args', async () => { - expect(TheCommand.args).toEqual([]) + expect(TheCommand.args).toEqual({}) }) describe('instance methods', () => { @@ -63,6 +63,9 @@ describe('instance methods', () => { getNpmLocalVersion.mockReset() command = new TheCommand([]) + command.config = { + runHook: jest.fn().mockResolvedValue({ successes: [], failures: [] }) + } }) test('indentString', () => { diff --git a/test/commands/templates/install.test.js b/test/commands/templates/install.test.js index d76aca9..dfe6a99 100644 --- a/test/commands/templates/install.test.js +++ b/test/commands/templates/install.test.js @@ -80,6 +80,9 @@ let command beforeEach(() => { command = new TheCommand([]) + command.config = { + runHook: jest.fn().mockResolvedValue({ successes: [], failures: [] }) + } jest.clearAllMocks() }) @@ -123,10 +126,10 @@ test('flags', () => { test('args', async () => { expect(TheCommand.args).toBeDefined() - expect(TheCommand.args).toBeInstanceOf(Array) - expect(TheCommand.args.length).toEqual(1) + expect(TheCommand.args).toBeInstanceOf(Object) + expect(Object.keys(TheCommand.args).length).toEqual(1) - expect(TheCommand.args[0].name).toEqual('path') + expect(TheCommand.args.path).toBeDefined() }) describe('run', () => { diff --git a/test/commands/templates/remove.test.js b/test/commands/templates/remove.test.js index 58ea3a4..c69fb84 100644 --- a/test/commands/templates/remove.test.js +++ b/test/commands/templates/remove.test.js @@ -31,7 +31,8 @@ beforeEach(() => { command = new TheCommand([]) command.error = jest.fn() command.config = { - runCommand: jest.fn() + runCommand: jest.fn(), + runHook: jest.fn().mockResolvedValue({ successes: [], failures: [] }) } command.login = jest.fn() }) @@ -56,9 +57,9 @@ test('flags', async () => { test('args', async () => { expect(TheCommand.args).toBeDefined() - expect(TheCommand.args).toBeInstanceOf(Array) - expect(TheCommand.args.length).toEqual(1) - expect(TheCommand.args[0].name).toEqual('name') + expect(TheCommand.args).toBeInstanceOf(Object) + expect(Object.keys(TheCommand.args).length).toEqual(1) + expect(TheCommand.args.name).toBeDefined() }) test('remove a template', async () => { diff --git a/test/commands/templates/rollback.test.js b/test/commands/templates/rollback.test.js index 1fa1376..57de563 100644 --- a/test/commands/templates/rollback.test.js +++ b/test/commands/templates/rollback.test.js @@ -45,7 +45,8 @@ beforeEach(() => { command = new TheCommand([]) command.config = { - runCommand: jest.fn() + runCommand: jest.fn(), + runHook: jest.fn().mockResolvedValue({ successes: [], failures: [] }) } }) @@ -73,7 +74,7 @@ test('flags', async () => { }) test('args', async () => { - expect(TheCommand.args).toEqual([]) + expect(TheCommand.args).toEqual({}) }) /** @private */ diff --git a/test/commands/templates/submit.test.js b/test/commands/templates/submit.test.js index 29f44de..be47319 100644 --- a/test/commands/templates/submit.test.js +++ b/test/commands/templates/submit.test.js @@ -31,7 +31,8 @@ beforeEach(() => { command = new TheCommand([]) command.error = jest.fn() command.config = { - runCommand: jest.fn() + runCommand: jest.fn(), + runHook: jest.fn().mockResolvedValue({ successes: [], failures: [] }) } command.login = jest.fn() }) @@ -56,11 +57,11 @@ test('flags', async () => { test('args', async () => { expect(TheCommand.args).toBeDefined() - expect(TheCommand.args).toBeInstanceOf(Array) - expect(TheCommand.args.length).toEqual(2) + expect(TheCommand.args).toBeInstanceOf(Object) + expect(Object.keys(TheCommand.args).length).toEqual(2) - expect(TheCommand.args[0].name).toEqual('name') - expect(TheCommand.args[1].name).toEqual('githubRepoUrl') + expect(TheCommand.args.name).toBeDefined() + expect(TheCommand.args.githubRepoUrl).toBeDefined() }) describe('submitting a template', () => { diff --git a/test/commands/templates/uninstall.test.js b/test/commands/templates/uninstall.test.js index bafa6e0..40e02d6 100644 --- a/test/commands/templates/uninstall.test.js +++ b/test/commands/templates/uninstall.test.js @@ -29,6 +29,9 @@ let command beforeEach(() => { command = new TheCommand([]) command.error = jest.fn() + command.config = { + runHook: jest.fn().mockResolvedValue({ successes: [], failures: [] }) + } readPackageJson.mockReset() writeObjectToPackageJson.mockReset() @@ -53,10 +56,10 @@ test('flags', async () => { test('args', async () => { expect(TheCommand.args).toBeDefined() - expect(TheCommand.args).toBeInstanceOf(Array) - expect(TheCommand.args.length).toEqual(1) + expect(TheCommand.args).toBeInstanceOf(Object) + expect(Object.keys(TheCommand.args).length).toEqual(1) - expect(TheCommand.args[0].name).toEqual('package-name') + expect(TheCommand.args['package-name']).toBeDefined() }) describe('run', () => {