Skip to content

Commit

Permalink
chore: Migrate from TSLint to ESLint (#85)
Browse files Browse the repository at this point in the history
* chore: convert to eslint

* chore: fix eslint issues with --fix

* chore: fix eslint issues

* chore: ignore eslint failures for no-await-in-loop

* chore(deps): use correct @types/node for node 8
  • Loading branch information
Chase McCarthy authored Nov 20, 2019
1 parent 17055d1 commit 461e4c6
Show file tree
Hide file tree
Showing 14 changed files with 882 additions and 293 deletions.
7 changes: 6 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
{
"extends": "oclif"
"extends": [
"oclif",
"oclif-typescript"
],
"rules": {
}
}
16 changes: 9 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,20 @@
"@oclif/errors": "^1.2.2",
"@oclif/plugin-help": "^2.1.4",
"@oclif/test": "^1.2.4",
"@oclif/tslint": "^3.1.1",
"@types/chai": "^4.1.7",
"@types/fs-extra": "^5.0.5",
"@types/mocha": "^5.2.6",
"@types/node": "^11.11.4",
"@types/node": "^8.10.59",
"@types/semver": "^5.5.0",
"@types/supports-color": "^5.3.0",
"chai": "^4.2.0",
"eslint": "^6.6.0",
"eslint-config-oclif": "^3.1.0",
"eslint-config-oclif-typescript": "^0.1.0",
"fancy-test": "^1.4.1",
"globby": "^9.1.0",
"mocha": "^6.0.2",
"ts-node": "^8.0.3",
"tslint": "^5.14.0",
"typescript": "^3.3.4000"
},
"engines": {
Expand Down Expand Up @@ -70,12 +71,13 @@
"scripts": {
"build": "rm -rf lib && tsc",
"clean": "rm -f oclif.manifest.json",
"lint": "tsc -p test --noEmit && tslint -p test -t stylish",
"postpublish": "yarn run clean",
"posttest": "yarn run lint",
"lint": "eslint . --ext .ts --config .eslintrc",
"pretest": "tsc -p test --noEmit",
"test": "mocha --forbid-only \"test/**/*.test.ts\"",
"posttest": "yarn lint",
"prepublishOnly": "yarn run build && oclif-dev manifest && oclif-dev readme",
"postpublish": "yarn run clean",
"preversion": "yarn run clean",
"test": "mocha --forbid-only \"test/**/*.test.ts\"",
"version": "oclif-dev readme && git add README.md"
},
"types": "lib/index.d.ts"
Expand Down
16 changes: 9 additions & 7 deletions src/commands/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import {sortBy} from '../../util'

export default class PluginsIndex extends Command {
static flags = {
core: flags.boolean({description: 'show core plugins'})
core: flags.boolean({description: 'show core plugins'}),
}

static description = 'list installed plugins'

static examples = ['$ <%- config.bin %> plugins']

plugins = new Plugins(this.config)
Expand All @@ -22,26 +24,26 @@ export default class PluginsIndex extends Command {
if (!flags.core) {
plugins = plugins.filter(p => p.type !== 'core' && p.type !== 'dev')
}
if (!plugins.length) {
if (plugins.length === 0) {
this.log('no plugins installed')
return
}
this.display(plugins as Plugin[])
}

private display(plugins: Plugin[]) {
for (let plugin of plugins.filter((p: Plugin) => !p.parent)) {
for (const plugin of plugins.filter((p: Plugin) => !p.parent)) {
this.log(this.formatPlugin(plugin))
if (plugin.children && plugin.children.length) {
let tree = this.createTree(plugin)
if (plugin.children && plugin.children.length > 0) {
const tree = this.createTree(plugin)
tree.display(this.log)
}
}
}

private createTree(plugin: Plugin) {
let tree = cli.tree()
for (let p of plugin.children) {
const tree = cli.tree()
for (const p of plugin.children) {
const name = this.formatPlugin(p)
tree.insert(name, this.createTree(p))
}
Expand Down
30 changes: 20 additions & 10 deletions src/commands/plugins/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,43 @@ Installation of a user-installed plugin will override a core plugin.
e.g. If you have a core plugin that has a 'hello' command, installing a user-installed plugin with a 'hello' command will override the core plugin implementation. This is useful if a user needs to update core plugin functionality in the CLI without the need to patch and update the whole CLI.
`

static usage = 'plugins:install PLUGIN...'

static examples = [
'$ <%= config.bin %> plugins:install <%- config.pjson.oclif.examplePlugin || "myplugin" %> ',
'$ <%= config.bin %> plugins:install https://github.com/someuser/someplugin',
'$ <%= config.bin %> plugins:install someuser/someplugin',
]

static strict = false

static args = [{name: 'plugin', description: 'plugin to install', required: true}]

static flags = {
help: flags.help({char: 'h'}),
verbose: flags.boolean({char: 'v'}),
force: flags.boolean({char: 'f', description: 'yarn install with force flag'}),
}

static aliases = ['plugins:add']

plugins = new Plugins(this.config)

// In this case we want these operations to happen
// sequentially so the `no-await-in-loop` rule is ugnored
/* eslint-disable no-await-in-loop */
async run() {
const {flags, argv} = this.parse(PluginsInstall)
if (flags.verbose) this.plugins.verbose = true
const aliases = this.config.pjson.oclif.aliases || {}
for (let name of argv) {
if (aliases[name] === null) this.error(`${name} is blacklisted`)
name = aliases[name] || name
let p = await this.parsePlugin(name)
const p = await this.parsePlugin(name)
let plugin
await this.config.runHook('plugins:preinstall', {
plugin: p
plugin: p,
})
if (p.type === 'npm') {
cli.action.start(`Installing plugin ${chalk.cyan(this.plugins.friendlyName(p.name))}`)
Expand All @@ -51,19 +60,20 @@ e.g. If you have a core plugin that has a 'hello' command, installing a user-ins
cli.action.stop(`installed v${plugin.version}`)
}
}
/* eslint-enable no-await-in-loop */

async parsePlugin(input: string): Promise<{name: string, tag: string, type: 'npm'} | {url: string, type: 'repo'}> {
async parsePlugin(input: string): Promise<{name: string; tag: string; type: 'npm'} | {url: string; type: 'repo'}> {
if (input.includes('@') && input.includes('/')) {
input = input.slice(1)
let [name, tag = 'latest'] = input.split('@')
const [name, tag = 'latest'] = input.split('@')
return {name: '@' + name, tag, type: 'npm'}
} else if (input.includes('/')) {
}
if (input.includes('/')) {
if (input.includes(':')) return {url: input, type: 'repo'}
else return {url: `https://github.com/${input}`, type: 'repo'}
} else {
let [name, tag = 'latest'] = input.split('@')
name = await this.plugins.maybeUnfriendlyName(name)
return {name, tag, type: 'npm'}
return {url: `https://github.com/${input}`, type: 'repo'}
}
const [splitName, tag = 'latest'] = input.split('@')
const name = await this.plugins.maybeUnfriendlyName(splitName)
return {name, tag, type: 'npm'}
}
}
3 changes: 3 additions & 0 deletions src/commands/plugins/link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ e.g. If you have a user-installed or core plugin that has a 'hello' command, ins
`

static usage = 'plugins:link PLUGIN'

static examples = ['$ <%= config.bin %> plugins:link <%- config.pjson.oclif.examplePlugin || "myplugin" %> ']

static args = [{name: 'path', description: 'path to plugin', required: true, default: '.'}]

static flags = {
help: flags.help({char: 'h'}),
verbose: flags.boolean({char: 'v'}),
Expand Down
16 changes: 13 additions & 3 deletions src/commands/plugins/uninstall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,41 @@ import Plugins from '../../plugins'

export default class PluginsUninstall extends Command {
static description = 'removes a plugin from the CLI'

static usage = 'plugins:uninstall PLUGIN...'

static help = `
Example:
$ <%- config.bin %> plugins:uninstall <%- config.pjson.oclif.examplePlugin || "myplugin" %>
`

static variableArgs = true

static args = [{name: 'plugin', description: 'plugin to uninstall'}]

static flags = {
help: flags.help({char: 'h'}),
verbose: flags.boolean({char: 'v'}),
}

static aliases = ['plugins:unlink', 'plugins:remove']

plugins = new Plugins(this.config)

// In this case we want these operations to happen
// sequentially so the `no-await-in-loop` rule is ugnored
/* eslint-disable no-await-in-loop */
async run() {
const {flags, argv} = this.parse(PluginsUninstall)
this.plugins = new Plugins(this.config)
if (flags.verbose) this.plugins.verbose = true
if (!argv.length) argv.push('.')
for (let plugin of argv) {
if (argv.length === 0) argv.push('.')
for (const plugin of argv) {
const friendly = this.plugins.friendlyName(plugin)
cli.action.start(`Uninstalling ${friendly}`)
const unfriendly = await this.plugins.hasPlugin(plugin)
if (!unfriendly) {
let p = this.config.plugins.find(p => p.name === plugin) as Plugin | undefined
const p = this.config.plugins.find(p => p.name === plugin) as Plugin | undefined
if (p) {
if (p && p.parent) return this.error(`${friendly} is installed via plugin ${p.parent!.name}, uninstall ${p.parent!.name} instead`)
}
Expand All @@ -41,4 +50,5 @@ export default class PluginsUninstall extends Command {
cli.action.stop()
}
}
/* eslint-enable no-await-in-loop */
}
3 changes: 3 additions & 0 deletions src/commands/plugins/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ import Plugins from '../../plugins'

export default class PluginsUpdate extends Command {
static topic = 'plugins'

static command = 'update'

static description = 'update installed plugins'

static flags = {
help: flags.help({char: 'h'}),
verbose: flags.boolean({char: 'v'}),
Expand Down
45 changes: 26 additions & 19 deletions src/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ const initPJSON: Config.PJSON.User = {private: true, oclif: {schema: 1, plugins:

export default class Plugins {
verbose = false

readonly yarn: Yarn

private readonly debug: any

constructor(public config: Config.IConfig) {
Expand All @@ -35,9 +37,9 @@ export default class Plugins {
dependencies: {},
...pjson,
}
} catch (err) {
this.debug(err)
if (err.code !== 'ENOENT') process.emitWarning(err)
} catch (error) {
this.debug(error)
if (error.code !== 'ENOENT') process.emitWarning(error)
return initPJSON
}
}
Expand Down Expand Up @@ -80,9 +82,9 @@ export default class Plugins {
await this.add({name, tag: range || tag, type: 'user'})
}
return plugin
} catch (err) {
await this.uninstall(name).catch(err => this.debug(err))
throw err
} catch (error) {
await this.uninstall(name).catch(error => this.debug(error))
throw error
}
}

Expand Down Expand Up @@ -124,40 +126,44 @@ export default class Plugins {
if ((pjson.oclif.plugins || []).find(p => typeof p === 'object' && p.type === 'user' && p.name === name)) {
await this.yarn.exec(['remove', name], {cwd: this.config.dataDir, verbose: this.verbose})
}
} catch (err) {
cli.warn(err)
} catch (error) {
cli.warn(error)
} finally {
await this.remove(name)
}
}

// In this case we want these operations to happen
// sequentially so the `no-await-in-loop` rule is ugnored
/* eslint-disable no-await-in-loop */
async update() {
let plugins = (await this.list()).filter((p): p is Config.PJSON.PluginTypes.User => p.type === 'user')
if (plugins.length === 0) return
cli.action.start(`${this.config.name}: Updating plugins`)

// migrate deprecated plugins
const aliases = this.config.pjson.oclif.aliases || {}
for (let [name, to] of Object.entries(aliases)) {
for (const [name, to] of Object.entries(aliases)) {
const plugin = plugins.find(p => p.name === name)
if (!plugin) continue
if (to) await this.install(to)
await this.uninstall(name)
plugins = plugins.filter(p => p.name !== name)
}

if (plugins.find(p => !!p.url)) {
if (plugins.find(p => Boolean(p.url))) {
await this.yarn.exec(['upgrade'], {cwd: this.config.dataDir, verbose: this.verbose})
}
const npmPlugins = plugins.filter(p => !p.url)
if (npmPlugins.length) {
if (npmPlugins.length > 0) {
await this.yarn.exec(['add', ...npmPlugins.map(p => `${p.name}@${p.tag}`)], {cwd: this.config.dataDir, verbose: this.verbose})
}
for (let p of plugins) {
for (const p of plugins) {
await this.refresh(path.join(this.config.dataDir, 'node_modules', p.name))
}
cli.action.stop()
}
/* eslint-enable no-await-in-loop */

async hasPlugin(name: string) {
const list = await this.list()
Expand All @@ -172,10 +178,10 @@ export default class Plugins {

async yarnNodeVersion(): Promise<string | undefined> {
try {
let f = await loadJSON<{nodeVersion: string}>(path.join(this.config.dataDir, 'node_modules', '.yarn-integrity'))
const f = await loadJSON<{nodeVersion: string}>(path.join(this.config.dataDir, 'node_modules', '.yarn-integrity'))
return f.nodeVersion
} catch (err) {
if (err.code !== 'ENOENT') cli.warn(err)
} catch (error) {
if (error.code !== 'ENOENT') cli.warn(error)
}
}

Expand Down Expand Up @@ -223,11 +229,11 @@ export default class Plugins {
private async npmHasPackage(name: string): Promise<boolean> {
try {
const http: typeof HTTP = require('http-call').HTTP
let url = `${this.npmRegistry}/-/package/${name.replace('/', '%2f')}/dist-tags`
const url = `${this.npmRegistry}/-/package/${name.replace('/', '%2f')}/dist-tags`
await http.get(url)
return true
} catch (err) {
this.debug(err)
} catch (error) {
this.debug(error)
return false
}
}
Expand All @@ -242,7 +248,8 @@ export default class Plugins {
let plugins = (input || []).map(p => {
if (typeof p === 'string') {
return {name: p, type: 'user', tag: 'latest'} as Config.PJSON.PluginTypes.User
} else return p
}
return p
})
plugins = uniqWith(plugins, (a, b) => a.name === b.name || (a.type === 'link' && b.type === 'link' && a.root === b.root))
return plugins
Expand Down
2 changes: 1 addition & 1 deletion src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export function sortBy<T>(arr: T[], fn: (i: T) => sortBy.Types | sortBy.Types[])

if (Array.isArray(a) && Array.isArray(b)) {
if (a.length === 0 && b.length === 0) return 0
let diff = compare(a[0], b[0])
const diff = compare(a[0], b[0])
if (diff !== 0) return diff
return compare(a.slice(1), b.slice(1))
}
Expand Down
Loading

0 comments on commit 461e4c6

Please sign in to comment.