Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .eslintignore

This file was deleted.

45 changes: 0 additions & 45 deletions .eslintrc

This file was deleted.

80 changes: 80 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { defineConfig, globalIgnores } from 'eslint/config'
import eslintPluginImport from 'eslint-plugin-import'
import eslintPluginN from 'eslint-plugin-n'
import eslintPluginPromise from 'eslint-plugin-promise'
import globals from 'globals'
import standard from 'eslint-config-standard'
import tseslint from 'typescript-eslint'

export default defineConfig([
Copy link

Copilot AI Oct 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 'defineConfig' wrapper is unnecessary in ESLint v9 flat config. The configuration should be exported as a plain array. Replace 'defineConfig([...])' with just the array: 'export default [...]'.

Copilot uses AI. Check for mistakes.
{
languageOptions: {
parserOptions: {
ecmaFeatures: standard.parserOptions.ecmaFeatures,
ecmaVersion: 2022
},
globals: {
...globals.es2021,
...globals.node,
document: 'readonly',
navigator: 'readonly',
window: 'readonly'
}
},
name: 'zcli/standard',
plugins: {
import: eslintPluginImport,
n: eslintPluginN,
promise: eslintPluginPromise
},
rules: {
...standard.rules,
'no-unused-expressions': ['error', {
allowShortCircuit: true,
allowTernary: true,
allowTaggedTemplates: true
}]
}
},
{
extends: [tseslint.configs.recommended],
files: ['**/*.ts', '**/*.test.ts'],
languageOptions: {
parser: tseslint.parser,
parserOptions: {
sourceType: 'module'
}
},
name: 'zcli/monorepo',
rules: {
'@typescript-eslint/no-unused-expressions': ['error', {
allowShortCircuit: true,
allowTernary: true,
allowTaggedTemplates: true
}],
'@typescript-eslint/camelcase': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-unused-vars': [2, { argsIgnorePattern: '^_', varsIgnorePattern: '^_.+', caughtErrorsIgnorePattern: '^_.+' }],
'eol-last': ['error', 'always'],
'space-before-blocks': ['error', 'always'],
camelcase: 'off',
indent: ['error', 2],
semi: 'off'
}
},
{
files: ['**/*.test.ts'],
languageOptions: {
globals: globals.mocha,
parser: tseslint.parser,
parserOptions: {
sourceType: 'module'
}
},
name: 'zcli/tests'
},
globalIgnores([
'node_modules',
'packages/**/node_modules'
])
Comment on lines +76 to +79
Copy link

Copilot AI Oct 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 'globalIgnores' helper is not a standard ESLint v9 export. Use the 'ignores' property directly in a configuration object instead: { ignores: ['node_modules', 'packages/**/node_modules'] }.

Copilot uses AI. Check for mistakes.
])
17 changes: 8 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,15 @@
"@oclif/test": "=2.1.0",
"@types/chai": "^4",
"@types/express": "^4.17.3",
"@types/glob": "^8.1.0",
"@types/mocha": "^9.1.1",
"@types/node": "^14.0.14",
"@types/glob": "^8.1.0",
"@typescript-eslint/eslint-plugin": "^5.30.0",
"@typescript-eslint/parser": "^5.30.0",
"chai": "^4",
"eslint": "^8.18.0",
"eslint-config-standard": "^17.0.0",
"eslint-plugin-import": "2",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.0.0",
"eslint": "^9.36.0",
"eslint-config-standard": "^17.1.0",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-n": "^17.23.1",
"eslint-plugin-promise": "^7.2.1",
"form-data": "^4.0.0",
"lerna": "^5.6.2",
"lerna-changelog": "^2.2.0",
Expand All @@ -32,6 +30,7 @@
"standard": "^17.0.0",
"ts-node": "^10.9.1",
"typescript": "~4.7.4",
"typescript-eslint": "^8.44.1",
"yarn-audit-fix": "^10.1.1"
},
"engines": {
Expand All @@ -49,7 +48,7 @@
"dev": "ts-node ./packages/zcli/bin/run",
"git:check": "./scripts/git_check.sh",
"link:bin": "bash ./scripts/link_dev.sh",
"lint": "eslint . --ext .ts --config .eslintrc",
"lint": "eslint",
"test": "nyc --extension .ts mocha --config=.mocharc.json --forbid-only packages/**/src/**/*.test.ts",
"test:functional": "mocha --config=.mocharc.json -r ts-node/register packages/**/tests/**/*.test.ts",
"changelog": "lerna-changelog",
Expand Down
2 changes: 1 addition & 1 deletion packages/zcli-apps/src/commands/apps/clean.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default class Clean extends Command {
try {
await cleanDirectory(tmpDirectoryPath)
this.log(chalk.green(`Successfully removed ${tmpDirectoryPath} directory.`))
} catch (error) {
} catch (_error) {
this.error(chalk.red(`Failed to remove ${tmpDirectoryPath} directory.`))
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/zcli-apps/src/commands/apps/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export default class Create extends Command {
const { job_id } = await deployApp('POST', 'api/apps.json', upload_id, manifest.name)

try {
const { app_id }: any = await getUploadJobStatus(job_id, appPath)
const { app_id }: { app_id: string } = await getUploadJobStatus(job_id, appPath)
CliUx.ux.action.stop('Deployed')

const allConfigs = getAllConfigs(appPath)
Expand Down
2 changes: 1 addition & 1 deletion packages/zcli-apps/src/commands/apps/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default class Update extends Command {
const { job_id } = await deployApp('PUT', `api/v2/apps/${appID}`, uploadId)

try {
const { app_id }: any = await getUploadJobStatus(job_id, appPath)
const { app_id }: { app_id: string } = await getUploadJobStatus(job_id, appPath)
CliUx.ux.action.stop('Deployed')
if (!manifest.requirementsOnly && manifest.location) {
Object.keys(manifest.location).forEach(async product => {
Expand Down
6 changes: 3 additions & 3 deletions packages/zcli-apps/src/lib/buildAppJSON.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ describe('buildAppJSON', () => {
const mockId = '1'

test
.stub(appPath, 'validateAppPath', () => {}) // eslint-disable-line @typescript-eslint/no-empty-function
.stub(appPath, 'validateAppPath', () => {})
.stub(manifest, 'getManifestFile', () => manifestOutput)
.stub(appConfig, 'getAllConfigs', () => ({
app_id: '234',
Expand Down Expand Up @@ -328,7 +328,7 @@ describe('buildAppJSON', () => {

describe('for non private apps', () => {
test
.stub(appPath, 'validateAppPath', () => {}) // eslint-disable-line @typescript-eslint/no-empty-function
.stub(appPath, 'validateAppPath', () => {})
.stub(manifest, 'getManifestFile', () => manifestOutputNoParams)
.stub(uuid, 'uuidV4', () => mockId)
.stub(buildAppJSON, 'getLocationIcons', () => { return multiProductLocationIcons })
Expand Down Expand Up @@ -370,7 +370,7 @@ describe('buildAppJSON', () => {

describe('with no params attribute on manifest file', () => {
test
.stub(appPath, 'validateAppPath', () => {}) // eslint-disable-line @typescript-eslint/no-empty-function
.stub(appPath, 'validateAppPath', () => {})
.stub(manifest, 'getManifestFile', () => manifestOutputNoParams)
.stub(appConfig, 'getAllConfigs', () => ({
app_id: '234',
Expand Down
19 changes: 10 additions & 9 deletions packages/zcli-apps/src/lib/buildAppJSON.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export const getLocationIcons = (appPath: string, manifestLocations: Location =
}, {})
}

export const getInstallation = (appId: string, app: App, configFileContents: ZcliConfigFileContent, appSettings: Array<Record<string, any>>): Installation => {
export const getInstallation = (appId: string, app: App, configFileContents: ZcliConfigFileContent, appSettings: Array<Record<string, unknown>>): Installation => {
const installationId = configFileContents.installation_id || uuidV4()

return {
Expand All @@ -73,20 +73,21 @@ const mergeLocationAndIcons = (locations: Location, locationIcons: LocationIcons
for (const locationName in locationIcons[product]) {
if (typeof (locations[product][locationName]) === 'string') {
locations[product][locationName] = {
url: locations[product][locationName]
url: locations[product][locationName] as string
}
}

Copy link

Copilot AI Oct 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] This blank line appears to be unintentionally added. Consider removing it to maintain consistent spacing with the surrounding code.

Suggested change

Copilot uses AI. Check for mistakes.
if (locationIcons[product][locationName].svg) {
locations[product][locationName].svg = locationIcons[product][locationName].svg
(locations[product][locationName] as { svg: string }).svg = locationIcons[product][locationName].svg
}
if (locationIcons[product][locationName].active) {
locations[product][locationName].active = locationIcons[product][locationName].active
(locations[product][locationName] as { active: string }).active = locationIcons[product][locationName].active
}
if (locationIcons[product][locationName].inactive) {
locations[product][locationName].inactive = locationIcons[product][locationName].inactive
(locations[product][locationName] as { inactive: string }).inactive = locationIcons[product][locationName].inactive
}
if (locationIcons[product][locationName].hover) {
locations[product][locationName].hover = locationIcons[product][locationName].hover
(locations[product][locationName] as { hover: string }).hover = locationIcons[product][locationName].hover
}
}
}
Expand All @@ -95,7 +96,7 @@ const mergeLocationAndIcons = (locations: Location, locationIcons: LocationIcons
for (const locationName in locations[product]) {
if (typeof (locations[product][locationName]) === 'string') {
locations[product][locationName] = {
url: locations[product][locationName]
url: locations[product][locationName] as string
}
}
}
Expand All @@ -122,8 +123,8 @@ export const getAppPayloadFromManifest = (appManifest: Manifest, port: number, a
return appPayload
}

const getSettingsArr = (appSettings: any) => {
const s: any[] = []
const getSettingsArr = (appSettings: Record<string, string>) => {
const s: Record<string, string>[] = []
Object.keys(appSettings).forEach((settingName: string) => {
const setting: Record<string, string> = {}
setting[settingName] = appSettings[settingName]
Expand Down
8 changes: 4 additions & 4 deletions packages/zcli-apps/src/lib/package.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ describe('package', () => {
.it('should throw if package has validation errors', async () => {
try {
await validatePkg('./app-path')
} catch (error: any) {
expect(error.message).to.equal('invalid location')
} catch (error: unknown) {
expect((error as Error).message).to.equal('invalid location')
}
})

Expand All @@ -31,8 +31,8 @@ describe('package', () => {
.it('should throw if app path is invalid', async () => {
try {
await validatePkg('./bad-path')
} catch (error: any) {
expect(error.message).to.equal('Package not found at ./bad-path')
} catch (error: unknown) {
expect((error as Error).message).to.equal('Package not found at ./bad-path')
}
})
})
Expand Down
12 changes: 9 additions & 3 deletions packages/zcli-apps/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@ export type Dictionary<T> = {

// Begin AppJSON definitions
export interface AppLocation {
[appLocation: string]: any;
[appLocation: string]: string | {
active?: string;
hover?: string;
inactive?: string;
svg?: string;
url: string;
};
}

export interface IconLocationAllowlist {
Expand Down Expand Up @@ -107,8 +113,8 @@ export interface Installation {
enabled: boolean;
id: string;
plan?: string;
requirements: Array<Record<string, any>>;
settings: Array<Record<string, any>>;
requirements: Array<Record<string, unknown>>;
settings: Array<Record<string, unknown>>;
updated_at: string;
}

Expand Down
2 changes: 1 addition & 1 deletion packages/zcli-apps/src/utils/appConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const getAllConfigs = (appPath: string, configFileName: string = DEFAULT_
const zcliConfigFile = fs.readFileSync(configFilePath, 'utf8')
try {
return JSON.parse(zcliConfigFile)
} catch (error) {
} catch (_error) {
throw new CLIError(chalk.red(`zcli configuration file was malformed at path: ${configFilePath}`))
}
}
Expand Down
4 changes: 2 additions & 2 deletions packages/zcli-apps/src/utils/createApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const getManifestAppName = (appPath: string): string | undefined => {
return getManifestFile(appPath).name
}

export const uploadAppPkg = async (pkgPath: string): Promise<any> => {
export const uploadAppPkg = async (pkgPath: string): Promise<{ id: number }> => {
const pkgBuffer = await fs.readFile(pkgPath)

const formData = new FormData()
Expand Down Expand Up @@ -63,7 +63,7 @@ export const deployApp = async (method: string, url: string, upload_id: number,
return installationResponse.data
}

export const createProductInstallation = async (settings: any, manifest: Manifest, app_id: string, product: string): Promise<boolean> => {
export const createProductInstallation = async (settings: Record<string, unknown>, manifest: Manifest, app_id: string, product: string): Promise<boolean> => {
const installResponse = await request.requestAPI(`api/${product}/apps/installations.json`, {
method: 'POST',
data: JSON.stringify({ app_id: `${app_id}`, settings: { name: manifest.name, ...settings } }),
Expand Down
2 changes: 1 addition & 1 deletion packages/zcli-apps/src/utils/uploadApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { request } from '@zendesk/zcli-core'
import { getAppSettings } from './getAppSettings'
import { Manifest, Installations, ZcliConfigFileContent } from '../types'

export const getUploadJobStatus = async (job_id: string, appPath: string, pollAfter = 1000) => new Promise((resolve, reject) => {
export const getUploadJobStatus = async (job_id: string, appPath: string, pollAfter = 1000) => new Promise<{ status: string, message: string, app_id: string }>((resolve, reject) => {
const polling = setInterval(async () => {
const res = await request.requestAPI(`api/v2/apps/job_statuses/${job_id}`, { method: 'GET' })
const { status, message, app_id } = await res.data
Expand Down
2 changes: 1 addition & 1 deletion packages/zcli-apps/tests/functional/server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import * as fs from 'fs'
import { omit } from 'lodash'
import ServerCommand from '../../src/commands/apps/server'
import { AppJSONPayload, Manifest } from '../../src/types'
const appJSONSnapshot = require('./mocks/snapshot_app') // eslint-disable-line @typescript-eslint/no-var-requires
const appJSONSnapshot = require('./mocks/snapshot_app') // eslint-disable-line @typescript-eslint/no-require-imports

describe('apps server', function () {
const singleProductApp = path.join(__dirname, 'mocks/single_product_app')
Expand Down
2 changes: 1 addition & 1 deletion packages/zcli-core/src/lib/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ export const EnvVars = {
APP_ID: 'ZENDESK_APP_ID'
}

export const varExists = (...args: any[]) => !args.filter(envVar => !process.env[envVar]).length
export const varExists = (...args: string[]) => !args.filter(envVar => !process.env[envVar]).length
2 changes: 1 addition & 1 deletion packages/zcli-core/src/lib/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const createRequestConfig = async (url: string, options: any = {}) => {
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const requestAPI = async (url: string, options: any = {}, json = false) => {
export const requestAPI = async (url: string, options: any = {}, _json = false) => {
const requestConfig = await createRequestConfig(url, options)
return axios.request({
...requestConfig,
Expand Down
4 changes: 2 additions & 2 deletions packages/zcli-core/src/lib/secretType.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export enum SecretType {
// eslint-disable-next-line no-unused-vars
TOKEN = 'token', PASSWORD = 'password'
PASSWORD = 'password',
TOKEN = 'token'
}
Loading