feat(CLI): begin adding extra configuration options
This commit is contained in:
@@ -4,7 +4,7 @@ import { Runner, TypescriptStarterUserOptions, validateName } from './utils';
|
||||
export async function inquire(): Promise<TypescriptStarterUserOptions> {
|
||||
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<TypescriptStarterUserOptions> {
|
||||
{ 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<TypescriptStarterUserOptions> {
|
||||
{ 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<string>;
|
||||
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)
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ async function testInteractive(
|
||||
projectName: string,
|
||||
entry: ReadonlyArray<string | ReadonlyArray<string>>
|
||||
): Promise<execa.ExecaReturns> {
|
||||
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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user