Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: remove support for baseFlags #1084

Merged
merged 8 commits into from
May 23, 2024
Merged
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
6 changes: 5 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ jobs:
matrix:
os: [ubuntu-latest, windows-latest]
node_version: [lts/*, latest]
test: [esm, cjs, precore, coreV1, coreV2, esbuild]
test: [esm, cjs, precore, coreV1, coreV2, coreV3, esbuild]
dev_runtime: [default, bun, tsx]
exclude:
- os: windows-latest
Expand All @@ -99,6 +99,10 @@ jobs:
dev_runtime: tsx
- test: coreV2
dev_runtime: bun
- test: coreV3
dev_runtime: tsx
- test: coreV3
dev_runtime: bun
fail-fast: false
runs-on: ${{ matrix.os }}
timeout-minutes: 75
Expand Down
9 changes: 4 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"@oclif/plugin-help": "^6",
"@oclif/plugin-plugins": "^5",
"@oclif/prettier-config": "^0.2.1",
"@oclif/test": "^4",
"@types/benchmark": "^2.1.5",
"@types/chai": "^4.3.11",
"@types/chai-as-promised": "^7.1.8",
Expand Down Expand Up @@ -57,7 +58,7 @@
"nyc": "^15.1.0",
"prettier": "^3.2.5",
"shx": "^0.3.4",
"sinon": "^17",
"sinon": "^18",
"ts-node": "^10.9.2",
"tsd": "^0.31.0",
"typescript": "^5"
Expand Down Expand Up @@ -112,20 +113,18 @@
},
"scripts": {
"build": "shx rm -rf lib && tsc",
"commitlint": "commitlint",
"compile": "tsc",
"format": "prettier --write \"+(src|test)/**/*.+(ts|js|json)\"",
"lint": "eslint . --ext .ts",
"posttest": "yarn lint && yarn test:circular-deps",
"prepack": "yarn run build",
"prepare": "husky",
"pretest": "yarn build && tsc -p test --noEmit --skipLibCheck",
"test:circular-deps": "madge lib/ -c",
"test:circular-deps": "yarn build && madge lib/ -c",
"test:debug": "nyc mocha --debug-brk --inspect \"test/**/*.test.ts\"",
"test:integration": "mocha --forbid-only \"test/**/*.integration.ts\" --parallel --timeout 1200000",
"test:interoperability": "cross-env DEBUG=integration:* ts-node test/integration/interop.ts",
"test:perf": "ts-node test/perf/parser.perf.ts",
"test": "nyc mocha --forbid-only \"test/**/*.test.ts\""
"test": "nyc mocha --forbid-only \"test/**/*.test.ts\" --parallel"
},
"types": "lib/index.d.ts"
}
8 changes: 4 additions & 4 deletions src/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import {readFileSync} from 'node:fs'
import {join} from 'node:path'

import {Config} from './config/config'
import {Configuration, Plugin} from './interfaces'
import {OclifConfiguration, Plugin} from './interfaces'

type OclifCoreInfo = {name: string; version: string}

type CacheContents = {
rootPlugin: Plugin
config: Config
exitCodes: Configuration['exitCodes']
exitCodes: OclifConfiguration['exitCodes']
'@oclif/core': OclifCoreInfo
}

Expand All @@ -36,7 +36,7 @@ export default class Cache extends Map<keyof CacheContents, ValueOf<CacheContent
public get(key: 'config'): Config | undefined
public get(key: '@oclif/core'): OclifCoreInfo
public get(key: 'rootPlugin'): Plugin | undefined
public get(key: 'exitCodes'): Configuration['exitCodes'] | undefined
public get(key: 'exitCodes'): OclifConfiguration['exitCodes'] | undefined
public get(key: keyof CacheContents): ValueOf<CacheContents> | undefined {
return super.get(key)
}
Expand All @@ -48,7 +48,7 @@ export default class Cache extends Map<keyof CacheContents, ValueOf<CacheContent
try {
return {
name: '@oclif/core',
version: JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8')),
version: JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8')).version,
}
} catch {
return {name: '@oclif/core', version: 'unknown'}
Expand Down
19 changes: 10 additions & 9 deletions src/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@ export abstract class Command {
/** An order-dependent object of arguments for the command */
public static args: ArgInput = {}

public static baseFlags: FlagInput

/**
* Emit deprecation warning when a command alias is used
*/
Expand Down Expand Up @@ -172,6 +170,9 @@ export abstract class Command {
}

const config = await Config.load(opts || require.main?.filename || __dirname)
const cache = Cache.getInstance()
if (!cache.has('config')) cache.set('config', config)

const cmd = new this(argv, config)
if (!cmd.id) {
const id = cmd.constructor.name.toLowerCase()
Expand Down Expand Up @@ -264,16 +265,16 @@ export abstract class Command {
}
}

protected async parse<F extends FlagOutput, B extends FlagOutput, A extends ArgOutput>(
options?: Input<F, B, A>,
protected async parse<F extends FlagOutput, A extends ArgOutput>(
options?: Input<F, A>,
argv = this.argv,
): Promise<ParserOutput<F, B, A>> {
if (!options) options = this.ctor as Input<F, B, A>
): Promise<ParserOutput<F, A>> {
if (!options) options = this.ctor as Input<F, A>

const opts = {
context: this,
...options,
flags: aggregateFlags<F, B>(options.flags, options.baseFlags, options.enableJsonFlag),
flags: aggregateFlags<F>(options.flags, options.enableJsonFlag),
}

const hookResult = await this.config.runHook('preparse', {argv: [...argv], options: opts})
Expand All @@ -284,7 +285,7 @@ export abstract class Command {
? hookResult.successes.find((s) => s.plugin.root === Cache.getInstance().get('rootPlugin')?.root)?.result ?? argv
: argv
this.argv = [...argvToParse]
const results = await Parser.parse<F, B, A>(argvToParse, opts)
const results = await Parser.parse<F, A>(argvToParse, opts)
this.warnIfFlagDeprecated(results.flags ?? {})

return results
Expand Down Expand Up @@ -319,7 +320,7 @@ export abstract class Command {
}

protected warnIfFlagDeprecated(flags: Record<string, unknown>): void {
const allFlags = aggregateFlags(this.ctor.flags, this.ctor.baseFlags, this.ctor.enableJsonFlag)
const allFlags = aggregateFlags(this.ctor.flags, this.ctor.enableJsonFlag)
for (const flag of Object.keys(flags)) {
const flagDef = allFlags[flag]
const deprecated = flagDef?.deprecated
Expand Down
77 changes: 13 additions & 64 deletions src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ import Cache from '../cache'
import {Command} from '../command'
import {CLIError, error, exit, warn} from '../errors'
import {getHelpFlagAdditions} from '../help/util'
import {Configuration, Hook, Hooks, PJSON, S3Templates, Topic, UserPJSON} from '../interfaces'
import {Hook, Hooks, OclifConfiguration, PJSON, S3Templates, Topic, UserPJSON} from '../interfaces'
import {ArchTypes, Config as IConfig, LoadOptions, PlatformTypes, VersionDetails} from '../interfaces/config'
import {Plugin as IPlugin, Options} from '../interfaces/plugin'
import {Theme} from '../interfaces/theme'
import {makeDebug as loggerMakeDebug, setLogger} from '../logger'
import {loadWithData} from '../module-loader'
import {OCLIF_MARKER_OWNER, Performance} from '../performance'
import {settings} from '../settings'
import {determinePriority} from '../util/determine-priority'
import {safeReadJson} from '../util/fs'
import {getHomeDir, getPlatform} from '../util/os'
import {compact, isProd} from '../util/util'
Expand Down Expand Up @@ -103,7 +104,7 @@ export class Config implements IConfig {
public shell!: string
public theme?: Theme | undefined
public topicSeparator: ' ' | ':' = ':'
public updateConfig!: NonNullable<Configuration['update']>
public updateConfig!: NonNullable<OclifConfiguration['update']>
public userAgent!: string
public userPJSON?: UserPJSON | undefined
public valid!: boolean
Expand Down Expand Up @@ -600,7 +601,7 @@ export class Config implements IConfig {
): string {
if (typeof ext === 'object') options = ext
else if (ext) options.ext = ext
const template = this.updateConfig.s3.templates?.[options.platform ? 'target' : 'vanilla'][type] ?? ''
const template = this.updateConfig.s3?.templates?.[options.platform ? 'target' : 'vanilla'][type] ?? ''
return ejs.render(template, {...(this as any), ...options})
}

Expand Down Expand Up @@ -702,64 +703,6 @@ export class Config implements IConfig {
}
}

/**
* This method is responsible for locating the correct plugin to use for a named command id
* It searches the {Config} registered commands to match either the raw command id or the command alias
* It is possible that more than one command will be found. This is due the ability of two distinct plugins to
* create the same command or command alias.
*
* In the case of more than one found command, the function will select the command based on the order in which
* the plugin is included in the package.json `oclif.plugins` list. The command that occurs first in the list
* is selected as the command to run.
*
* Commands can also be present from either an install or a link. When a command is one of these and a core plugin
* is present, this function defers to the core plugin.
*
* If there is not a core plugin command present, this function will return the first
* plugin as discovered (will not change the order)
*
* @param commands commands to determine the priority of
* @returns command instance {Command.Loadable} or undefined
*/
private determinePriority(commands: Command.Loadable[]): Command.Loadable {
const oclifPlugins = this.pjson.oclif?.plugins ?? []
const commandPlugins = commands.sort((a, b) => {
const pluginAliasA = a.pluginAlias ?? 'A-Cannot-Find-This'
const pluginAliasB = b.pluginAlias ?? 'B-Cannot-Find-This'
const aIndex = oclifPlugins.indexOf(pluginAliasA)
const bIndex = oclifPlugins.indexOf(pluginAliasB)
// When both plugin types are 'core' plugins sort based on index
if (a.pluginType === 'core' && b.pluginType === 'core') {
// If b appears first in the pjson.plugins sort it first
return aIndex - bIndex
}

// if b is a core plugin and a is not sort b first
if (b.pluginType === 'core' && a.pluginType !== 'core') {
return 1
}

// if a is a core plugin and b is not sort a first
if (a.pluginType === 'core' && b.pluginType !== 'core') {
return -1
}

// if a is a jit plugin and b is not sort b first
if (a.pluginType === 'jit' && b.pluginType !== 'jit') {
return 1
}

// if b is a jit plugin and a is not sort a first
if (b.pluginType === 'jit' && a.pluginType !== 'jit') {
return -1
}

// neither plugin is core, so do not change the order
return 0
})
return commandPlugins[0]
}

private getCmdLookupId(id: string): string {
if (this._commands.has(id)) return id
if (this.commandPermutations.hasValid(id)) return this.commandPermutations.getValid(id)!
Expand All @@ -786,7 +729,7 @@ export class Config implements IConfig {
this.plugins.set(plugin.name, plugin)

// Delete all commands from the legacy plugin so that we can re-add them.
// This is necessary because this.determinePriority will pick the initial
// This is necessary because determinePriority will pick the initial
// command that was added, which won't have been converted by PluginLegacy yet.
for (const cmd of plugin.commands ?? []) {
this._commands.delete(cmd.id)
Expand All @@ -812,7 +755,10 @@ export class Config implements IConfig {
for (const command of plugin.commands) {
// set canonical command id
if (this._commands.has(command.id)) {
const prioritizedCommand = this.determinePriority([this._commands.get(command.id)!, command])
const prioritizedCommand = determinePriority(this.pjson.oclif.plugins ?? [], [
this._commands.get(command.id)!,
command,
])
this._commands.set(prioritizedCommand.id, prioritizedCommand)
} else {
this._commands.set(command.id, command)
Expand All @@ -831,7 +777,10 @@ export class Config implements IConfig {

const handleAlias = (alias: string, hidden = false) => {
if (this._commands.has(alias)) {
const prioritizedCommand = this.determinePriority([this._commands.get(alias)!, command])
const prioritizedCommand = determinePriority(this.pjson.oclif.plugins ?? [], [
this._commands.get(alias)!,
command,
])
this._commands.set(alias, {...prioritizedCommand, id: alias})
} else {
this._commands.set(alias, {...command, hidden, id: alias})
Expand Down
8 changes: 4 additions & 4 deletions src/config/plugin-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {Plugin as IPlugin, Options} from '../interfaces/plugin'
import {OCLIF_MARKER_OWNER, Performance} from '../performance'
import {readJson} from '../util/fs'
import {isProd} from '../util/util'
import * as Plugin from './plugin'
import {Plugin} from './plugin'
import {makeDebug} from './util'

const debug = makeDebug()
Expand Down Expand Up @@ -66,7 +66,7 @@ export default class PluginLoader {
rootPlugin = plugins.find((p) => p.root === this.options.root) ?? plugins[0]
} else {
const marker = Performance.mark(OCLIF_MARKER_OWNER, 'plugin.load#root')
rootPlugin = new Plugin.Plugin({isRoot: true, pjson, root: this.options.root})
rootPlugin = new Plugin({isRoot: true, pjson, root: this.options.root})
await rootPlugin.load()
marker?.addDetails({
commandCount: rootPlugin.commands.length,
Expand Down Expand Up @@ -140,7 +140,7 @@ export default class PluginLoader {
root: string,
type: string,
plugins: ({name?: string; root?: string; tag?: string; url?: string} | string)[],
parent?: Plugin.Plugin,
parent?: Plugin,
): Promise<void> {
if (!plugins || plugins.length === 0) return
const mark = Performance.mark(OCLIF_MARKER_OWNER, `config.loadPlugins#${type}`)
Expand All @@ -166,7 +166,7 @@ export default class PluginLoader {

if (this.plugins.has(name)) return
const pluginMarker = Performance.mark(OCLIF_MARKER_OWNER, `plugin.load#${name}`)
const instance = new Plugin.Plugin(opts)
const instance = new Plugin(opts)
await instance.load()
pluginMarker?.addDetails({
commandCount: instance.commands.length,
Expand Down
4 changes: 2 additions & 2 deletions src/interfaces/config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Command} from '../command'
import {Hook, Hooks} from './hooks'
import {Configuration, PJSON, S3Templates} from './pjson'
import {OclifConfiguration, PJSON, S3Templates} from './pjson'
import {Options, Plugin} from './plugin'
import {Theme} from './theme'
import {Topic} from './topic'
Expand Down Expand Up @@ -115,7 +115,7 @@ export interface Config {
readonly theme?: Theme | undefined
topicSeparator: ' ' | ':'
readonly topics: Topic[]
readonly updateConfig: NonNullable<Configuration['update']>
readonly updateConfig: NonNullable<OclifConfiguration['update']>
/**
* user agent to use for http calls
*
Expand Down
5 changes: 3 additions & 2 deletions src/interfaces/flags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import {FlagInput} from './parser'
* Infer the flags that are returned by Command.parse. This is useful for when you want to assign the flags as a class property.
*
* @example
* export type StatusFlags = Interfaces.InferredFlags<typeof Status.flags & typeof Status.baseFlags>
* export type StatusFlags = Interfaces.InferredFlags<typeof Status.flags>
*
* export abstract class BaseCommand extends Command {
* static enableJsonFlag = true
*
* static baseFlags = {
* static flags = {
* config: Flags.string({
* description: 'specify config file',
* }),
Expand All @@ -18,6 +18,7 @@ import {FlagInput} from './parser'
*
* export default class Status extends BaseCommand {
* static flags = {
* ...BaseCommand.flags,
* force: Flags.boolean({char: 'f', description: 'a flag'}),
* }
*
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export interface Hooks {
preparse: {
options: {
argv: string[]
options: Input<OutputFlags<any>, OutputFlags<any>, OutputFlags<any>>
options: Input<OutputFlags<any>, OutputFlags<any>>
}
return: string[]
}
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export type {Hook, Hooks} from './hooks'
export type {Logger} from './logger'
export type {Manifest} from './manifest'
export type {Arg, BooleanFlag, CustomOptions, Deprecation, Flag, FlagDefinition, OptionFlag} from './parser'
export type {Configuration, PJSON, S3, S3Templates, UserPJSON} from './pjson'
export type {OclifConfiguration, PJSON, S3, S3Templates, UserPJSON} from './pjson'
export type {Options, Plugin, PluginOptions} from './plugin'
export type {S3Manifest} from './s3-manifest'
export type {Theme} from './theme'
Expand Down
3 changes: 1 addition & 2 deletions src/interfaces/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -416,9 +416,8 @@ export type FlagDefinition<

export type Flag<T> = BooleanFlag<T> | OptionFlag<T>

export type Input<TFlags extends FlagOutput, BFlags extends FlagOutput, AFlags extends ArgOutput> = {
export type Input<TFlags extends FlagOutput, AFlags extends ArgOutput> = {
flags?: FlagInput<TFlags>
baseFlags?: FlagInput<BFlags>
enableJsonFlag?: true | false
args?: ArgInput<AFlags>
strict?: boolean | undefined
Expand Down
Loading
Loading