Skip to content

Commit 4abf811

Browse files
committed
feat(plugins): moved the dependency-updaters under the plugins property
and enabled passing as a full plugin that matches the form8ion conventional shape BREAKING CHANGE: a plugins map is now a required option and dependency-updaters are now expected to be provided there as a full plugin rather than just an object with a `scaffolder` plugin
1 parent 9c77ca5 commit 4abf811

File tree

10 files changed

+36
-40
lines changed

10 files changed

+36
-40
lines changed

.remarkrc.cjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
exports.settings = {
2-
listItemIndent: 1,
2+
listItemIndent: 'one',
33
emphasis: '_',
44
strong: '_',
55
bullet: '*',

README.md

+5
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ import {lift, questionNames, scaffold} from '@form8ion/project';
9090
},
9191
languages: {
9292
foo: options => options
93+
},
94+
plugins: {
95+
dependencyUpdaters: {
96+
bar: {scaffold: options => options}
97+
}
9398
}
9499
});
95100

example.js

+5
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ import {lift, questionNames, scaffold} from './lib/index.js';
2424
},
2525
languages: {
2626
foo: options => options
27+
},
28+
plugins: {
29+
dependencyUpdaters: {
30+
bar: {scaffold: options => options}
31+
}
2732
}
2833
});
2934

src/dependency-updater/schema.js

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

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

src/dependency-updater/schema.test.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ describe('dependency-updater plugins schema', () => {
1111
it('should return the validated options', () => {
1212
const options = any.objectWithKeys(
1313
any.listOf(any.string),
14-
{factory: () => ({scaffolder: foo => foo})}
14+
{factory: () => ({scaffold: foo => foo})}
1515
);
1616

1717
expect(validateOptions(dependencyUpdaterPluginsSchema, options)).toEqual(options);
@@ -22,19 +22,19 @@ describe('dependency-updater plugins schema', () => {
2222
.toThrowError(`"${key}" must be of type object`);
2323
});
2424

25-
it('should require a `scaffolder` to be included', () => {
25+
it('should require a `scaffold` property to be included', () => {
2626
expect(() => validateOptions(dependencyUpdaterPluginsSchema, {[key]: {}}))
27-
.toThrowError(`"${key}.scaffolder" is required`);
27+
.toThrowError(`"${key}.scaffold" is required`);
2828
});
2929

30-
it('should require `scaffolder` to be a function', () => {
31-
expect(() => validateOptions(dependencyUpdaterPluginsSchema, {[key]: {scaffolder: any.word()}}))
32-
.toThrowError(`"${key}.scaffolder" must be of type function`);
30+
it('should require `scaffold` to be a function', () => {
31+
expect(() => validateOptions(dependencyUpdaterPluginsSchema, {[key]: {scaffold: any.word()}}))
32+
.toThrowError(`"${key}.scaffold" must be of type function`);
3333
});
3434

3535
it('should require the scaffolder to accept a single argument', () => {
36-
expect(() => validateOptions(dependencyUpdaterPluginsSchema, {[key]: {scaffolder: () => undefined}}))
37-
.toThrowError(`"${key}.scaffolder" must have an arity of 1`);
36+
expect(() => validateOptions(dependencyUpdaterPluginsSchema, {[key]: {scaffold: () => undefined}}))
37+
.toThrowError(`"${key}.scaffold" must have an arity of 1`);
3838
});
3939

4040
it('should default to an empty map when no updaters are provided', () => {

src/options-validator.js

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
1-
import {validateOptions, optionsSchemas} from '@form8ion/core';
1+
import {validateOptions} from '@form8ion/core';
22
import joi from 'joi';
33

44
import languagePluginsSchema from './language/schema.js';
55
import vcsHostPluginsSchema from './vcs/host/schema.js';
66
import dependencyUpdaterPluginsSchema from './dependency-updater/schema.js';
77
import {decisionsSchema} from './options-schemas.js';
88

9-
const {form8ionPlugin} = optionsSchemas;
10-
119
export function validate(options) {
1210
return validateOptions(joi.object({
1311
languages: languagePluginsSchema,
1412
vcsHosts: vcsHostPluginsSchema,
1513
decisions: decisionsSchema,
16-
dependencyUpdaters: dependencyUpdaterPluginsSchema,
17-
plugins: joi.object({dependencyUpdaters: joi.object().pattern(joi.string(), form8ionPlugin)})
14+
plugins: joi.object({dependencyUpdaters: dependencyUpdaterPluginsSchema})
1815
}), options) || {};
1916
}

src/options-validator.test.js

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

4-
import {describe, expect, it, beforeEach, afterEach, vi} from 'vitest';
4+
import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest';
55
import any from '@travi/any';
66
import {when} from 'jest-when';
77

@@ -14,8 +14,6 @@ import {validate} from './options-validator.js';
1414
vi.mock('@form8ion/core');
1515

1616
describe('options validator', () => {
17-
const {form8ionPlugin} = optionsSchemas;
18-
1917
beforeEach(() => {
2018
vi.spyOn(joi, 'object');
2119
vi.spyOn(joi, 'string');
@@ -28,20 +26,13 @@ describe('options validator', () => {
2826
it('should build the full schema and call the base validator', () => {
2927
const options = any.simpleObject();
3028
const pluginsSchema = any.simpleObject();
31-
const pluginMapSchema = any.simpleObject();
3229
const fullSchema = any.simpleObject();
3330
const validatedOptions = any.simpleObject();
34-
const joiPattern = vi.fn();
35-
const stringSchema = any.simpleObject();
36-
joi.string.mockReturnValue(stringSchema);
37-
when(joiPattern).calledWith(stringSchema, form8ionPlugin).mockReturnValue(pluginMapSchema);
38-
when(joi.object).calledWith().mockReturnValue({pattern: joiPattern});
39-
when(joi.object).calledWith({dependencyUpdaters: pluginMapSchema}).mockReturnValue(pluginsSchema);
31+
when(joi.object).calledWith({dependencyUpdaters: dependencyUpdaterPluginsSchema}).mockReturnValue(pluginsSchema);
4032
when(joi.object).calledWith({
4133
languages: languagePluginsSchema,
4234
vcsHosts: vcsHostPluginsSchema,
4335
decisions: decisionsSchema,
44-
dependencyUpdaters: dependencyUpdaterPluginsSchema,
4536
plugins: pluginsSchema
4637
}).mockReturnValue(fullSchema);
4738
when(validateOptions).calledWith(fullSchema, options).mockReturnValue(validatedOptions);

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, dependencyUpdaters} = validate(options);
22+
const {languages = {}, vcsHosts = {}, decisions, plugins: {dependencyUpdaters}} = validate(options);
2323

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

src/scaffolder.test.js

+9-9
Original file line numberDiff line numberDiff line change
@@ -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, dependencyUpdaters});
97+
.mockReturnValue({languages: languageScaffolders, vcsHosts, decisions, plugins: {dependencyUpdaters}});
9898
when(prompts.promptForBaseDetails)
9999
.calledWith(projectPath, decisions)
100100
.mockResolvedValue({
@@ -160,7 +160,7 @@ describe('project scaffolder', () => {
160160

161161
it('should consider all options to be optional', async () => {
162162
const gitRepoShouldBeInitialized = any.boolean();
163-
optionsValidator.validate.mockReturnValue({});
163+
optionsValidator.validate.mockReturnValue({plugins: {}});
164164
when(prompts.promptForBaseDetails)
165165
.calledWith(projectPath, undefined)
166166
.mockResolvedValue({
@@ -175,9 +175,9 @@ describe('project scaffolder', () => {
175175
.toHaveBeenCalledWith(gitRepoShouldBeInitialized, projectPath, projectName, {}, undefined, undefined);
176176
});
177177

178-
it('should consider each option optional', async () => {
178+
it('should consider each option except the plugins map optional', async () => {
179179
const emptyOptions = {};
180-
when(optionsValidator.validate).calledWith(emptyOptions).mockReturnValue({});
180+
when(optionsValidator.validate).calledWith(emptyOptions).mockReturnValue({plugins: {}});
181181
when(prompts.promptForBaseDetails).calledWith(projectPath, undefined, undefined).mockResolvedValue({});
182182
languagePrompt.default.mockResolvedValue({});
183183
scaffoldGit.mockResolvedValue({});
@@ -223,7 +223,7 @@ describe('project scaffolder', () => {
223223
});
224224

225225
it('should not scaffold the git repo if not requested', async () => {
226-
when(optionsValidator.validate).calledWith(options).mockReturnValue({});
226+
when(optionsValidator.validate).calledWith(options).mockReturnValue({plugins: {}});
227227
prompts.promptForBaseDetails.mockResolvedValue({[questionNames.GIT_REPO]: false});
228228
languagePrompt.default.mockResolvedValue({});
229229
scaffoldReadme.mockResolvedValue();
@@ -259,7 +259,7 @@ describe('project scaffolder', () => {
259259
};
260260
when(optionsValidator.validate)
261261
.calledWith(options)
262-
.mockReturnValue({languages: languageScaffolders, vcsHosts, decisions});
262+
.mockReturnValue({languages: languageScaffolders, vcsHosts, decisions, plugins: {}});
263263
scaffoldGit.mockResolvedValue(vcs);
264264
liftGit.mockResolvedValue({nextSteps: gitNextSteps});
265265
prompts.promptForBaseDetails.mockResolvedValue({
@@ -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});
311+
.mockReturnValue({languages: languageScaffolders, vcsHosts, decisions, plugins: {}});
312312
scaffoldGit.mockResolvedValue(vcs);
313313
prompts.promptForBaseDetails.mockResolvedValue({
314314
[coreQuestionNames.PROJECT_NAME]: projectName,
@@ -334,7 +334,7 @@ describe('project scaffolder', () => {
334334
});
335335

336336
it('should pass the license to the language scaffolder as `UNLICENSED` when no license was chosen', async () => {
337-
when(optionsValidator.validate).calledWith(options).mockReturnValue({});
337+
when(optionsValidator.validate).calledWith(options).mockReturnValue({plugins: {}});
338338
prompts.promptForBaseDetails.mockResolvedValue({});
339339
languagePrompt.default.mockResolvedValue({[questionNames.PROJECT_LANGUAGE]: projectLanguage});
340340
scaffoldGit.mockResolvedValue({});
@@ -356,7 +356,7 @@ describe('project scaffolder', () => {
356356
});
357357

358358
it('should not run a verification command when one is not provided', async () => {
359-
when(optionsValidator.validate).calledWith(options).mockReturnValue({});
359+
when(optionsValidator.validate).calledWith(options).mockReturnValue({plugins: {}});
360360
prompts.promptForBaseDetails.mockResolvedValue({});
361361
languagePrompt.default.mockResolvedValue({});
362362
scaffoldGit.mockResolvedValue({});

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

-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ When(/^the project is scaffolded$/, async function () {
6969
}
7070
}
7171
},
72-
...this.updaterScaffolderDetails && {dependencyUpdaters: {[chosenUpdater]: this.updaterScaffolderDetails}},
7372
...vcsHost && {
7473
vcsHosts: {
7574
[vcsHost]: {

0 commit comments

Comments
 (0)