Skip to content

Commit

Permalink
fix: work with 4.8.3 (#493)
Browse files Browse the repository at this point in the history
* fix: work with 4.8.3

* test: fix test compilation

* chore: refine solution
  • Loading branch information
mdonnalley committed Sep 23, 2022
1 parent 2038ad4 commit 2f09a72
Show file tree
Hide file tree
Showing 13 changed files with 190 additions and 157 deletions.
6 changes: 3 additions & 3 deletions package.json
Expand Up @@ -73,9 +73,9 @@
"shelljs": "^0.8.5",
"shx": "^0.3.4",
"sinon": "^11.1.2",
"ts-node": "^9.1.1",
"ts-node": "^10.9.1",
"tsd": "^0.22.0",
"typescript": "4.5.5"
"typescript": "^4.8.3"
},
"engines": {
"node": ">=14.0.0"
Expand Down Expand Up @@ -111,7 +111,7 @@
"prepack": "yarn run build",
"test": "mocha --forbid-only \"test/**/*.test.ts\"",
"test:e2e": "mocha \"test/**/*.e2e.ts\" --timeout 600000",
"pretest": "yarn build --noEmit && tsc -p test --noEmit"
"pretest": "yarn build --noEmit && tsc -p test --noEmit --skipLibCheck"
},
"types": "lib/index.d.ts"
}
4 changes: 1 addition & 3 deletions src/command.ts
Expand Up @@ -107,10 +107,8 @@ export default abstract class Command {
if (value === true) {
this.globalFlags = jsonFlag
} else {
// @ts-expect-error because this.globalFlags is typed as a plain object
delete this.globalFlags?.json
this.flags = {} // force the flags setter to run
// @ts-expect-error because this.flags is typed as a plain object
delete this.flags?.json
}
}
Expand Down Expand Up @@ -250,7 +248,7 @@ export default abstract class Command {
g['http-call']!.userAgent = this.config.userAgent
}

protected async parse<F, G, A extends { [name: string]: any }>(options?: Interfaces.Input<F, G>, argv = this.argv): Promise<Interfaces.ParserOutput<F, G, A>> {
protected async parse<F extends Interfaces.FlagOutput, G extends Interfaces.FlagOutput, A extends { [name: string]: any }>(options?: Interfaces.Input<F, G>, argv = this.argv): Promise<Interfaces.ParserOutput<F, G, A>> {
if (!options) options = this.constructor as any
const opts = {context: this, ...options}
// the spread operator doesn't work with getters so we have to manually add it here
Expand Down
3 changes: 1 addition & 2 deletions src/interfaces/parser.ts
Expand Up @@ -246,5 +246,4 @@ export type CompletableOptionFlag<T> = OptionFlag<T> & {

export type CompletableFlag<T> = BooleanFlag<T> | CompletableOptionFlag<T>

// eslint-disable-next-line @typescript-eslint/ban-types
export type FlagInput<T extends FlagOutput = object> = { [P in keyof T]: CompletableFlag<T[P]> }
export type FlagInput<T extends FlagOutput = { [flag: string]: any }> = { [P in keyof T]: CompletableFlag<T[P]> }
4 changes: 2 additions & 2 deletions src/parser/index.ts
Expand Up @@ -2,7 +2,7 @@ import * as args from './args'
import Deps from './deps'
import * as flags from './flags'
import {Parser} from './parse'
import {FlagInput, Input, ParserOutput} from '../interfaces'
import {FlagInput, Input, ParserOutput, OutputFlags, FlagOutput} from '../interfaces'
import * as Validate from './validate'
export {args}
export {flags}
Expand All @@ -13,7 +13,7 @@ const m = Deps()
// eslint-disable-next-line node/no-missing-require
.add('validate', () => require('./validate').validate as typeof Validate.validate)

export async function parse<TFlags, GFlags, TArgs extends { [name: string]: string }>(argv: string[], options: Input<TFlags, GFlags>): Promise<ParserOutput<TFlags, GFlags, TArgs>> {
export async function parse<TFlags extends OutputFlags<any>, GFlags extends FlagOutput, TArgs extends { [name: string]: string }>(argv: string[], options: Input<TFlags, GFlags>): Promise<ParserOutput<TFlags, GFlags, TArgs>> {
const input = {
argv,
context: options.context,
Expand Down
2 changes: 1 addition & 1 deletion src/parser/util.ts
@@ -1,4 +1,4 @@
export function pickBy<T>(obj: T, fn: (i: T[keyof T]) => boolean): Partial<T> {
export function pickBy<T extends { [s: string]: T[keyof T]; } | ArrayLike<T[keyof T]>>(obj: T, fn: (i: T[keyof T]) => boolean): Partial<T> {
return Object.entries(obj)
.reduce((o, [k, v]) => {
if (fn(v)) o[k] = v
Expand Down
44 changes: 3 additions & 41 deletions test/help/format-command-with-options.test.ts
@@ -1,8 +1,7 @@
import {expect, test as base} from '@oclif/test'
import stripAnsi = require('strip-ansi')

import {Command as Base, Flags as flags, Interfaces, toCached} from '../../src'
import {Help, CommandHelp} from '../../src/help'
import {Command as Base, Flags as flags} from '../../src'
import {commandHelp, TestHelpWithOptions as TestHelp} from './help-test-utils'

const g: any = global
g.oclif.columns = 80
Expand All @@ -15,47 +14,10 @@ class Command extends Base {
}
}

// Allow overriding section headers
class TestCommandHelp extends CommandHelp {
protected sections() {
const sections = super.sections()
const flagSection = sections.find(section => section.header === 'FLAGS')
if (flagSection) flagSection.header = 'OPTIONS'
return sections
}
}

// extensions to expose method as public for testing
class TestHelp extends Help {
CommandHelpClass = TestCommandHelp

constructor(config: Interfaces.Config, opts: Partial<Interfaces.HelpOptions> = {}) {
super(config, opts)
this.opts.showFlagNameInTitle = true
this.opts.showFlagOptionsInTitle = true
this.opts.hideCommandSummaryInDescription = true
}

public formatCommand(command: Interfaces.Command) {
return super.formatCommand(command)
}
}

const test = base
.loadConfig()
.add('help', ctx => new TestHelp(ctx.config as any))
.register('commandHelp', (command?: any) => ({
async run(ctx: {help: TestHelp; commandHelp: string; expectation: string}) {
const cached = await toCached(command!, {} as any)
const help = ctx.help.formatCommand(cached)
if (process.env.TEST_OUTPUT === '1') {
console.log(help)
}

ctx.commandHelp = stripAnsi(help).split('\n').map(s => s.trimEnd()).join('\n')
ctx.expectation = 'has commandHelp'
},
}))
.register('commandHelp', commandHelp)

describe('formatCommand', () => {
test
Expand Down
25 changes: 3 additions & 22 deletions test/help/format-command.test.ts
@@ -1,8 +1,7 @@
import {expect, test as base} from '@oclif/test'
import stripAnsi = require('strip-ansi')

import {Command as Base, Flags as flags, Interfaces, toCached} from '../../src'
import {Help} from '../../src/help'
import {Command as Base, Flags as flags} from '../../src'
import {commandHelp, TestHelp} from './help-test-utils'

const g: any = global
g.oclif.columns = 80
Expand All @@ -13,28 +12,10 @@ class Command extends Base {
}
}

// extensions to expose method as public for testing
class TestHelp extends Help {
public formatCommand(command: Interfaces.Command) {
return super.formatCommand(command)
}
}

const test = base
.loadConfig()
.add('help', ctx => new TestHelp(ctx.config as any))
.register('commandHelp', (command?: any) => ({
async run(ctx: {help: TestHelp; commandHelp: string; expectation: string}) {
const cached = await toCached(command!, {} as any)
const help = ctx.help.formatCommand(cached)
if (process.env.TEST_OUTPUT === '1') {
console.log(help)
}

ctx.commandHelp = stripAnsi(help).split('\n').map(s => s.trimEnd()).join('\n')
ctx.expectation = 'has commandHelp'
},
}))
.register('commandHelp', commandHelp)

describe('formatCommand', () => {
test
Expand Down
14 changes: 7 additions & 7 deletions test/help/format-commands.test.ts
Expand Up @@ -14,10 +14,7 @@ class TestHelp extends Help {
}
}

const test = base
.loadConfig()
.add('help', ctx => new TestHelp(ctx.config as any))
.register('formatCommands', (commands: Interfaces.Command[] = []) => ({
const formatCommands = (commands: Interfaces.Command[]) => ({
run(ctx: {help: TestHelp; output: string}) {
const help = ctx.help.formatCommands(commands)
if (process.env.TEST_OUTPUT === '1') {
Expand All @@ -26,7 +23,12 @@ const test = base

ctx.output = stripAnsi(help).split('\n').map(s => s.trimEnd()).join('\n')
},
}))
})

const test = base
.loadConfig()
.add('help', ctx => new TestHelp(ctx.config as any))
.register('formatCommands', formatCommands)

describe('formatCommand', () => {
test
Expand All @@ -47,8 +49,6 @@ describe('formatCommand', () => {

static description = 'This is a very long command description that should wrap after too many characters have been entered'

static flags = {}

static args = []

async run() {
Expand Down
10 changes: 6 additions & 4 deletions test/help/format-root.test.ts
Expand Up @@ -17,9 +17,7 @@ class TestHelp extends Help {
}
}

const test = base
.loadConfig()
.register('rootHelp', (ctxOverride?: (config: Interfaces.Config) => Interfaces.Config) => ({
const rootHelp = (ctxOverride?: (config: Interfaces.Config) => Interfaces.Config) => ({
run(ctx: { config: Interfaces.Config; help: Help; commandHelp: string; expectation: string}) {
const config = ctxOverride ? ctxOverride(ctx.config) : ctx.config

Expand All @@ -31,7 +29,11 @@ const test = base

ctx.commandHelp = stripAnsi(root).split('\n').map(s => s.trimEnd()).join('\n')
},
}))
})

const test = base
.loadConfig()
.register('rootHelp', rootHelp)

describe('formatRoot', () => {
test
Expand Down
24 changes: 2 additions & 22 deletions test/help/format-topic.test.ts
@@ -1,35 +1,15 @@
import {expect, test as base} from '@oclif/test'
import stripAnsi = require('strip-ansi')

import {Help} from '../../src/help'
import {Interfaces} from '../../src'
import {TestHelp, topicHelp} from './help-test-utils'

const g: any = global
g.oclif.columns = 80

// extensions to expose method as public for testing
class TestHelp extends Help {
public formatTopic(topic: Interfaces.Topic) {
return super.formatTopic(topic)
}
}

const test = base
.loadConfig()
.add('help', ctx => {
return new TestHelp(ctx.config as any)
})
.register('topicHelp', (topic: Interfaces.Topic) => ({
run(ctx: {help: TestHelp; commandHelp: string; expectation: string}) {
const topicHelpOutput = ctx.help.formatTopic(topic)
if (process.env.TEST_OUTPUT === '1') {
console.log(topicHelpOutput)
}

ctx.commandHelp = stripAnsi(topicHelpOutput).split('\n').map(s => s.trimEnd()).join('\n')
ctx.expectation = 'has topicHelp'
},
}))
.register('topicHelp', topicHelp)

describe('formatHelp', () => {
test
Expand Down
24 changes: 2 additions & 22 deletions test/help/format-topics.test.ts
@@ -1,34 +1,14 @@
import {expect, test as base} from '@oclif/test'
import stripAnsi = require('strip-ansi')

import {Help} from '../../src/help'
import {Interfaces} from '../../src'
import {TestHelp, topicsHelp} from './help-test-utils'

const g: any = global
g.oclif.columns = 80

// extensions to expose method as public for testing
class TestHelp extends Help {
public formatTopics(topics: Interfaces.Topic[]) {
return super.formatTopics(topics)
}
}

const test = base
.loadConfig()
.add('help', ctx => new TestHelp(ctx.config as any))
.register('topicsHelp', (topics: Interfaces.Topic[]) => ({
run(ctx: {help: TestHelp; commandHelp: string; expectation: string}) {
const topicsHelpOutput = ctx.help.formatTopics(topics) || ''

if (process.env.TEST_OUTPUT === '1') {
console.log(topicsHelpOutput)
}

ctx.commandHelp = stripAnsi(topicsHelpOutput).split('\n').map(s => s.trimEnd()).join('\n')
ctx.expectation = 'has topicsHelp'
},
}))
.register('topicsHelp', topicsHelp)

describe('formatTopics', () => {
test
Expand Down
82 changes: 82 additions & 0 deletions test/help/help-test-utils.ts
@@ -0,0 +1,82 @@
import stripAnsi = require('strip-ansi')

import {Interfaces, toCached} from '../../src'
import {Help, CommandHelp} from '../../src/help'

export class TestCommandHelp extends CommandHelp {
protected sections() {
const sections = super.sections()
const flagSection = sections.find(section => section.header === 'FLAGS')
if (flagSection) flagSection.header = 'OPTIONS'
return sections
}
}

// extensions to expose method as public for testing
export class TestHelpWithOptions extends Help {
CommandHelpClass = TestCommandHelp

constructor(config: Interfaces.Config, opts: Partial<Interfaces.HelpOptions> = {}) {
super(config, opts)
this.opts.showFlagNameInTitle = true
this.opts.showFlagOptionsInTitle = true
this.opts.hideCommandSummaryInDescription = true
}

public formatCommand(command: Interfaces.Command) {
return super.formatCommand(command)
}
}

// extensions to expose method as public for testing
export class TestHelp extends Help {
public formatCommand(command: Interfaces.Command) {
return super.formatCommand(command)
}

public formatTopics(topics: Interfaces.Topic[]) {
return super.formatTopics(topics)
}

public formatTopic(topic: Interfaces.Topic) {
return super.formatTopic(topic)
}
}

export const commandHelp = (command?: any) => ({
async run(ctx: {help: TestHelp; commandHelp: string; expectation: string}) {
const cached = await toCached(command!, {} as any)
const help = ctx.help.formatCommand(cached)
if (process.env.TEST_OUTPUT === '1') {
console.log(help)
}

ctx.commandHelp = stripAnsi(help).split('\n').map(s => s.trimEnd()).join('\n')
ctx.expectation = 'has commandHelp'
},
})

export const topicsHelp = (topics: Interfaces.Topic[]) => ({
run(ctx: {help: TestHelp; commandHelp: string; expectation: string}) {
const topicsHelpOutput = ctx.help.formatTopics(topics) || ''

if (process.env.TEST_OUTPUT === '1') {
console.log(topicsHelpOutput)
}

ctx.commandHelp = stripAnsi(topicsHelpOutput).split('\n').map(s => s.trimEnd()).join('\n')
ctx.expectation = 'has topicsHelp'
},
})

export const topicHelp = (topic: Interfaces.Topic) => ({
run(ctx: {help: TestHelp; commandHelp: string; expectation: string}) {
const topicHelpOutput = ctx.help.formatTopic(topic)
if (process.env.TEST_OUTPUT === '1') {
console.log(topicHelpOutput)
}

ctx.commandHelp = stripAnsi(topicHelpOutput).split('\n').map(s => s.trimEnd()).join('\n')
ctx.expectation = 'has topicHelp'
},
})

0 comments on commit 2f09a72

Please sign in to comment.