diff --git a/README.md b/README.md index 43d474b2d..50aca11b1 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,10 @@ $ npm install @form8ion/javascript --save #### Import +```javascript +import 'validate-npm-package-name'; +``` + ```javascript const {dialects, projectTypes} = await import('@form8ion/javascript-core'); const { @@ -52,8 +56,14 @@ const { lift: liftJavascript, test: thisIsAJavaScriptProject, scaffoldUnitTesting, - questionNames + promptConstants } = await import('./lib/index.js'); + +const { + questionNames +} = promptConstants; +const {BASE_DETAILS} = questionNames; +const {UNIT_TEST_FRAMEWORK} = questionNames.UNIT_TESTING; ``` #### Execute @@ -61,6 +71,12 @@ const { ```javascript const accountName = 'form8ion'; const projectRoot = process.cwd(); +const logger = { + info: () => undefined, + warn: () => undefined, + error: () => undefined, + success: () => undefined +}; await scaffoldJavaScript({ projectRoot, @@ -81,22 +97,22 @@ await scaffoldJavaScript({ ciServices: {} }, decisions: { - [questionNames.DIALECT]: dialects.BABEL, - [questionNames.NODE_VERSION_CATEGORY]: 'LTS', - [questionNames.PACKAGE_MANAGER]: 'npm', - [questionNames.PROJECT_TYPE]: projectTypes.PACKAGE, - [questionNames.SHOULD_BE_SCOPED]: true, - [questionNames.SCOPE]: accountName, - [questionNames.AUTHOR_NAME]: 'Your Name', - [questionNames.AUTHOR_EMAIL]: 'you@domain.tld', - [questionNames.AUTHOR_URL]: 'https://your.website.tld', - [questionNames.UNIT_TESTS]: true, - [questionNames.INTEGRATION_TESTS]: true, - [questionNames.PROVIDE_EXAMPLE]: true + [BASE_DETAILS.DIALECT]: dialects.BABEL, + [BASE_DETAILS.NODE_VERSION_CATEGORY]: 'LTS', + [BASE_DETAILS.PACKAGE_MANAGER]: 'npm', + [BASE_DETAILS.PROJECT_TYPE]: projectTypes.PACKAGE, + [BASE_DETAILS.SHOULD_BE_SCOPED]: true, + [BASE_DETAILS.SCOPE]: accountName, + [BASE_DETAILS.AUTHOR_NAME]: 'Your Name', + [BASE_DETAILS.AUTHOR_EMAIL]: 'you@domain.tld', + [BASE_DETAILS.AUTHOR_URL]: 'https://your.website.tld', + [BASE_DETAILS.UNIT_TESTS]: true, + [BASE_DETAILS.INTEGRATION_TESTS]: true, + [BASE_DETAILS.PROVIDE_EXAMPLE]: true } -}); +}, {logger}); -if (await thisIsAJavaScriptProject({projectRoot})) { +if (await thisIsAJavaScriptProject({projectRoot}, {logger})) { await liftJavascript({ projectRoot, configs: {eslint: {scope: '@foo'}}, @@ -112,7 +128,7 @@ if (await thisIsAJavaScriptProject({projectRoot})) { lift: () => ({}) } } - }); + }, {logger}); } await scaffoldUnitTesting({ @@ -123,8 +139,8 @@ await scaffoldUnitTesting({ }, visibility: 'OSS', vcs: {host: 'GitHub', owner: 'foo', name: 'bar'}, - decisions: {[questionNames.UNIT_TEST_FRAMEWORK]: 'Mocha'} -}); + decisions: {[UNIT_TEST_FRAMEWORK]: 'Mocha'} +}, {logger}); ``` ### Documentation diff --git a/example.js b/example.js index 9823f4ab5..259965330 100644 --- a/example.js +++ b/example.js @@ -1,6 +1,7 @@ // #### Import // remark-usage-ignore-next 4 import {resolve} from 'path'; +import {existsSync} from 'fs'; import stubbedFs from 'mock-fs'; import * as td from 'testdouble'; import 'validate-npm-package-name'; @@ -10,7 +11,7 @@ stubbedFs({ node_modules: stubbedFs.load(resolve('node_modules')), '.nvmrc': 'v1.2.3', lib: stubbedFs.load(resolve('lib')), - templates: stubbedFs.load(resolve('templates')) + ...existsSync(resolve('templates')) && {templates: stubbedFs.load(resolve('templates'))} }); const {execa} = await td.replaceEsm('execa'); td.when(execa('. ~/.nvm/nvm.sh && nvm ls-remote --lts', {shell: true})) @@ -24,12 +25,24 @@ const { lift: liftJavascript, test: thisIsAJavaScriptProject, scaffoldUnitTesting, - questionNames + promptConstants } = await import('./lib/index.js'); +const { + questionNames +} = promptConstants; +const {BASE_DETAILS} = questionNames; +const {UNIT_TEST_FRAMEWORK} = questionNames.UNIT_TESTING; + // #### Execute const accountName = 'form8ion'; const projectRoot = process.cwd(); +const logger = { + info: () => undefined, + warn: () => undefined, + error: () => undefined, + success: () => undefined +}; await scaffoldJavaScript({ projectRoot, @@ -50,22 +63,22 @@ await scaffoldJavaScript({ ciServices: {} }, decisions: { - [questionNames.DIALECT]: dialects.BABEL, - [questionNames.NODE_VERSION_CATEGORY]: 'LTS', - [questionNames.PACKAGE_MANAGER]: 'npm', - [questionNames.PROJECT_TYPE]: projectTypes.PACKAGE, - [questionNames.SHOULD_BE_SCOPED]: true, - [questionNames.SCOPE]: accountName, - [questionNames.AUTHOR_NAME]: 'Your Name', - [questionNames.AUTHOR_EMAIL]: 'you@domain.tld', - [questionNames.AUTHOR_URL]: 'https://your.website.tld', - [questionNames.UNIT_TESTS]: true, - [questionNames.INTEGRATION_TESTS]: true, - [questionNames.PROVIDE_EXAMPLE]: true + [BASE_DETAILS.DIALECT]: dialects.BABEL, + [BASE_DETAILS.NODE_VERSION_CATEGORY]: 'LTS', + [BASE_DETAILS.PACKAGE_MANAGER]: 'npm', + [BASE_DETAILS.PROJECT_TYPE]: projectTypes.PACKAGE, + [BASE_DETAILS.SHOULD_BE_SCOPED]: true, + [BASE_DETAILS.SCOPE]: accountName, + [BASE_DETAILS.AUTHOR_NAME]: 'Your Name', + [BASE_DETAILS.AUTHOR_EMAIL]: 'you@domain.tld', + [BASE_DETAILS.AUTHOR_URL]: 'https://your.website.tld', + [BASE_DETAILS.UNIT_TESTS]: true, + [BASE_DETAILS.INTEGRATION_TESTS]: true, + [BASE_DETAILS.PROVIDE_EXAMPLE]: true } -}); +}, {logger}); -if (await thisIsAJavaScriptProject({projectRoot})) { +if (await thisIsAJavaScriptProject({projectRoot}, {logger})) { await liftJavascript({ projectRoot, configs: {eslint: {scope: '@foo'}}, @@ -81,7 +94,7 @@ if (await thisIsAJavaScriptProject({projectRoot})) { lift: () => ({}) } } - }); + }, {logger}); } await scaffoldUnitTesting({ @@ -92,5 +105,5 @@ await scaffoldUnitTesting({ }, visibility: 'OSS', vcs: {host: 'GitHub', owner: 'foo', name: 'bar'}, - decisions: {[questionNames.UNIT_TEST_FRAMEWORK]: 'Mocha'} -}); + decisions: {[UNIT_TEST_FRAMEWORK]: 'Mocha'} +}, {logger}); diff --git a/src/index.js b/src/index.js index cf21fe357..444728133 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,5 @@ -export {questionNames} from './prompts/question-names.js'; +export {questionNames} from './prompts/index.js'; +export {constants as promptConstants} from './prompts/index.js'; export {scaffold as scaffoldUnitTesting} from './testing/unit/index.js'; export {default as scaffold} from './scaffolder.js'; export {default as lift} from './lifter.js'; diff --git a/src/project-type-plugin/prompt.js b/src/project-type-plugin/prompt.js index 9005c0c77..35bff931c 100644 --- a/src/project-type-plugin/prompt.js +++ b/src/project-type-plugin/prompt.js @@ -2,15 +2,19 @@ import {prompt} from '@form8ion/overridable-prompts'; import {questionNames} from '../prompts/question-names.js'; +export const PROJECT_TYPE_PLUGIN_PROMPT_ID = 'project-type-plugin'; + export default async function gatherProjectTypePluginInput({types, projectType, decisions}) { + const {PROJECT_TYPE_CHOICE} = questionNames.PROJECT_TYPE_PLUGIN; + if (!Object.keys(types).length) return 'Other'; const answers = await prompt([{ - name: questionNames.PROJECT_TYPE_CHOICE, + name: PROJECT_TYPE_CHOICE, type: 'list', message: `What type of ${projectType} is this?`, choices: [...Object.keys(types), 'Other'] }], decisions); - return answers[questionNames.PROJECT_TYPE_CHOICE]; + return answers[PROJECT_TYPE_CHOICE]; } diff --git a/src/project-type-plugin/prompt.test.js b/src/project-type-plugin/prompt.test.js index bb978ecf0..0795cdb05 100644 --- a/src/project-type-plugin/prompt.test.js +++ b/src/project-type-plugin/prompt.test.js @@ -11,15 +11,16 @@ vi.mock('@form8ion/overridable-prompts'); describe('project-type prompts', () => { it('should present the choice of project-type', async () => { + const {PROJECT_TYPE_CHOICE} = questionNames.PROJECT_TYPE_PLUGIN; const chosenType = any.word(); const projectType = any.word(); const decisions = any.simpleObject(); - const answers = {...any.simpleObject(), [questionNames.PROJECT_TYPE_CHOICE]: chosenType}; + const answers = {...any.simpleObject(), [PROJECT_TYPE_CHOICE]: chosenType}; const types = any.simpleObject(); when(prompts.prompt) .calledWith( [{ - name: questionNames.PROJECT_TYPE_CHOICE, + name: PROJECT_TYPE_CHOICE, type: 'list', message: `What type of ${projectType} is this?`, choices: [...Object.keys(types), 'Other'] diff --git a/src/project-type/publishable/bundler/prompt.js b/src/project-type/publishable/bundler/prompt.js index a182f5356..57f63fc9b 100644 --- a/src/project-type/publishable/bundler/prompt.js +++ b/src/project-type/publishable/bundler/prompt.js @@ -2,15 +2,19 @@ import {prompt} from '@form8ion/overridable-prompts'; import {questionNames} from '../../../prompts/question-names.js'; +export const PACKAGE_BUNDLER_PROMPT_ID = 'package-bundler'; + export default async function gatherBundlerInput({bundlers, decisions}) { + const {PACKAGE_BUNDLER} = questionNames.PACKAGE_BUNDLER; + if (!Object.keys(bundlers).length) return 'Other'; const answers = await prompt([{ - name: questionNames.PACKAGE_BUNDLER, + name: PACKAGE_BUNDLER, type: 'list', message: 'Which bundler should be used?', choices: [...Object.keys(bundlers), 'Other'] }], decisions); - return answers[questionNames.PACKAGE_BUNDLER]; + return answers[PACKAGE_BUNDLER]; } diff --git a/src/project-type/publishable/bundler/prompt.test.js b/src/project-type/publishable/bundler/prompt.test.js index d2e8f3f74..dabfe85bb 100644 --- a/src/project-type/publishable/bundler/prompt.test.js +++ b/src/project-type/publishable/bundler/prompt.test.js @@ -15,12 +15,13 @@ describe('bundler prompt', () => { }); it('should present the choice of package bundlers', async () => { + const {PACKAGE_BUNDLER} = questionNames.PACKAGE_BUNDLER; const chosenType = any.word(); const decisions = any.simpleObject(); - const answers = {...any.simpleObject(), [questionNames.PACKAGE_BUNDLER]: chosenType}; + const answers = {...any.simpleObject(), [PACKAGE_BUNDLER]: chosenType}; const bundlers = any.simpleObject(); when(prompts.prompt).calledWith([{ - name: questionNames.PACKAGE_BUNDLER, + name: PACKAGE_BUNDLER, type: 'list', message: 'Which bundler should be used?', choices: [...Object.keys(bundlers), 'Other'] diff --git a/src/prompts/conditionals.js b/src/prompts/conditionals.js index 83d8de0da..cf3ed5378 100644 --- a/src/prompts/conditionals.js +++ b/src/prompts/conditionals.js @@ -2,20 +2,22 @@ import {projectTypes} from '@form8ion/javascript-core'; import {questionNames} from './question-names.js'; +const {BASE_DETAILS} = questionNames; + function projectIsCLI(answers) { - return projectTypes.CLI === answers[questionNames.PROJECT_TYPE]; + return projectTypes.CLI === answers[BASE_DETAILS.PROJECT_TYPE]; } export function projectIsPackage(answers) { - return projectTypes.PACKAGE === answers[questionNames.PROJECT_TYPE]; + return projectTypes.PACKAGE === answers[BASE_DETAILS.PROJECT_TYPE]; } export function projectIsApplication(answers) { - return projectTypes.APPLICATION === answers[questionNames.PROJECT_TYPE]; + return projectTypes.APPLICATION === answers[BASE_DETAILS.PROJECT_TYPE]; } function packageShouldBeScoped(visibility, answers) { - return ['ISS', 'CS'].includes(visibility) || answers[questionNames.SHOULD_BE_SCOPED]; + return ['ISS', 'CS'].includes(visibility) || answers[BASE_DETAILS.SHOULD_BE_SCOPED]; } function willBePublishedToRegistry(answers) { @@ -31,8 +33,8 @@ export function scopePromptShouldBePresentedFactory(visibility) { } export function lintingPromptShouldBePresented({ - [questionNames.UNIT_TESTS]: unitTested, - [questionNames.INTEGRATION_TESTS]: integrationTested + [BASE_DETAILS.UNIT_TESTS]: unitTested, + [BASE_DETAILS.INTEGRATION_TESTS]: integrationTested }) { return !unitTested && !integrationTested; } diff --git a/src/prompts/conditionals.test.js b/src/prompts/conditionals.test.js index 23acee2b9..3c0f09e2a 100644 --- a/src/prompts/conditionals.test.js +++ b/src/prompts/conditionals.test.js @@ -11,104 +11,106 @@ import { shouldBeScopedPromptShouldBePresented } from './conditionals.js'; +const {BASE_DETAILS} = questionNames; + describe('javascript prompt conditionals', () => { describe('scope', () => { it('should present the prompt for whether the package should be scoped for `package` project-types', () => { - expect(shouldBeScopedPromptShouldBePresented({[questionNames.PROJECT_TYPE]: projectTypes.PACKAGE})).toBe(true); + expect(shouldBeScopedPromptShouldBePresented({[BASE_DETAILS.PROJECT_TYPE]: projectTypes.PACKAGE})).toBe(true); }); it('should present the prompt for whether the package should be scoped for `cli` project-types', () => { - expect(shouldBeScopedPromptShouldBePresented({[questionNames.PROJECT_TYPE]: projectTypes.CLI})).toBe(true); + expect(shouldBeScopedPromptShouldBePresented({[BASE_DETAILS.PROJECT_TYPE]: projectTypes.CLI})).toBe(true); }); it('shouldnt present the prompt for whether the package should be scoped for non-publishable project-types', () => { - expect(shouldBeScopedPromptShouldBePresented({[questionNames.PROJECT_TYPE]: any.string()})).toBe(false); + expect(shouldBeScopedPromptShouldBePresented({[BASE_DETAILS.PROJECT_TYPE]: any.string()})).toBe(false); }); it('should present a scope prompt when a package should be scoped', () => { expect(scopePromptShouldBePresentedFactory()({ - [questionNames.SHOULD_BE_SCOPED]: true, - [questionNames.PROJECT_TYPE]: projectTypes.PACKAGE + [BASE_DETAILS.SHOULD_BE_SCOPED]: true, + [BASE_DETAILS.PROJECT_TYPE]: projectTypes.PACKAGE })).toBe(true); }); it('should present a scope prompt when a package is inner source, because they must be scoped', () => { expect(scopePromptShouldBePresentedFactory('ISS')({ - [questionNames.SHOULD_BE_SCOPED]: false, - [questionNames.PROJECT_TYPE]: projectTypes.PACKAGE + [BASE_DETAILS.SHOULD_BE_SCOPED]: false, + [BASE_DETAILS.PROJECT_TYPE]: projectTypes.PACKAGE })).toBe(true); }); it('should present a scope prompt when a package is closed source, because they must be scoped', () => { expect(scopePromptShouldBePresentedFactory('CS')({ - [questionNames.SHOULD_BE_SCOPED]: false, - [questionNames.PROJECT_TYPE]: projectTypes.PACKAGE + [BASE_DETAILS.SHOULD_BE_SCOPED]: false, + [BASE_DETAILS.PROJECT_TYPE]: projectTypes.PACKAGE })).toBe(true); }); it('should present a scope prompt when a CLI should be scoped', () => { expect(scopePromptShouldBePresentedFactory()({ - [questionNames.SHOULD_BE_SCOPED]: true, - [questionNames.PROJECT_TYPE]: projectTypes.CLI + [BASE_DETAILS.SHOULD_BE_SCOPED]: true, + [BASE_DETAILS.PROJECT_TYPE]: projectTypes.CLI })).toBe(true); }); it('should present a scope prompt when a CLI is closed source, because they must be scoped', () => { expect(scopePromptShouldBePresentedFactory('CS')({ - [questionNames.SHOULD_BE_SCOPED]: false, - [questionNames.PROJECT_TYPE]: projectTypes.CLI + [BASE_DETAILS.SHOULD_BE_SCOPED]: false, + [BASE_DETAILS.PROJECT_TYPE]: projectTypes.CLI })).toBe(true); }); it('should present a scope prompt when a CLI is inner source, because they must be scoped', () => { expect(scopePromptShouldBePresentedFactory('ISS')({ - [questionNames.SHOULD_BE_SCOPED]: false, - [questionNames.PROJECT_TYPE]: projectTypes.CLI + [BASE_DETAILS.SHOULD_BE_SCOPED]: false, + [BASE_DETAILS.PROJECT_TYPE]: projectTypes.CLI })).toBe(true); }); it('should not present a scope prompt when an application is closed source', () => { expect(scopePromptShouldBePresentedFactory('CS')({ - [questionNames.SHOULD_BE_SCOPED]: false, - [questionNames.PROJECT_TYPE]: projectTypes.APPLICATION + [BASE_DETAILS.SHOULD_BE_SCOPED]: false, + [BASE_DETAILS.PROJECT_TYPE]: projectTypes.APPLICATION })).toBe(false); }); it('should not present a scope prompt when an application is inner source', () => { expect(scopePromptShouldBePresentedFactory('ISS')({ - [questionNames.SHOULD_BE_SCOPED]: false, - [questionNames.PROJECT_TYPE]: projectTypes.APPLICATION + [BASE_DETAILS.SHOULD_BE_SCOPED]: false, + [BASE_DETAILS.PROJECT_TYPE]: projectTypes.APPLICATION })).toBe(false); }); it('should not preset a scope prompt for non-publishable projects', () => { - expect(scopePromptShouldBePresentedFactory()({[questionNames.SHOULD_BE_SCOPED]: false})).toBe(false); + expect(scopePromptShouldBePresentedFactory()({[BASE_DETAILS.SHOULD_BE_SCOPED]: false})).toBe(false); }); }); describe('application', () => { it('should return `true` when the package-type is `Application`', () => { - expect(projectIsApplication({[questionNames.PROJECT_TYPE]: projectTypes.APPLICATION})).toBe(true); + expect(projectIsApplication({[BASE_DETAILS.PROJECT_TYPE]: projectTypes.APPLICATION})).toBe(true); }); it('should return `false` when the project-type is not an application', () => { - expect(projectIsApplication({[questionNames.PROJECT_TYPE]: any.word()})).toBe(false); + expect(projectIsApplication({[BASE_DETAILS.PROJECT_TYPE]: any.word()})).toBe(false); }); }); describe('transpilation/linting', () => { it('should not show the prompt if the project is unit tested ', () => { - expect(lintingPromptShouldBePresented({[questionNames.UNIT_TESTS]: true})).toBe(false); + expect(lintingPromptShouldBePresented({[BASE_DETAILS.UNIT_TESTS]: true})).toBe(false); }); it('should not show the prompt if the project is integration tested', () => { - expect(lintingPromptShouldBePresented({[questionNames.INTEGRATION_TESTS]: true})).toBe(false); + expect(lintingPromptShouldBePresented({[BASE_DETAILS.INTEGRATION_TESTS]: true})).toBe(false); }); it('should show the prompt if the project is not tested', () => { expect(lintingPromptShouldBePresented({ - [questionNames.INTEGRATION_TESTS]: false, - [questionNames.UNIT_TESTS]: false + [BASE_DETAILS.INTEGRATION_TESTS]: false, + [BASE_DETAILS.UNIT_TESTS]: false })).toBe(true); }); }); diff --git a/src/prompts/index.js b/src/prompts/index.js new file mode 100644 index 000000000..3091b5b58 --- /dev/null +++ b/src/prompts/index.js @@ -0,0 +1,18 @@ +import {PROJECT_TYPE_PLUGIN_PROMPT_ID} from '../project-type-plugin/prompt.js'; +import {PACKAGE_BUNDLER_PROMPT_ID} from '../project-type/publishable/bundler/prompt.js'; +import {UNIT_TESTING_PROMPT_ID} from '../testing/unit/prompt.js'; +import {INTEGRATION_TESTING_PROMPT_ID} from '../testing/integration/prompt.js'; +import {BASE_DETAILS_PROMPT_ID} from './questions.js'; +import {questionNames} from './question-names.js'; + +export const ids = { + BASE_DETAILS: BASE_DETAILS_PROMPT_ID, + PROJECT_TYPE_PLUGIN: PROJECT_TYPE_PLUGIN_PROMPT_ID, + PACKAGE_BUNDLER: PACKAGE_BUNDLER_PROMPT_ID, + UNIT_TESTING: UNIT_TESTING_PROMPT_ID, + INTEGRATION_TESTING: INTEGRATION_TESTING_PROMPT_ID +}; + +export {questionNames}; + +export const constants = {ids, questionNames}; diff --git a/src/prompts/index.test.js b/src/prompts/index.test.js new file mode 100644 index 000000000..4b5af6082 --- /dev/null +++ b/src/prompts/index.test.js @@ -0,0 +1,21 @@ +import {describe, expect, it} from 'vitest'; + +import {BASE_DETAILS_PROMPT_ID} from './questions.js'; +import {PROJECT_TYPE_PLUGIN_PROMPT_ID} from '../project-type-plugin/prompt.js'; +import {PACKAGE_BUNDLER_PROMPT_ID} from '../project-type/publishable/bundler/prompt.js'; +import {UNIT_TESTING_PROMPT_ID} from '../testing/unit/prompt.js'; +import {INTEGRATION_TESTING_PROMPT_ID} from '../testing/integration/prompt.js'; +import {constants, ids, questionNames} from './index.js'; + +describe('prompt constants', () => { + it('should aggregate the prompt ids and grouped question names', () => { + expect(ids).toEqual({ + BASE_DETAILS: BASE_DETAILS_PROMPT_ID, + PROJECT_TYPE_PLUGIN: PROJECT_TYPE_PLUGIN_PROMPT_ID, + PACKAGE_BUNDLER: PACKAGE_BUNDLER_PROMPT_ID, + UNIT_TESTING: UNIT_TESTING_PROMPT_ID, + INTEGRATION_TESTING: INTEGRATION_TESTING_PROMPT_ID + }); + expect(constants).toEqual({ids, questionNames}); + }); +}); diff --git a/src/prompts/question-names.js b/src/prompts/question-names.js index 0d26048fb..cab0b9338 100644 --- a/src/prompts/question-names.js +++ b/src/prompts/question-names.js @@ -1,20 +1,30 @@ export const questionNames = { - UNIT_TESTS: 'unitTests', - INTEGRATION_TESTS: 'integrationTests', - UNIT_TEST_FRAMEWORK: 'unitTestFramework', - INTEGRATION_TEST_FRAMEWORK: 'integrationTestFramework', - NODE_VERSION_CATEGORY: 'nodeVersionCategory', - PACKAGE_MANAGER: 'packageManager', - PACKAGE_BUNDLER: 'packageBundler', - PROJECT_TYPE: 'projectType', - PROJECT_TYPE_CHOICE: 'projectTypeChoice', - SHOULD_BE_SCOPED: 'shouldBeScoped', - SCOPE: 'scope', - AUTHOR_NAME: 'authorName', - AUTHOR_EMAIL: 'authorEmail', - AUTHOR_URL: 'authorUrl', - HOST: 'host', - CONFIGURE_LINTING: 'configureLint', - PROVIDE_EXAMPLE: 'provideExample', - DIALECT: 'dialect' + BASE_DETAILS: { + UNIT_TESTS: 'unitTests', + INTEGRATION_TESTS: 'integrationTests', + NODE_VERSION_CATEGORY: 'nodeVersionCategory', + PACKAGE_MANAGER: 'packageManager', + PROJECT_TYPE: 'projectType', + SHOULD_BE_SCOPED: 'shouldBeScoped', + SCOPE: 'scope', + AUTHOR_NAME: 'authorName', + AUTHOR_EMAIL: 'authorEmail', + AUTHOR_URL: 'authorUrl', + HOST: 'host', + CONFIGURE_LINTING: 'configureLint', + PROVIDE_EXAMPLE: 'provideExample', + DIALECT: 'dialect' + }, + UNIT_TESTING: { + UNIT_TEST_FRAMEWORK: 'unitTestFramework' + }, + INTEGRATION_TESTING: { + INTEGRATION_TEST_FRAMEWORK: 'integrationTestFramework' + }, + PROJECT_TYPE_PLUGIN: { + PROJECT_TYPE_CHOICE: 'projectTypeChoice' + }, + PACKAGE_BUNDLER: { + PACKAGE_BUNDLER: 'packageBundler' + } }; diff --git a/src/prompts/question-names.test.js b/src/prompts/question-names.test.js new file mode 100644 index 000000000..5b459973c --- /dev/null +++ b/src/prompts/question-names.test.js @@ -0,0 +1,38 @@ +import {describe, expect, it} from 'vitest'; + +import {questionNames} from './question-names.js'; + +describe('question names', () => { + it('should group question names by prompt area', () => { + expect(questionNames).toEqual({ + BASE_DETAILS: { + UNIT_TESTS: 'unitTests', + INTEGRATION_TESTS: 'integrationTests', + NODE_VERSION_CATEGORY: 'nodeVersionCategory', + PACKAGE_MANAGER: 'packageManager', + PROJECT_TYPE: 'projectType', + SHOULD_BE_SCOPED: 'shouldBeScoped', + SCOPE: 'scope', + AUTHOR_NAME: 'authorName', + AUTHOR_EMAIL: 'authorEmail', + AUTHOR_URL: 'authorUrl', + HOST: 'host', + CONFIGURE_LINTING: 'configureLint', + PROVIDE_EXAMPLE: 'provideExample', + DIALECT: 'dialect' + }, + UNIT_TESTING: { + UNIT_TEST_FRAMEWORK: 'unitTestFramework' + }, + INTEGRATION_TESTING: { + INTEGRATION_TEST_FRAMEWORK: 'integrationTestFramework' + }, + PROJECT_TYPE_PLUGIN: { + PROJECT_TYPE_CHOICE: 'projectTypeChoice' + }, + PACKAGE_BUNDLER: { + PACKAGE_BUNDLER: 'packageBundler' + } + }); + }); +}); diff --git a/src/prompts/questions.js b/src/prompts/questions.js index a046659ff..782b9c687 100644 --- a/src/prompts/questions.js +++ b/src/prompts/questions.js @@ -14,20 +14,24 @@ import { import {questionNames} from './question-names.js'; import {scope as validateScope} from './validators.js'; +export const BASE_DETAILS_PROMPT_ID = 'base-details'; + +const {BASE_DETAILS} = questionNames; + function authorQuestions({name, email, url}) { return [ { - name: questionNames.AUTHOR_NAME, + name: BASE_DETAILS.AUTHOR_NAME, message: 'What is the author\'s name?', default: name }, { - name: questionNames.AUTHOR_EMAIL, + name: BASE_DETAILS.AUTHOR_EMAIL, message: 'What is the author\'s email?', default: email }, { - name: questionNames.AUTHOR_URL, + name: BASE_DETAILS.AUTHOR_URL, message: 'What is the author\'s website url?', default: url } @@ -49,64 +53,64 @@ export async function prompt( try { maybeLoggedInNpmUsername = (await execa('npm', ['whoami'])).stdout; } catch (failedExecutionResult) { - if (!decisions[questionNames.SCOPE]) { + if (!decisions[BASE_DETAILS.SCOPE]) { logger.warn('No logged in user found with `npm whoami`. Login with `npm login` ' + 'to use your npm account name as the package scope default.'); } } const { - [questionNames.UNIT_TESTS]: unitTested, - [questionNames.INTEGRATION_TESTS]: integrationTested, - [questionNames.PROJECT_TYPE]: projectType, - [questionNames.HOST]: chosenHost, - [questionNames.SCOPE]: scope, - [questionNames.NODE_VERSION_CATEGORY]: nodeVersionCategory, - [questionNames.AUTHOR_NAME]: authorName, - [questionNames.AUTHOR_EMAIL]: authorEmail, - [questionNames.AUTHOR_URL]: authorUrl, - [questionNames.CONFIGURE_LINTING]: configureLinting, - [questionNames.PROVIDE_EXAMPLE]: provideExample, - [questionNames.PACKAGE_MANAGER]: packageManager, - [questionNames.DIALECT]: dialect + [BASE_DETAILS.UNIT_TESTS]: unitTested, + [BASE_DETAILS.INTEGRATION_TESTS]: integrationTested, + [BASE_DETAILS.PROJECT_TYPE]: projectType, + [BASE_DETAILS.HOST]: chosenHost, + [BASE_DETAILS.SCOPE]: scope, + [BASE_DETAILS.NODE_VERSION_CATEGORY]: nodeVersionCategory, + [BASE_DETAILS.AUTHOR_NAME]: authorName, + [BASE_DETAILS.AUTHOR_EMAIL]: authorEmail, + [BASE_DETAILS.AUTHOR_URL]: authorUrl, + [BASE_DETAILS.CONFIGURE_LINTING]: configureLinting, + [BASE_DETAILS.PROVIDE_EXAMPLE]: provideExample, + [BASE_DETAILS.PACKAGE_MANAGER]: packageManager, + [BASE_DETAILS.DIALECT]: dialect } = await promptWithInquirer([ { - name: questionNames.DIALECT, + name: BASE_DETAILS.DIALECT, message: 'Which JavaScript dialect should this project follow?', type: 'list', choices: buildDialectChoices(configs), default: 'babel' }, ...pathWithinParent ? [] : [{ - name: questionNames.NODE_VERSION_CATEGORY, + name: BASE_DETAILS.NODE_VERSION_CATEGORY, message: 'What node.js version should be used?', type: 'list', choices: ['LTS', 'Latest'], default: 'LTS' }], { - name: questionNames.PACKAGE_MANAGER, + name: BASE_DETAILS.PACKAGE_MANAGER, message: 'Which package manager will be used with this project?', type: 'list', choices: Object.values(packageManagers), default: packageManagers.NPM }, { - name: questionNames.PROJECT_TYPE, + name: BASE_DETAILS.PROJECT_TYPE, message: 'What type of JavaScript project is this?', type: 'list', choices: [...Object.values(projectTypes), 'Other'], default: projectTypes.PACKAGE }, ...['ISS', 'CS'].includes(visibility) ? [] : [{ - name: questionNames.SHOULD_BE_SCOPED, + name: BASE_DETAILS.SHOULD_BE_SCOPED, message: 'Should this package be scoped?', type: 'confirm', when: shouldBeScopedPromptShouldBePresented, default: true }], { - name: questionNames.SCOPE, + name: BASE_DETAILS.SCOPE, message: 'What is the scope?', when: scopePromptShouldBePresentedFactory(visibility), validate: validateScope(visibility), @@ -118,31 +122,31 @@ export async function prompt( url: npmConf.get('init.author.url') }), { - name: questionNames.UNIT_TESTS, + name: BASE_DETAILS.UNIT_TESTS, message: 'Will this project be unit tested?', type: 'confirm', default: true }, { - name: questionNames.INTEGRATION_TESTS, + name: BASE_DETAILS.INTEGRATION_TESTS, message: 'Will this project be integration tested?', type: 'confirm', default: true }, { - name: questionNames.CONFIGURE_LINTING, + name: BASE_DETAILS.CONFIGURE_LINTING, message: 'Will there be source code that should be linted?', type: 'confirm', when: lintingPromptShouldBePresented }, { - name: questionNames.PROVIDE_EXAMPLE, + name: BASE_DETAILS.PROVIDE_EXAMPLE, message: 'Should an example be provided in the README?', type: 'confirm', when: projectIsPackage }, { - name: questionNames.HOST, + name: BASE_DETAILS.HOST, type: 'list', message: 'Where will the application be hosted?', when: projectIsApplication, diff --git a/src/prompts/questions.test.js b/src/prompts/questions.test.js index 704889cd2..b46b46c06 100644 --- a/src/prompts/questions.test.js +++ b/src/prompts/questions.test.js @@ -13,6 +13,8 @@ import * as conditionals from './conditionals.js'; import {prompt} from './questions.js'; import * as validators from './validators.js'; +const {BASE_DETAILS} = questionNames; + vi.mock('execa'); vi.mock('@form8ion/overridable-prompts'); vi.mock('../../thirdparty-wrappers/npm-conf.js'); @@ -41,19 +43,19 @@ describe('prompts', () => { const scope = any.word(); const provideExample = any.boolean(); const answers = { - [questionNames.UNIT_TESTS]: unitTested, - [questionNames.INTEGRATION_TESTS]: integrationTested, - [questionNames.PROJECT_TYPE]: projectType, - [questionNames.CI_SERVICE]: ci, - [questionNames.HOST]: chosenHost, - [questionNames.SCOPE]: scope, - [questionNames.NODE_VERSION_CATEGORY]: nodeVersionCategory, - [questionNames.AUTHOR_NAME]: authorName, - [questionNames.AUTHOR_EMAIL]: authorEmail, - [questionNames.AUTHOR_URL]: authorUrl, - [questionNames.PACKAGE_MANAGER]: packageManager, - [questionNames.DIALECT]: dialect, - [questionNames.PROVIDE_EXAMPLE]: provideExample + [BASE_DETAILS.UNIT_TESTS]: unitTested, + [BASE_DETAILS.INTEGRATION_TESTS]: integrationTested, + [BASE_DETAILS.PROJECT_TYPE]: projectType, + [ci]: ci, + [BASE_DETAILS.HOST]: chosenHost, + [BASE_DETAILS.SCOPE]: scope, + [BASE_DETAILS.NODE_VERSION_CATEGORY]: nodeVersionCategory, + [BASE_DETAILS.AUTHOR_NAME]: authorName, + [BASE_DETAILS.AUTHOR_EMAIL]: authorEmail, + [BASE_DETAILS.AUTHOR_URL]: authorUrl, + [BASE_DETAILS.PACKAGE_MANAGER]: packageManager, + [BASE_DETAILS.DIALECT]: dialect, + [BASE_DETAILS.PROVIDE_EXAMPLE]: provideExample }; const logger = {info: () => undefined, warn: () => undefined}; @@ -78,95 +80,95 @@ describe('prompts', () => { when(prompts.prompt) .calledWith([ { - name: questionNames.DIALECT, + name: BASE_DETAILS.DIALECT, message: 'Which JavaScript dialect should this project follow?', type: 'list', choices: dialects, default: 'babel' }, { - name: questionNames.NODE_VERSION_CATEGORY, + name: BASE_DETAILS.NODE_VERSION_CATEGORY, message: 'What node.js version should be used?', type: 'list', choices: ['LTS', 'Latest'], default: 'LTS' }, { - name: questionNames.PACKAGE_MANAGER, + name: BASE_DETAILS.PACKAGE_MANAGER, message: 'Which package manager will be used with this project?', type: 'list', choices: Object.values(packageManagers), default: packageManagers.NPM }, { - name: questionNames.PROJECT_TYPE, + name: BASE_DETAILS.PROJECT_TYPE, message: 'What type of JavaScript project is this?', type: 'list', choices: [...Object.values(projectTypes), 'Other'], default: projectTypes.PACKAGE }, { - name: questionNames.SHOULD_BE_SCOPED, + name: BASE_DETAILS.SHOULD_BE_SCOPED, message: 'Should this package be scoped?', type: 'confirm', when: conditionals.shouldBeScopedPromptShouldBePresented, default: true }, { - name: questionNames.SCOPE, + name: BASE_DETAILS.SCOPE, message: 'What is the scope?', when: scopePromptShouldBePresented, validate: scopeValidator, default: npmUser }, { - name: questionNames.AUTHOR_NAME, + name: BASE_DETAILS.AUTHOR_NAME, message: 'What is the author\'s name?', default: authorName }, { - name: questionNames.AUTHOR_EMAIL, + name: BASE_DETAILS.AUTHOR_EMAIL, message: 'What is the author\'s email?', default: authorEmail }, { - name: questionNames.AUTHOR_URL, + name: BASE_DETAILS.AUTHOR_URL, message: 'What is the author\'s website url?', default: authorUrl }, { - name: questionNames.UNIT_TESTS, + name: BASE_DETAILS.UNIT_TESTS, message: 'Will this project be unit tested?', type: 'confirm', default: true }, { - name: questionNames.INTEGRATION_TESTS, + name: BASE_DETAILS.INTEGRATION_TESTS, message: 'Will this project be integration tested?', type: 'confirm', default: true }, { - name: questionNames.CONFIGURE_LINTING, + name: BASE_DETAILS.CONFIGURE_LINTING, message: 'Will there be source code that should be linted?', type: 'confirm', when: conditionals.lintingPromptShouldBePresented }, { - name: questionNames.PROVIDE_EXAMPLE, + name: BASE_DETAILS.PROVIDE_EXAMPLE, message: 'Should an example be provided in the README?', type: 'confirm', when: conditionals.projectIsPackage }, { - name: questionNames.HOST, + name: BASE_DETAILS.HOST, type: 'list', message: 'Where will the application be hosted?', when: conditionals.projectIsApplication, choices: [...Object.keys(hosts), 'Other'] } ], decisions) - .thenResolve({...answers, [questionNames.CONFIGURE_LINTING]: any.word()}); + .thenResolve({...answers, [BASE_DETAILS.CONFIGURE_LINTING]: any.word()}); expect(await prompt(hosts, visibility, vcs, decisions, configs, undefined, {logger})).toEqual({ tests, @@ -187,7 +189,7 @@ describe('prompts', () => { const get = vi.fn(); npmConfFactory.mockReturnValue({get}); when(execa).calledWith('npm', ['whoami']).thenResolve({stdout: npmUser}); - prompts.prompt.mockResolvedValue({...answers, [questionNames.CONFIGURE_LINTING]: false}); + prompts.prompt.mockResolvedValue({...answers, [BASE_DETAILS.CONFIGURE_LINTING]: false}); expect(await prompt({}, visibility, vcs, decisions, undefined, undefined, {logger})).toEqual({ tests, @@ -211,7 +213,7 @@ describe('prompts', () => { await prompt({}, 'CS', vcs, null, null, pathWithinParent, {logger}); const [questions] = prompts.prompt.mock.lastCall; - expect(questions.filter(question => questionNames.NODE_VERSION_CATEGORY === question.name).length).toEqual(0); + expect(questions.filter(question => BASE_DETAILS.NODE_VERSION_CATEGORY === question.name).length).toEqual(0); }); it('should not ask whether closed source packages should be scoped', async () => { @@ -222,7 +224,7 @@ describe('prompts', () => { await prompt({}, 'CS', vcs, null, null, pathWithinParent, {logger}); const [questions] = prompts.prompt.mock.lastCall; - expect(questions.filter(question => questionNames.SHOULD_BE_SCOPED === question.name).length).toEqual(0); + expect(questions.filter(question => BASE_DETAILS.SHOULD_BE_SCOPED === question.name).length).toEqual(0); }); it('should not ask whether inner source packages should be scoped', async () => { @@ -233,7 +235,7 @@ describe('prompts', () => { await prompt({}, 'ISS', vcs, null, null, pathWithinParent, {logger}); const [questions] = prompts.prompt.mock.lastCall; - expect(questions.filter(question => questionNames.SHOULD_BE_SCOPED === question.name).length).toEqual(0); + expect(questions.filter(question => BASE_DETAILS.SHOULD_BE_SCOPED === question.name).length).toEqual(0); }); it('should handle a non-logged-in user gracefully', async () => { @@ -244,6 +246,6 @@ describe('prompts', () => { await prompt({}, 'OSS', vcs, {}, null, pathWithinParent, {logger}); const [questions] = prompts.prompt.mock.lastCall; - expect(questions.filter(question => questionNames.SHOULD_BE_SCOPED === question.name).length).toEqual(1); + expect(questions.filter(question => BASE_DETAILS.SHOULD_BE_SCOPED === question.name).length).toEqual(1); }); }); diff --git a/src/testing/integration/prompt.js b/src/testing/integration/prompt.js index c3c67159b..1db0ba8cb 100644 --- a/src/testing/integration/prompt.js +++ b/src/testing/integration/prompt.js @@ -1,15 +1,19 @@ import {prompt} from '@form8ion/overridable-prompts'; import {questionNames} from '../../prompts/question-names.js'; +export const INTEGRATION_TESTING_PROMPT_ID = 'integration-testing'; + export default async function gatherUnitTestingInput({frameworks, decisions}) { + const {INTEGRATION_TEST_FRAMEWORK} = questionNames.INTEGRATION_TESTING; + if (!Object.keys(frameworks).length) return 'Other'; const answers = await prompt([{ - name: questionNames.INTEGRATION_TEST_FRAMEWORK, + name: INTEGRATION_TEST_FRAMEWORK, type: 'list', message: 'Which integration testing framework should be used?', choices: [...Object.keys(frameworks), 'Other'] }], decisions); - return answers[questionNames.INTEGRATION_TEST_FRAMEWORK]; + return answers[INTEGRATION_TEST_FRAMEWORK]; } diff --git a/src/testing/integration/prompt.test.js b/src/testing/integration/prompt.test.js index 7aee499d5..8a26e543f 100644 --- a/src/testing/integration/prompt.test.js +++ b/src/testing/integration/prompt.test.js @@ -11,13 +11,14 @@ vi.mock('@form8ion/overridable-prompts'); describe('integration-test framework prompt', () => { it('should preset the choice of integration-test framework', async () => { + const {INTEGRATION_TEST_FRAMEWORK} = questionNames.INTEGRATION_TESTING; const chosenType = any.word(); const decisions = any.simpleObject(); - const answers = {...any.simpleObject(), [questionNames.INTEGRATION_TEST_FRAMEWORK]: chosenType}; + const answers = {...any.simpleObject(), [INTEGRATION_TEST_FRAMEWORK]: chosenType}; const frameworks = any.simpleObject(); when(prompts.prompt) .calledWith([{ - name: questionNames.INTEGRATION_TEST_FRAMEWORK, + name: INTEGRATION_TEST_FRAMEWORK, type: 'list', message: 'Which integration testing framework should be used?', choices: [...Object.keys(frameworks), 'Other'] diff --git a/src/testing/unit/prompt.js b/src/testing/unit/prompt.js index ddf936633..e616bce7c 100644 --- a/src/testing/unit/prompt.js +++ b/src/testing/unit/prompt.js @@ -1,15 +1,19 @@ import {prompt} from '@form8ion/overridable-prompts'; import {questionNames} from '../../prompts/question-names.js'; +export const UNIT_TESTING_PROMPT_ID = 'unit-testing'; + export default async function gatherUnitTestingInput({frameworks, decisions}) { + const {UNIT_TEST_FRAMEWORK} = questionNames.UNIT_TESTING; + if (!Object.keys(frameworks).length) return 'Other'; const answers = await prompt([{ - name: questionNames.UNIT_TEST_FRAMEWORK, + name: UNIT_TEST_FRAMEWORK, type: 'list', message: 'Which unit testing framework should be used?', choices: [...Object.keys(frameworks), 'Other'] }], decisions); - return answers[questionNames.UNIT_TEST_FRAMEWORK]; + return answers[UNIT_TEST_FRAMEWORK]; } diff --git a/src/testing/unit/prompt.test.js b/src/testing/unit/prompt.test.js index d9d1e0030..899062c4c 100644 --- a/src/testing/unit/prompt.test.js +++ b/src/testing/unit/prompt.test.js @@ -11,13 +11,14 @@ vi.mock('@form8ion/overridable-prompts'); describe('unit-test framework prompts', () => { it('should preset the choice of unit-test framework', async () => { + const {UNIT_TEST_FRAMEWORK} = questionNames.UNIT_TESTING; const chosenType = any.word(); const decisions = any.simpleObject(); - const answers = {...any.simpleObject(), [questionNames.UNIT_TEST_FRAMEWORK]: chosenType}; + const answers = {...any.simpleObject(), [UNIT_TEST_FRAMEWORK]: chosenType}; const frameworks = any.simpleObject(); when(prompts.prompt) .calledWith([{ - name: questionNames.UNIT_TEST_FRAMEWORK, + name: UNIT_TEST_FRAMEWORK, type: 'list', message: 'Which unit testing framework should be used?', choices: [...Object.keys(frameworks), 'Other'] diff --git a/test/integration/features/step_definitions/common-steps.js b/test/integration/features/step_definitions/common-steps.js index c6dab7631..c65dc68b0 100644 --- a/test/integration/features/step_definitions/common-steps.js +++ b/test/integration/features/step_definitions/common-steps.js @@ -27,7 +27,7 @@ import { import {assertThatProperDirectoriesAreIgnoredFromEslint} from './eslint-steps.js'; import {assertHomepageDefinedProperly} from './project-type-steps.js'; -let scaffold, lift, test, questionNames; +let scaffold, lift, test, promptConstants; const __dirname = dirname(fileURLToPath(import.meta.url)); // eslint-disable-line no-underscore-dangle const pathToProjectRoot = [__dirname, '..', '..', '..', '..']; const pathToNodeModules = [...pathToProjectRoot, 'node_modules']; @@ -44,6 +44,58 @@ function escapeSpecialCharacters(string) { return string.replace(/[.*+?^$\-{}()|[\]\\]/g, '\\$&'); } +function buildScaffoldingDecisions(context, shouldBeScopedAnswer) { + const {questionNames} = promptConstants; + const { + NODE_VERSION_CATEGORY, + PROJECT_TYPE, + AUTHOR_NAME, + AUTHOR_EMAIL, + AUTHOR_URL, + UNIT_TESTS, + INTEGRATION_TESTS, + CONFIGURE_LINTING, + PROVIDE_EXAMPLE, + HOST, + SHOULD_BE_SCOPED, + SCOPE, + PACKAGE_MANAGER, + DIALECT + } = questionNames.BASE_DETAILS; + const {UNIT_TEST_FRAMEWORK} = questionNames.UNIT_TESTING; + const {INTEGRATION_TEST_FRAMEWORK} = questionNames.INTEGRATION_TESTING; + const {PROJECT_TYPE_CHOICE} = questionNames.PROJECT_TYPE_PLUGIN; + const {PACKAGE_BUNDLER} = questionNames.PACKAGE_BUNDLER; + + return { + [NODE_VERSION_CATEGORY]: 'LTS', + [PROJECT_TYPE]: context.projectType, + [AUTHOR_NAME]: any.word(), + [AUTHOR_EMAIL]: any.email(), + [AUTHOR_URL]: any.url(), + [UNIT_TESTS]: context.unitTestAnswer, + ...context.unitTestAnswer && {[UNIT_TEST_FRAMEWORK]: context.unitTestFrameworkAnswer}, + [INTEGRATION_TESTS]: context.integrationTestAnswer, + ...context.integrationTestAnswer && context.integrationTestFrameworkAnswer && { + [INTEGRATION_TEST_FRAMEWORK]: context.integrationTestFrameworkAnswer + }, + [CONFIGURE_LINTING]: context.configureLinting, + [PROVIDE_EXAMPLE]: context.provideExample, + [PROJECT_TYPE_CHOICE]: context.projectTypeChoiceAnswer + || context.packageTypeChoiceAnswer + || context.applicationTypeChoiceAnswer + || 'Other', + [HOST]: 'Other', + ...['Package', 'CLI'].includes(context.projectType) && { + [SHOULD_BE_SCOPED]: shouldBeScopedAnswer, + ...shouldBeScopedAnswer && {[SCOPE]: context.npmAccount} + }, + ...context.packageManager && {[PACKAGE_MANAGER]: context.packageManager}, + [DIALECT]: context.dialect, + [PACKAGE_BUNDLER]: context.packageBundler + }; +} + export function assertDevDependencyIsInstalled(execa, dependencyName) { td.verify( execa(td.matchers.contains( @@ -60,7 +112,7 @@ Before(async function () { this.projectRoot = process.cwd(); // eslint-disable-next-line import/no-extraneous-dependencies,import/no-unresolved - ({scaffold, lift, test, questionNames} = await import('@form8ion/javascript')); + ({scaffold, lift, test, promptConstants} = await import('@form8ion/javascript')); stubbedFs({ node_modules: stubbedNodeModules @@ -154,30 +206,7 @@ When(/^the project is scaffolded$/, async function () { ciServices: this.ciServicePlugins || {[any.word()]: {scaffold: foo => ({foo})}}, registries: {[any.word()]: {scaffold: foo => ({foo})}} }, - decisions: { - [questionNames.NODE_VERSION_CATEGORY]: 'LTS', - [questionNames.PROJECT_TYPE]: this.projectType, - [questionNames.AUTHOR_NAME]: any.word(), - [questionNames.AUTHOR_EMAIL]: any.email(), - [questionNames.AUTHOR_URL]: any.url(), - [questionNames.UNIT_TESTS]: this.unitTestAnswer, - ...this.unitTestAnswer && {[questionNames.UNIT_TEST_FRAMEWORK]: this.unitTestFrameworkAnswer}, - [questionNames.INTEGRATION_TESTS]: this.integrationTestAnswer, - [questionNames.CONFIGURE_LINTING]: this.configureLinting, - [questionNames.PROVIDE_EXAMPLE]: this.provideExample, - [questionNames.PROJECT_TYPE_CHOICE]: this.projectTypeChoiceAnswer - || this.packageTypeChoiceAnswer - || this.applicationTypeChoiceAnswer - || 'Other', - [questionNames.HOST]: 'Other', - ...['Package', 'CLI'].includes(this.projectType) && { - [questionNames.SHOULD_BE_SCOPED]: shouldBeScopedAnswer, - ...shouldBeScopedAnswer && {[questionNames.SCOPE]: this.npmAccount} - }, - ...this.packageManager && {[questionNames.PACKAGE_MANAGER]: this.packageManager}, - [questionNames.DIALECT]: this.dialect, - [questionNames.PACKAGE_BUNDLER]: this.packageBundler - } + decisions: buildScaffoldingDecisions(this, shouldBeScopedAnswer) }, {logger}); this.liftResult = await lift({