diff --git a/src/cli/inquire.ts b/src/cli/inquire.ts index dedeaa1..41edec6 100644 --- a/src/cli/inquire.ts +++ b/src/cli/inquire.ts @@ -4,7 +4,7 @@ import { Runner, TypescriptStarterUserOptions, validateName } from './utils'; export async function inquire(): Promise { const packageNameQuestion: Question = { filter: (answer: string) => answer.trim(), - message: 'Enter the new package name:', + message: '📦 Enter the new package name:', name: 'projectName', type: 'input', validate: validateName @@ -19,14 +19,14 @@ export async function inquire(): Promise { { name: 'Node.js application', value: ProjectType.Node }, { name: 'Javascript library', value: ProjectType.Library } ], - message: 'What are you making?', + message: '🔨 What are you making?', name: 'type', type: 'list' }; const packageDescriptionQuestion: Question = { filter: (answer: string) => answer.trim(), - message: 'Enter the package description:', + message: '💬 Enter the package description:', name: 'description', type: 'input', validate: (answer: string) => answer.length > 0 @@ -37,71 +37,109 @@ export async function inquire(): Promise { { name: 'npm', value: Runner.Npm }, { name: 'yarn', value: Runner.Yarn } ], - message: 'Will this project use npm or yarn?', + message: '🚄 Will this project use npm or yarn?', name: 'runner', type: 'list' }; enum TypeDefinitions { none = 'none', - Node = 'node', - DOM = 'dom', - NodeAndDOM = 'both' + node = 'node', + dom = 'dom', + nodeAndDom = 'both' } const typeDefsQuestion: Question = { choices: [ { name: `None — the library won't use any globals or modules from Node.js or the DOM`, - value: '0' + value: TypeDefinitions.none }, { name: `Node.js — parts of the library require access to Node.js globals or built-in modules`, - value: '1' + value: TypeDefinitions.node }, { name: `DOM — parts of the library require access to the Document Object Model (DOM)`, - value: '2' + value: TypeDefinitions.dom }, { name: `Both Node.js and DOM — some parts of the library require Node.js, other parts require DOM access`, - value: '3' + value: TypeDefinitions.nodeAndDom } ], - message: 'Which global type definitions do you want to include?', + message: '📚 Which global type definitions do you want to include?', name: 'definitions', type: 'list', when: (answers: any) => answers.type === ProjectType.Library }; + enum Extras { + strict = 'strict', + immutable = 'immutable', + vscode = 'vscode' + } + const extrasQuestion: Question = { + choices: [ + { + name: 'Enable stricter type-checking', + value: Extras.strict + }, + { + checked: true, + name: 'Enable tslint-immutable', + value: Extras.immutable + }, + { + checked: true, + name: 'Include VS Code debugging config', + value: Extras.vscode + } + ], + message: '🚀 More fun stuff:', + name: 'extras', + type: 'checkbox' + }; + return prompt([ packageNameQuestion, projectTypeQuestion, packageDescriptionQuestion, runnerQuestion, - typeDefsQuestion + typeDefsQuestion, + extrasQuestion ]).then(answers => { - const { definitions, description, projectName, runner } = answers as { + const { + definitions, + description, + extras, + projectName, + runner + } = answers as { readonly definitions?: TypeDefinitions; readonly description: string; + readonly extras: ReadonlyArray; readonly projectName: string; readonly runner: Runner; }; return { description, domDefinitions: definitions - ? [TypeDefinitions.DOM, TypeDefinitions.NodeAndDOM].includes( + ? [TypeDefinitions.dom, TypeDefinitions.nodeAndDom].includes( definitions ) : false, + immutable: extras.includes(Extras.immutable), install: true, nodeDefinitions: definitions - ? [TypeDefinitions.Node, TypeDefinitions.NodeAndDOM].includes( + ? [TypeDefinitions.node, TypeDefinitions.nodeAndDom].includes( definitions ) : false, projectName, - runner + runner, + strict: extras.includes(Extras.strict), + vscode: extras.includes(Extras.vscode) }; }); } diff --git a/src/cli/tests/cli.integration.spec.ts b/src/cli/tests/cli.integration.spec.ts index 634cd16..0a39983 100644 --- a/src/cli/tests/cli.integration.spec.ts +++ b/src/cli/tests/cli.integration.spec.ts @@ -205,7 +205,7 @@ async function testInteractive( projectName: string, entry: ReadonlyArray> ): Promise { - const lastCheck = entry[3] !== undefined; + const typeDefs = entry[3] !== ''; const proc = execa(`../bin/typescript-starter`, ['--noinstall'], { cwd: buildDir, env: { @@ -247,45 +247,54 @@ async function testInteractive( clearBuffer(); type(`${entry[1]}${enter}`); await ms(200); - checkBuffer(new RegExp(`${entry[1]}[\\s\\S]*npm or yarn?`)); + checkBuffer(new RegExp(`${entry[1]}[\\s\\S]*npm or yarn\\?`)); clearBuffer(); type(`${entry[2][0]}${enter}`); await ms(200); - const search = `${entry[2][1]}[\\s\\S]*global type definitions`; - const exp = lastCheck + const search = `\\? ${entry[2][1]}`; + const exp = typeDefs ? new RegExp(`${search}`) // should match : new RegExp(`(?!${search})`); // should not match checkBuffer(exp); // tslint:disable-next-line:no-if-statement - if (lastCheck) { + if (typeDefs) { clearBuffer(); type(`${entry[3][0]}${enter}`); await ms(200); - checkBuffer(new RegExp(`${entry[3][1]}`)); + checkBuffer(new RegExp(`${entry[3][1]}[\\s\\S]*More fun stuff`)); } + clearBuffer(); + type(`${entry[4][0]}${enter}`); + await ms(200); + checkBuffer(new RegExp(`${entry[4][1]}`)); return proc; } test(`${ TestDirectories.three }: interactive mode: javascript library`, async t => { - t.plan(7); + t.plan(8); const proc = await testInteractive(t, `${TestDirectories.three}`, [ [`${down}${up}${down}`, `Javascript library`], `integration test 3 description`, [`${down}${up}${down}${enter}`, `yarn`], - [`${down}${down}${down}${enter}`, `Both Node.js and DOM`] + [`${down}${down}${down}${enter}`, `Both Node.js and DOM`], + [' ', 'stricter type-checking[\\s\\S]*tslint-immutable[\\s\\S]*VS Code'] ]); await proc; const map = await hashAllTheThings(TestDirectories.three); t.deepEqual(map, { 'test-3/README.md': 'c52631ebf78f6b030af9a109b769b647', 'test-3/bin/typescript-starter': 'a4ad3923f37f50df986b43b1adb9f6b3', - 'test-3/src/index.ts': '5991bedc40ac87a01d880c6db16fe349', + 'test-3/src/index.ts': 'fbc67c2cbf3a7d37e4e02583bf06eec9', + 'test-3/src/lib/async.spec.ts': '1e83b84de3f3b068244885219acb42bd', + 'test-3/src/lib/async.ts': '9012c267bb25fa98ad2561929de3d4e2', + 'test-3/src/lib/hash.spec.ts': '87bfca3c0116fd86a353750fcf585ecf', + 'test-3/src/lib/hash.ts': 'a4c552897f25da5963f410e375264bd1', 'test-3/src/lib/number.spec.ts': '40ebb014eb7871d1f810c618aba1d589', 'test-3/src/lib/number.ts': '43756f90e6ac0b1c4ee6c81d8ab969c7', 'test-3/src/types/example.d.ts': '4221812f6f0434eec77ccb1fba1e3759', - 'test-3/tsconfig.json': 'f36dc6407fc898f41a23cb620b2f4884', + 'test-3/tsconfig.json': '43817952d399db9e44977b3703edd7cf', 'test-3/tsconfig.module.json': '2fda4c8760c6cfa3462b40df0645850d', 'test-3/tslint.json': '7ac167ffbcb724a6c270e8dc4e747067' }); @@ -294,11 +303,13 @@ test(`${ test(`${ TestDirectories.four }: interactive mode: node.js application`, async t => { - t.plan(6); + t.plan(7); const proc = await testInteractive(t, `${TestDirectories.four}`, [ [`${down}${up}`, `Node.js application`], `integration test 4 description`, - [`${down}${up}${enter}`, `npm`] + [`${down}${up}${enter}`, `npm`], + '', + [`${down} `, 'VS Code'] ]); await proc; const map = await hashAllTheThings(TestDirectories.four); @@ -347,10 +358,13 @@ test(`${ domDefinitions: false, email: 'email@example.com', fullName: 'Satoshi Nakamoto', + immutable: true, install: true, nodeDefinitions: false, projectName: TestDirectories.five, - runner: Runner.Npm + runner: Runner.Npm, + strict: true, + vscode: false }; const log = console.log; // tslint:disable-next-line:no-object-mutation @@ -384,10 +398,13 @@ test(`${TestDirectories.six}: Sandboxed: yarn, no initial commit`, async t => { domDefinitions: true, email: Placeholders.email, fullName: Placeholders.name, + immutable: true, install: true, nodeDefinitions: true, projectName: TestDirectories.six, - runner: Runner.Yarn + runner: Runner.Yarn, + strict: false, + vscode: true }; const log = console.log; // tslint:disable-next-line:no-object-mutation diff --git a/src/cli/utils.ts b/src/cli/utils.ts index de83144..e375703 100644 --- a/src/cli/utils.ts +++ b/src/cli/utils.ts @@ -9,10 +9,13 @@ export enum Runner { export interface TypescriptStarterUserOptions { readonly description: string; readonly domDefinitions: boolean; + readonly immutable: boolean; readonly install: boolean; readonly nodeDefinitions: boolean; readonly projectName: string; readonly runner: Runner; + readonly strict: boolean; + readonly vscode: boolean; } export interface TypescriptStarterInferredOptions {