From fec3ea4268b1853f2555f9a018593a79eb9229c5 Mon Sep 17 00:00:00 2001 From: Klaus Reimer Date: Fri, 18 Dec 2015 13:28:36 +0100 Subject: [PATCH 1/5] Add some missing yeoman methods and fix some wrong ones --- yeoman-generator/yeoman-generator.d.ts | 36 ++++++++++++++++++-------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/yeoman-generator/yeoman-generator.d.ts b/yeoman-generator/yeoman-generator.d.ts index 4ccd98e44..8ebc4da89 100644 --- a/yeoman-generator/yeoman-generator.d.ts +++ b/yeoman-generator/yeoman-generator.d.ts @@ -28,6 +28,7 @@ declare module yo { composeWith(namespace: string, options: any, settings?: IComposeSetting): IYeomanGenerator; defaultFor(name: string): void; destinationRoot(rootPath: string): string; + destinationPath(file: string): string; determineAppname(): void; getCollisionFilter(): (output: any) => void; hookFor(name: string, config: IHookConfig): void; @@ -37,6 +38,7 @@ declare module yo { run(args: any, callback?: Function): void; runHooks(callback?: Function): void; sourceRoot(rootPath: string): string; + templatePath(file: string): string; addListener(event: string, listener: Function): NodeJS.EventEmitter; on(event: string, listener: Function): NodeJS.EventEmitter; once(event: string, listener: Function): NodeJS.EventEmitter; @@ -49,18 +51,30 @@ declare module yo { async(): any; prompt(opt?:IPromptOptions, callback?:(answers:any)=>void) :void; log(message: string) : void; - npmInstall(packages: string[], options?:any) :void; + npmInstall(packages: string[], options?: any, cb?: Function) :void; + installDependencies(): void; + spawnCommand(name: string, args?: string[]): void; appname: string; gruntfile: IGruntFileStatic; + options: { [key: string]: any }; } + + export interface IChoice { + name: string; + value: string; + short?: string; + } + export interface IPromptOptions{ - type:string; - name:string; - message:string; - default:string; + type: string; + name: string; + message: string; + choices?: string[] | Function | IChoice[]; + default?: string; + store?: boolean; } - + export interface IGruntFileStatic { loadNpmTasks(pluginName: string): void; insertConfig(name:string, config:any):void; @@ -70,11 +84,11 @@ declare module yo { } export interface IArgumentConfig { - desc: string; - required: boolean; - optional: boolean; - type: any; - defaults: any; + desc?: string; + required?: boolean; + optional?: boolean; + type?: any; + defaults?: any; } export interface IComposeSetting { From 818e6cf2ff8a7b0458fd9f50054ffb37778a93ed Mon Sep 17 00:00:00 2001 From: Klaus Reimer Date: Fri, 18 Dec 2015 15:07:14 +0100 Subject: [PATCH 2/5] More typing corrections and added tests --- yeoman-generator/yeoman-generator-tests.ts | 64 ++++++++++++++++++++++ yeoman-generator/yeoman-generator.d.ts | 43 ++++++++++----- 2 files changed, 94 insertions(+), 13 deletions(-) diff --git a/yeoman-generator/yeoman-generator-tests.ts b/yeoman-generator/yeoman-generator-tests.ts index 84f007206..f72dff4e3 100644 --- a/yeoman-generator/yeoman-generator-tests.ts +++ b/yeoman-generator/yeoman-generator-tests.ts @@ -112,3 +112,67 @@ runContext.inDir('dirPath') .withGenerators(['deps', 'deps']) .withOptions('opts') .withPrompts('answers'); + +// http://yeoman.io/generator/Base.html#destinationPath +generator.destinationPath() === 'string'; +generator.destinationPath('path1') === 'string'; +generator.destinationPath('path1', 'path2') === 'string'; +generator.destinationPath('path1', 'path2', 'path3') === 'string'; + +// http://yeoman.io/generator/Base.html#templatePath +generator.templatePath() === 'string'; +generator.templatePath('path1') === 'string'; +generator.templatePath('path1', 'path2') === 'string'; +generator.templatePath('path1', 'path2', 'path3') === 'string'; + +// http://yeoman.io/generator/Base.html#npmInstall +generator.npmInstall(); +generator.npmInstall('pkg'); +generator.npmInstall([ 'pkg1', 'pkg2' ]); +generator.npmInstall('pkg', {}); +generator.npmInstall('pkg', {}, () => {}); + +// http://yeoman.io/generator/Base.html#installDependencies +generator.installDependencies(); +generator.installDependencies({}); +generator.installDependencies({ npm: true }); +generator.installDependencies({ bower: true }); +generator.installDependencies({ skipMessage: true }); +generator.installDependencies({ callback: () => {} }); + +// http://yeoman.io/generator/Base.html#spawnCommand +generator.spawnCommand('command', []); +generator.spawnCommand('command', [ '-arg' ]); +generator.spawnCommand('command', [], {}); + +// http://yeoman.io/generator/Base.html#spawnCommandSync +generator.spawnCommandSync('command', []); +generator.spawnCommandSync('command', [ '-arg' ]); +generator.spawnCommandSync('command', [], {}); + +// http://yeoman.io/generator/Base.html#option +generator.options['opt'] === 'string'; + +// http://yeoman.io/generator/Base.html#prompt +// https://github.com/SBoudrias/Inquirer.js +generator.prompt({ name: 'Name', message: 'Message' }, (answer) => {}); +generator.prompt({ name: 'Name', message: (answers) => 'Message' }, (answer) => {}); +generator.prompt({ name: 'Name', message: '', choices: [ 'c1', 'c2' ] }, (answer) => {}); +generator.prompt({ name: 'Name', message: '', choices: [ { name: 'Choice 1', value: 'c1' } ] }, (answer) => {}); +generator.prompt({ name: 'Name', message: '', choices: (answers) => [ 'c1', 'c2' ] }, (answer) => {}); +generator.prompt({ name: 'Name', message: '', choices: (answers) => [ { name: 'Choice 1', value: 'c1' } ] }, (answer) => {}); +generator.prompt({ name: 'Name', message: '', choices: (answers) => [ { name: 'Choice 1', value: 'c1', short: '1' } ] }, (answer) => {}); +generator.prompt({ name: 'Name', message: '', default: 'string' }, (answer) => {}); +generator.prompt({ name: 'Name', message: '', default: 10 }, (answer) => {}); +generator.prompt({ name: 'Name', message: '', default: [ 'string' ] }, (answer) => {}); +generator.prompt({ name: 'Name', message: '', default: [ 10 ] }, (answer) => {}); +generator.prompt({ name: 'Name', message: '', default: (answers) => [ 'string' ] }, (answer) => {}); +generator.prompt({ name: 'Name', message: '', default: (answers) => [ 10 ] }, (answer) => {}); +generator.prompt({ name: 'Name', message: '', default: (answers) => 'string' }, (answer) => {}); +generator.prompt({ name: 'Name', message: '', default: (answers) => 10 }, (answer) => {}); +generator.prompt({ name: 'Name', message: '', type: "list" }, (answer) => {}); +generator.prompt({ name: 'Name', message: '', validate: (input) => true }, (answer) => {}); +generator.prompt({ name: 'Name', message: '', validate: (input) => "Error" }, (answer) => {}); +generator.prompt({ name: 'Name', message: '', filter: (input) => input }, (answer) => {}); +generator.prompt({ name: 'Name', message: '', when: (answers) => true }, (answer) => {}); +generator.prompt({ name: 'Name', message: '', when: true }, (answer) => {}); diff --git a/yeoman-generator/yeoman-generator.d.ts b/yeoman-generator/yeoman-generator.d.ts index 8ebc4da89..b73037ea5 100644 --- a/yeoman-generator/yeoman-generator.d.ts +++ b/yeoman-generator/yeoman-generator.d.ts @@ -10,6 +10,7 @@ declare module yo { composeWith(namespace: string, options: any, settings?: IComposeSetting): IYeomanGenerator; defaultFor(name: string): void; destinationRoot(rootPath: string): string; + destinationPath(...path: string[]): string; determineAppname(): void; getCollisionFilter(): (output: any) => void; hookFor(name: string, config: IHookConfig): void; @@ -19,8 +20,13 @@ declare module yo { run(args: any, callback?: Function): void; runHooks(callback?: Function): void; sourceRoot(rootPath: string): string; - - + templatePath(...path: string[]): string; + prompt(opt: IPromptOptions | IPromptOptions[], callback: (answers: any) => void): void; + npmInstall(packages?: string[] | string, options?: any, cb?: Function): void; + installDependencies(options?: IInstallDependencyOptions): void; + spawnCommand(name: string, args?: string[], options?: Object): void; + spawnCommandSync(name: string, args?: string[], options?: Object): void; + options: { [key: string]: any }; } export class YeomanGeneratorBase implements IYeomanGenerator, NodeJS.EventEmitter { @@ -28,7 +34,7 @@ declare module yo { composeWith(namespace: string, options: any, settings?: IComposeSetting): IYeomanGenerator; defaultFor(name: string): void; destinationRoot(rootPath: string): string; - destinationPath(file: string): string; + destinationPath(...path: string[]): string; determineAppname(): void; getCollisionFilter(): (output: any) => void; hookFor(name: string, config: IHookConfig): void; @@ -38,7 +44,7 @@ declare module yo { run(args: any, callback?: Function): void; runHooks(callback?: Function): void; sourceRoot(rootPath: string): string; - templatePath(file: string): string; + templatePath(...path: string[]): string; addListener(event: string, listener: Function): NodeJS.EventEmitter; on(event: string, listener: Function): NodeJS.EventEmitter; once(event: string, listener: Function): NodeJS.EventEmitter; @@ -49,17 +55,25 @@ declare module yo { emit(event: string, ...args: any[]): boolean; async(): any; - prompt(opt?:IPromptOptions, callback?:(answers:any)=>void) :void; + prompt(opt: IPromptOptions | IPromptOptions[], callback: (answers: any) => void): void; log(message: string) : void; npmInstall(packages: string[], options?: any, cb?: Function) :void; - installDependencies(): void; - spawnCommand(name: string, args?: string[]): void; + installDependencies(options?: IInstallDependencyOptions): void; + spawnCommand(name: string, args?: string[], options?: Object): void; + spawnCommandSync(name: string, args?: string[], options?: Object): void; appname: string; gruntfile: IGruntFileStatic; options: { [key: string]: any }; } + export interface IInstallDependencyOptions { + npm?: boolean; + bower?: boolean; + skipMessage?: boolean; + callback?: Function; + } + export interface IChoice { name: string; value: string; @@ -67,11 +81,14 @@ declare module yo { } export interface IPromptOptions{ - type: string; + type?: string; name: string; - message: string; - choices?: string[] | Function | IChoice[]; - default?: string; + message: string | ((answers: Object) => string); + choices?: string[] | IChoice[] | ((answers: Object) => (string[] | IChoice[])); + default?: string | number | string[] | number[] | ((answers: Object) => (string | number | string[] | number[])); + validate?: ((input: any) => boolean | string); + filter?: ((input: any) => any); + when?: ((answers: Object) => boolean) | boolean; store?: boolean; } @@ -84,10 +101,10 @@ declare module yo { } export interface IArgumentConfig { - desc?: string; + desc: string; required?: boolean; optional?: boolean; - type?: any; + type: any; defaults?: any; } From 33e3ab99b09c3c4b159868ed66db602792aecdec Mon Sep 17 00:00:00 2001 From: Klaus Reimer Date: Fri, 18 Dec 2015 16:10:09 +0100 Subject: [PATCH 3/5] "generators" is deprecated now. Use "Base" and "NamedBase" directly. --- yeoman-generator/yeoman-generator.d.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/yeoman-generator/yeoman-generator.d.ts b/yeoman-generator/yeoman-generator.d.ts index b73037ea5..48fbd835c 100644 --- a/yeoman-generator/yeoman-generator.d.ts +++ b/yeoman-generator/yeoman-generator.d.ts @@ -205,6 +205,8 @@ declare module yo { var file: any; var assert: IAssert; var test: ITestHelper; + + // "generators" is deprecated module generators { export class NamedBase extends YeomanGeneratorBase implements INamedBase { @@ -215,6 +217,14 @@ declare module yo { static extend(protoProps: IQueueProps, staticProps?: any): IYeomanGenerator; } } + + export class NamedBase extends YeomanGeneratorBase implements INamedBase { + constructor(args: string | string[], options: any); + } + + export class Base extends NamedBase implements IBase { + static extend(protoProps: IQueueProps, staticProps?: any): IYeomanGenerator; + } } declare module "yeoman-generator" { From 2321f2da7738733f71a24ca5e9ec1b8153ced3e3 Mon Sep 17 00:00:00 2001 From: Klaus Reimer Date: Fri, 18 Dec 2015 17:05:26 +0100 Subject: [PATCH 4/5] Just use `any` instead of explicit types Inquirer also supports some other stuff like separator objects as choices. It gets too complicated to properly type it because its unclear what other stuff can be used as choices so I just use `any` now. --- yeoman-generator/yeoman-generator.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yeoman-generator/yeoman-generator.d.ts b/yeoman-generator/yeoman-generator.d.ts index 48fbd835c..27e79943c 100644 --- a/yeoman-generator/yeoman-generator.d.ts +++ b/yeoman-generator/yeoman-generator.d.ts @@ -84,7 +84,7 @@ declare module yo { type?: string; name: string; message: string | ((answers: Object) => string); - choices?: string[] | IChoice[] | ((answers: Object) => (string[] | IChoice[])); + choices?: any[] | ((answers: Object) => any); default?: string | number | string[] | number[] | ((answers: Object) => (string | number | string[] | number[])); validate?: ((input: any) => boolean | string); filter?: ((input: any) => any); From 1b1ee18ef97a0efb52f04f5ae6d2b7c371550d24 Mon Sep 17 00:00:00 2001 From: Klaus Reimer Date: Tue, 22 Dec 2015 09:13:14 +0100 Subject: [PATCH 5/5] Fix sourceRoot and destinationRoot and add fs API --- yeoman-generator/yeoman-generator-tests.ts | 26 +++++++++++++++++++++- yeoman-generator/yeoman-generator.d.ts | 24 ++++++++++++++++---- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/yeoman-generator/yeoman-generator-tests.ts b/yeoman-generator/yeoman-generator-tests.ts index f72dff4e3..fdb341177 100644 --- a/yeoman-generator/yeoman-generator-tests.ts +++ b/yeoman-generator/yeoman-generator-tests.ts @@ -35,6 +35,7 @@ var compose = generator.composeWith('namespace', 'any', { }); compose.defaultFor('name'); +compose.destinationRoot() === 'string'; compose.destinationRoot('rootPath') === 'string'; compose.determineAppname(); compose.getCollisionFilter()('output'); @@ -59,7 +60,8 @@ compose.run('args', () => { compose.runHooks(() => { return; }); -returnString = compose.sourceRoot('rootPath') === 'string'; +compose.sourceRoot('rootPath') === 'string'; +compose.sourceRoot() === 'string'; var assert = yeoman.assert; @@ -176,3 +178,25 @@ generator.prompt({ name: 'Name', message: '', validate: (input) => "Error" }, (a generator.prompt({ name: 'Name', message: '', filter: (input) => input }, (answer) => {}); generator.prompt({ name: 'Name', message: '', when: (answers) => true }, (answer) => {}); generator.prompt({ name: 'Name', message: '', when: true }, (answer) => {}); + +// http://yeoman.io/generator/Base.html +// https://github.com/SBoudrias/mem-fs-editor +generator.fs.read("file") === "string"; +generator.fs.read("file", {}) === "string"; +generator.fs.readJSON("file") === {}; +generator.fs.readJSON("file", {}) === {}; +generator.fs.write("file", "contents"); +generator.fs.writeJSON("file", {}); +generator.fs.writeJSON("file", {}, () => {}); +generator.fs.writeJSON("file", {}, () => {}, 2); +generator.fs.delete("file"); +generator.fs.delete("file", {}); +generator.fs.copy("from", "to"); +generator.fs.copy("from", "to", {}); +generator.fs.copyTpl("from", "to", {}); +generator.fs.copyTpl("from", "to", {}, {}); +generator.fs.move("from", "to"); +generator.fs.move("from", "to", {}); +generator.fs.exists("file") === true; +generator.fs.commit(() => {}); +generator.fs.commit([], () => {}); diff --git a/yeoman-generator/yeoman-generator.d.ts b/yeoman-generator/yeoman-generator.d.ts index 27e79943c..7b8d073ee 100644 --- a/yeoman-generator/yeoman-generator.d.ts +++ b/yeoman-generator/yeoman-generator.d.ts @@ -9,7 +9,7 @@ declare module yo { argument(name: string, config: IArgumentConfig): void; composeWith(namespace: string, options: any, settings?: IComposeSetting): IYeomanGenerator; defaultFor(name: string): void; - destinationRoot(rootPath: string): string; + destinationRoot(rootPath?: string): string; destinationPath(...path: string[]): string; determineAppname(): void; getCollisionFilter(): (output: any) => void; @@ -19,7 +19,7 @@ declare module yo { run(args?: any): void; run(args: any, callback?: Function): void; runHooks(callback?: Function): void; - sourceRoot(rootPath: string): string; + sourceRoot(rootPath?: string): string; templatePath(...path: string[]): string; prompt(opt: IPromptOptions | IPromptOptions[], callback: (answers: any) => void): void; npmInstall(packages?: string[] | string, options?: any, cb?: Function): void; @@ -27,13 +27,14 @@ declare module yo { spawnCommand(name: string, args?: string[], options?: Object): void; spawnCommandSync(name: string, args?: string[], options?: Object): void; options: { [key: string]: any }; + fs: IMemFsEditor; } export class YeomanGeneratorBase implements IYeomanGenerator, NodeJS.EventEmitter { argument(name: string, config: IArgumentConfig): void; composeWith(namespace: string, options: any, settings?: IComposeSetting): IYeomanGenerator; defaultFor(name: string): void; - destinationRoot(rootPath: string): string; + destinationRoot(rootPath?: string): string; destinationPath(...path: string[]): string; determineAppname(): void; getCollisionFilter(): (output: any) => void; @@ -43,7 +44,7 @@ declare module yo { run(args?: any): void; run(args: any, callback?: Function): void; runHooks(callback?: Function): void; - sourceRoot(rootPath: string): string; + sourceRoot(rootPath?: string): string; templatePath(...path: string[]): string; addListener(event: string, listener: Function): NodeJS.EventEmitter; on(event: string, listener: Function): NodeJS.EventEmitter; @@ -65,6 +66,21 @@ declare module yo { appname: string; gruntfile: IGruntFileStatic; options: { [key: string]: any }; + fs: IMemFsEditor; + } + + export interface IMemFsEditor { + read(filepath: string, options?: Object): string; + readJSON(filepath: string, defaults?: Object): Object; + write(filepath: string, contents: string): void; + writeJSON(filepath: string, contents: Object, replacer?: Function, space?: number): void; + delete(filepath: string, options?: Object): void; + copy(from: string, to: string, options?: Object): void; + copyTpl(from: string, to: string, context: Object, options?: Object): void; + move(from: string, to: string, options?: Object): void; + exists(filepath: string): boolean; + commit(callback: Function): void; + commit(filters: any[], callback: Function): void; } export interface IInstallDependencyOptions {