Skip to content

Commit 70c7b75

Browse files
committed
feat(languages): moved the languages plugins under the plugins property
BREAKING CHANGE: languages now must be provided under the `plugins` property and as full plugins rather than a direct scaffolder function
1 parent 7330434 commit 70c7b75

11 files changed

+60
-40
lines changed

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,12 @@ import {lift, questionNames, scaffold} from '@form8ion/project';
8888
[questionNames.COPYRIGHT_YEAR]: '2022',
8989
[questionNames.PROJECT_LANGUAGE]: 'foo'
9090
},
91-
languages: {
92-
foo: options => options
93-
},
9491
plugins: {
9592
dependencyUpdaters: {
9693
bar: {scaffold: options => options}
94+
},
95+
languages: {
96+
foo: {scaffold: options => options}
9797
}
9898
}
9999
});

example.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ import {lift, questionNames, scaffold} from './lib/index.js';
2222
[questionNames.COPYRIGHT_YEAR]: '2022',
2323
[questionNames.PROJECT_LANGUAGE]: 'foo'
2424
},
25-
languages: {
26-
foo: options => options
27-
},
2825
plugins: {
2926
dependencyUpdaters: {
3027
bar: {scaffold: options => options}
28+
},
29+
languages: {
30+
foo: {scaffold: options => options}
3131
}
3232
}
3333
});

src/language/scaffolder.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
export default function (scaffolders, chosenLanguage, options) {
2-
const scaffolder = scaffolders[chosenLanguage];
1+
export default function (languagePlugins, chosenLanguage, options) {
2+
const plugin = languagePlugins[chosenLanguage];
33

4-
if (scaffolder) return scaffolder(options);
4+
if (plugin) return plugin.scaffold(options);
55

66
return undefined;
77
}

src/language/scaffolder.test.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ describe('language scaffolder', () => {
1010
const chosenLanguage = any.word();
1111
const scaffolderResult = any.simpleObject();
1212
const chosenLanguageScaffolder = vi.fn();
13-
const scaffolders = {...any.simpleObject(), [chosenLanguage]: chosenLanguageScaffolder};
13+
const plugins = {...any.simpleObject(), [chosenLanguage]: {scaffold: chosenLanguageScaffolder}};
1414
when(chosenLanguageScaffolder).calledWith(options).mockResolvedValue(scaffolderResult);
1515

16-
expect(await scaffold(scaffolders, chosenLanguage, options)).toEqual(scaffolderResult);
16+
expect(await scaffold(plugins, chosenLanguage, options)).toEqual(scaffolderResult);
1717
});
1818

1919
it('should not result in an error when choosing a language without a defined scaffolder', async () => {

src/language/schema.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
import joi from 'joi';
2+
import {optionsSchemas} from '@form8ion/core';
23

3-
export default joi.object().pattern(/^/, joi.func().arity(1));
4+
export default joi.object().pattern(/^/, optionsSchemas.form8ionPlugin).default({});

src/language/schema.test.js

+23-6
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,35 @@ describe('language plugins schema', () => {
99
const key = any.word();
1010

1111
it('should return the validated options', () => {
12-
const options = any.objectWithKeys(any.listOf(any.string), {factory: () => foo => foo});
12+
const options = any.objectWithKeys(
13+
any.listOf(any.string),
14+
{factory: () => ({scaffold: foo => foo})}
15+
);
1316

1417
expect(validateOptions(languageSchema, options)).toEqual(options);
1518
});
1619

17-
it('should require a scaffold function to be included', () => {
18-
expect(() => validateOptions(languageSchema, {[key]: any.word()}))
19-
.toThrowError(`"${key}" must be of type function`);
20+
it('should require options to be provided as an object', () => {
21+
expect(() => validateOptions(languageSchema, {[key]: []}))
22+
.toThrowError(`"${key}" must be of type object`);
23+
});
24+
25+
it('should require a `scaffold` property to be included', () => {
26+
expect(() => validateOptions(languageSchema, {[key]: {}}))
27+
.toThrowError(`"${key}.scaffold" is required`);
28+
});
29+
30+
it('should require `scaffold` to be a function', () => {
31+
expect(() => validateOptions(languageSchema, {[key]: {scaffold: any.word()}}))
32+
.toThrowError(`"${key}.scaffold" must be of type function`);
2033
});
2134

2235
it('should require the scaffolder to accept a single argument', () => {
23-
expect(() => validateOptions(languageSchema, {[key]: () => undefined}))
24-
.toThrowError(`"${key}" must have an arity of 1`);
36+
expect(() => validateOptions(languageSchema, {[key]: {scaffold: () => undefined}}))
37+
.toThrowError(`"${key}.scaffold" must have an arity of 1`);
38+
});
39+
40+
it('should default to an empty map when no updaters are provided', () => {
41+
expect(validateOptions(languageSchema)).toEqual({});
2542
});
2643
});

src/options-validator.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@ import {decisionsSchema} from './options-schemas.js';
88

99
export function validate(options) {
1010
return validateOptions(joi.object({
11-
languages: languagePluginsSchema,
1211
vcsHosts: vcsHostPluginsSchema,
1312
decisions: decisionsSchema,
14-
plugins: joi.object({dependencyUpdaters: dependencyUpdaterPluginsSchema})
13+
plugins: joi.object({dependencyUpdaters: dependencyUpdaterPluginsSchema, languages: languagePluginsSchema})
1514
}), options) || {};
1615
}

src/options-validator.test.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@ describe('options validator', () => {
2828
const pluginsSchema = any.simpleObject();
2929
const fullSchema = any.simpleObject();
3030
const validatedOptions = any.simpleObject();
31-
when(joi.object).calledWith({dependencyUpdaters: dependencyUpdaterPluginsSchema}).mockReturnValue(pluginsSchema);
31+
when(joi.object)
32+
.calledWith({dependencyUpdaters: dependencyUpdaterPluginsSchema, languages: languagePluginsSchema})
33+
.mockReturnValue(pluginsSchema);
3234
when(joi.object).calledWith({
33-
languages: languagePluginsSchema,
3435
vcsHosts: vcsHostPluginsSchema,
3536
decisions: decisionsSchema,
3637
plugins: pluginsSchema

src/scaffolder.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import lift from './lift.js';
1919

2020
export async function scaffold(options) {
2121
const projectRoot = process.cwd();
22-
const {languages = {}, vcsHosts = {}, decisions, plugins: {dependencyUpdaters}} = validate(options);
22+
const {vcsHosts = {}, decisions, plugins: {dependencyUpdaters, languages = {}}} = validate(options);
2323

2424
const {
2525
[coreQuestionNames.PROJECT_NAME]: projectName,

src/scaffolder.test.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ describe('project scaffolder', () => {
4848
const license = any.string();
4949
const projectLanguage = any.word();
5050
const licenseBadge = any.url();
51-
const languageScaffolders = any.simpleObject();
51+
const languages = any.simpleObject();
5252
const vcsHosts = any.simpleObject();
5353
const documentation = any.simpleObject();
5454
const vcs = any.simpleObject();
@@ -94,7 +94,7 @@ describe('project scaffolder', () => {
9494
const contributingResults = any.simpleObject();
9595
when(optionsValidator.validate)
9696
.calledWith(options)
97-
.mockReturnValue({languages: languageScaffolders, vcsHosts, decisions, plugins: {dependencyUpdaters}});
97+
.mockReturnValue({vcsHosts, decisions, plugins: {dependencyUpdaters, languages}});
9898
when(prompts.promptForBaseDetails)
9999
.calledWith(projectPath, decisions)
100100
.mockResolvedValue({
@@ -107,7 +107,7 @@ describe('project scaffolder', () => {
107107
[coreQuestionNames.VISIBILITY]: visibility
108108
});
109109
when(languagePrompt.default)
110-
.calledWith(languageScaffolders, decisions)
110+
.calledWith(languages, decisions)
111111
.mockResolvedValue({[questionNames.PROJECT_LANGUAGE]: projectLanguage});
112112
when(scaffoldGit)
113113
.calledWith(gitRepoShouldBeInitialized, projectPath, projectName, vcsHosts, visibility, decisions)
@@ -259,7 +259,7 @@ describe('project scaffolder', () => {
259259
};
260260
when(optionsValidator.validate)
261261
.calledWith(options)
262-
.mockReturnValue({languages: languageScaffolders, vcsHosts, decisions, plugins: {}});
262+
.mockReturnValue({vcsHosts, decisions, plugins: {languages}});
263263
scaffoldGit.mockResolvedValue(vcs);
264264
liftGit.mockResolvedValue({nextSteps: gitNextSteps});
265265
prompts.promptForBaseDetails.mockResolvedValue({
@@ -270,9 +270,9 @@ describe('project scaffolder', () => {
270270
[coreQuestionNames.DESCRIPTION]: description
271271
});
272272
when(languagePrompt.default)
273-
.calledWith(languageScaffolders, decisions)
273+
.calledWith(languages, decisions)
274274
.mockResolvedValue({[questionNames.PROJECT_LANGUAGE]: projectLanguage});
275-
when(languageScaffolder.default).calledWith(languageScaffolders, projectLanguage, {
275+
when(languageScaffolder.default).calledWith(languages, projectLanguage, {
276276
projectName,
277277
projectRoot: projectPath,
278278
visibility,
@@ -308,7 +308,7 @@ describe('project scaffolder', () => {
308308
it('should consider the language details to be optional', async () => {
309309
when(optionsValidator.validate)
310310
.calledWith(options)
311-
.mockReturnValue({languages: languageScaffolders, vcsHosts, decisions, plugins: {}});
311+
.mockReturnValue({vcsHosts, decisions, plugins: {languages}});
312312
scaffoldGit.mockResolvedValue(vcs);
313313
prompts.promptForBaseDetails.mockResolvedValue({
314314
[coreQuestionNames.PROJECT_NAME]: projectName,
@@ -318,7 +318,7 @@ describe('project scaffolder', () => {
318318
[coreQuestionNames.DESCRIPTION]: description
319319
});
320320
when(languagePrompt.default)
321-
.calledWith(languageScaffolders, decisions)
321+
.calledWith(languages, decisions)
322322
.mockResolvedValue({[questionNames.PROJECT_LANGUAGE]: projectLanguage});
323323
vcsHostScaffolder.default.mockResolvedValue(vcsOriginDetails);
324324
languageScaffolder.default.mockResolvedValue({});

test/integration/features/step_definitions/common-steps.js

+11-9
Original file line numberDiff line numberDiff line change
@@ -53,20 +53,22 @@ When(/^the project is scaffolded$/, async function () {
5353
this.projectDescription = any.sentence();
5454

5555
await scaffold({
56-
languages: {
57-
...'Other' !== chosenLanguage && {
58-
[chosenLanguage]: ({projectName}) => {
59-
info(`Scaffolding ${chosenLanguage} language details for ${projectName}`);
60-
61-
return this.languageScaffolderResults;
62-
}
63-
}
64-
},
6556
plugins: {
6657
...this.updaterScaffolderDetails && {
6758
dependencyUpdaters: {
6859
[chosenUpdater]: {...this.updaterScaffolderDetails, scaffold: this.updaterScaffolderDetails.scaffolder}
6960
}
61+
},
62+
languages: {
63+
...'Other' !== chosenLanguage && {
64+
[chosenLanguage]: {
65+
scaffold: ({projectName}) => {
66+
info(`Scaffolding ${chosenLanguage} language details for ${projectName}`);
67+
68+
return this.languageScaffolderResults;
69+
}
70+
}
71+
}
7072
}
7173
},
7274
...vcsHost && {

0 commit comments

Comments
 (0)