Skip to content

Commit 5bf0012

Browse files
authored
Merge pull request #1014 from form8ion/alpha
2 parents 8f9855c + 364b44d commit 5bf0012

40 files changed

+255
-265
lines changed

README.md

+63-66
Original file line numberDiff line numberDiff line change
@@ -46,88 +46,85 @@ $ npm install @form8ion/javascript --save
4646
#### Import
4747

4848
```javascript
49-
const {dialects, projectTypes} = require('@form8ion/javascript-core');
49+
const {dialects, projectTypes} = await import('@form8ion/javascript-core');
5050
const {
5151
scaffold: scaffoldJavaScript,
5252
lift: liftJavascript,
5353
test: thisIsAJavaScriptProject,
5454
scaffoldUnitTesting,
5555
questionNames
56-
} = require('@form8ion/javascript');
56+
} = await import('./lib/index.js');
5757
```
5858

5959
#### Execute
6060

6161
```javascript
62-
(async () => {
63-
const accountName = 'form8ion';
64-
const projectRoot = process.cwd();
62+
const accountName = 'form8ion';
63+
const projectRoot = process.cwd();
64+
65+
await scaffoldJavaScript({
66+
projectRoot,
67+
projectName: 'project-name',
68+
visibility: 'Public',
69+
license: 'MIT',
70+
configs: {
71+
eslint: {scope: `@${accountName}`},
72+
remark: `@${accountName}/remark-lint-preset`,
73+
babelPreset: {name: `@${accountName}`, packageName: `@${accountName}/babel-preset`},
74+
commitlint: {name: `@${accountName}`, packageName: `@${accountName}/commitlint-config`}
75+
},
76+
plugins: {
77+
unitTestFrameworks: {},
78+
applicationTypes: {},
79+
packageTypes: {},
80+
packageBundlers: {},
81+
ciServices: {}
82+
},
83+
decisions: {
84+
[questionNames.DIALECT]: dialects.BABEL,
85+
[questionNames.NODE_VERSION_CATEGORY]: 'LTS',
86+
[questionNames.PACKAGE_MANAGER]: 'npm',
87+
[questionNames.PROJECT_TYPE]: projectTypes.PACKAGE,
88+
[questionNames.SHOULD_BE_SCOPED]: true,
89+
[questionNames.SCOPE]: accountName,
90+
[questionNames.AUTHOR_NAME]: 'Your Name',
91+
[questionNames.AUTHOR_EMAIL]: '[email protected]',
92+
[questionNames.AUTHOR_URL]: 'https://your.website.tld',
93+
[questionNames.UNIT_TESTS]: true,
94+
[questionNames.INTEGRATION_TESTS]: true,
95+
[questionNames.PROVIDE_EXAMPLE]: true
96+
}
97+
});
6598

66-
await scaffoldJavaScript({
99+
if (await thisIsAJavaScriptProject({projectRoot})) {
100+
await liftJavascript({
67101
projectRoot,
68-
projectName: 'project-name',
69-
visibility: 'Public',
70-
license: 'MIT',
71-
configs: {
72-
eslint: {scope: `@${accountName}`},
73-
remark: `@${accountName}/remark-lint-preset`,
74-
babelPreset: {name: `@${accountName}`, packageName: `@${accountName}/babel-preset`},
75-
commitlint: {name: `@${accountName}`, packageName: `@${accountName}/commitlint-config`}
76-
},
77-
plugins: {
78-
unitTestFrameworks: {},
79-
applicationTypes: {},
80-
packageTypes: {},
81-
packageBundlers: {},
82-
ciServices: {}
102+
configs: {eslint: {scope: '@foo'}},
103+
results: {
104+
dependencies: {javascript: {production: [], development: []}},
105+
scripts: {},
106+
eslint: {configs: [], ignore: {directories: []}},
107+
packageManager: 'npm'
83108
},
84-
decisions: {
85-
[questionNames.DIALECT]: dialects.BABEL,
86-
[questionNames.NODE_VERSION_CATEGORY]: 'LTS',
87-
[questionNames.PACKAGE_MANAGER]: 'npm',
88-
[questionNames.PROJECT_TYPE]: projectTypes.PACKAGE,
89-
[questionNames.SHOULD_BE_SCOPED]: true,
90-
[questionNames.SCOPE]: accountName,
91-
[questionNames.AUTHOR_NAME]: 'Your Name',
92-
[questionNames.AUTHOR_EMAIL]: '[email protected]',
93-
[questionNames.AUTHOR_URL]: 'https://your.website.tld',
94-
[questionNames.UNIT_TESTS]: true,
95-
[questionNames.INTEGRATION_TESTS]: true,
96-
[questionNames.PROVIDE_EXAMPLE]: true
97-
}
98-
});
99-
100-
if (await thisIsAJavaScriptProject({projectRoot})) {
101-
await liftJavascript({
102-
projectRoot,
103-
configs: {eslint: {scope: '@foo'}},
104-
results: {
105-
dependencies: [],
106-
devDependencies: [],
107-
scripts: {},
108-
eslint: {configs: [], ignore: {directories: []}},
109-
packageManager: 'npm'
110-
},
111-
enhancers: {
112-
PluginName: {
113-
test: () => true,
114-
lift: () => ({})
115-
}
109+
enhancers: {
110+
PluginName: {
111+
test: () => true,
112+
lift: () => ({})
116113
}
117-
});
118-
}
119-
120-
await scaffoldUnitTesting({
121-
projectRoot: process.cwd(),
122-
frameworks: {
123-
Mocha: {scaffold: options => options},
124-
Jest: {scaffold: options => options}
125-
},
126-
visibility: 'Public',
127-
vcs: {host: 'GitHub', owner: 'foo', name: 'bar'},
128-
decisions: {[questionNames.UNIT_TEST_FRAMEWORK]: 'Mocha'}
114+
}
129115
});
130-
})();
116+
}
117+
118+
await scaffoldUnitTesting({
119+
projectRoot: process.cwd(),
120+
frameworks: {
121+
Mocha: {scaffold: options => options},
122+
Jest: {scaffold: options => options}
123+
},
124+
visibility: 'Public',
125+
vcs: {host: 'GitHub', owner: 'foo', name: 'bar'},
126+
decisions: {[questionNames.UNIT_TEST_FRAMEWORK]: 'Mocha'}
127+
});
131128
```
132129

133130
### Documentation

docs/api/scaffold.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Language scaffolder for JavaScript projects
88
* [`projectRoot` __string__ (_required_)](#projectroot-string-required)
99
* [`projectName` __string__ (_required_)](#projectname-string-required)
1010
* [`description` __string__ (_optional_)](#description-string-optional)
11-
* [`pathWithinParent` __string__ (_required_)](#pathwithinparent-string-required)
11+
* [`pathWithinParent` __string__ (_optional_)](#pathwithinparent-string-optional)
1212
* [`license` __string__ (_required_)](#license-string-required)
1313
* [`decisions` __object__ (_optional_)](#decisions-object-optional)
1414
* [`visibility` __string__ (_required_)](#visibility-string-required)

example.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,18 @@ import stubbedFs from 'mock-fs';
55
import * as td from 'testdouble';
66
import 'validate-npm-package-name';
77

8-
// remark-usage-ignore-next 10
8+
// remark-usage-ignore-next 11
99
stubbedFs({
1010
node_modules: stubbedFs.load(resolve('node_modules')),
1111
'.nvmrc': 'v1.2.3',
1212
lib: stubbedFs.load(resolve('lib')),
1313
templates: stubbedFs.load(resolve('templates'))
1414
});
15-
const execa = td.replace('execa');
15+
const {execa} = await td.replaceEsm('execa');
1616
td.when(execa('. ~/.nvm/nvm.sh && nvm ls-remote --lts', {shell: true}))
1717
.thenResolve({stdout: ['v16.5.4', ''].join('\n')});
1818
td.when(execa('. ~/.nvm/nvm.sh && nvm install', {shell: true})).thenReturn({stdout: {pipe: () => undefined}});
19+
td.when(execa('npm', ['--version'])).thenResolve({stdout: '10.6.18'});
1920

2021
const {dialects, projectTypes} = await import('@form8ion/javascript-core');
2122
const {
@@ -69,8 +70,7 @@ if (await thisIsAJavaScriptProject({projectRoot})) {
6970
projectRoot,
7071
configs: {eslint: {scope: '@foo'}},
7172
results: {
72-
dependencies: [],
73-
devDependencies: [],
73+
dependencies: {javascript: {production: [], development: []}},
7474
scripts: {},
7575
eslint: {configs: [], ignore: {directories: []}},
7676
packageManager: 'npm'

package-lock.json

+12-12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,11 @@
6060
"packageManager": "[email protected]+sha512.11dff29565d2297c74e7c594a9762581bde969f0aa5cbe6f5b3644bf008a16c065ece61094d9ffbb81125be38df8e1ba43eb8244b3d30c61eb797e9a2440e3ec",
6161
"dependencies": {
6262
"@form8ion/codecov": "^6.0.0",
63-
"@form8ion/commit-convention": "^7.0.0",
63+
"@form8ion/commit-convention": "^8.0.0-beta.1",
6464
"@form8ion/config-file": "^1.1.1",
6565
"@form8ion/core": "^4.0.0",
66-
"@form8ion/eslint": "^6.1.0",
67-
"@form8ion/husky": "^6.0.0-beta.2",
66+
"@form8ion/eslint": "^7.0.0-beta.1",
67+
"@form8ion/husky": "^7.0.0-beta.1",
6868
"@form8ion/javascript-core": "^12.0.0-beta.1",
6969
"@form8ion/overridable-prompts": "^1.2.0",
7070
"@form8ion/prettier": "^2.0.0",

src/code-style/remark/scaffolder.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@ export default async function ({config, projectRoot, projectType, vcs}) {
2727

2828
return deepmerge(
2929
{
30-
devDependencies: [config, 'remark-cli', 'remark-toc'],
30+
dependencies: {javascript: {development: [config, 'remark-cli', 'remark-toc']}},
3131
scripts: {
3232
'lint:md': 'remark . --frail',
3333
'generate:md': 'remark . --output'
3434
}
3535
},
36-
{...projectTypes.PACKAGE === projectType && {devDependencies: ['remark-usage']}}
36+
{...projectTypes.PACKAGE === projectType && {dependencies: {javascript: {development: ['remark-usage']}}}}
3737
);
3838
}

src/code-style/remark/scaffolder.test.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ describe('remark scaffolder', () => {
2020
it('should write the config and define dependencies', async () => {
2121
expect(await scaffoldRemark({config, projectRoot, vcs: any.simpleObject()}))
2222
.toEqual({
23-
devDependencies: [config, 'remark-cli', 'remark-toc'],
23+
dependencies: {javascript: {development: [config, 'remark-cli', 'remark-toc']}},
2424
scripts: {
2525
'lint:md': 'remark . --frail',
2626
'generate:md': 'remark . --output'
@@ -49,7 +49,7 @@ describe('remark scaffolder', () => {
4949
it('should configure the remark-usage plugin for package projects', async () => {
5050
expect(await scaffoldRemark({config, projectRoot, projectType: projectTypes.PACKAGE, vcs: any.simpleObject()}))
5151
.toEqual({
52-
devDependencies: [config, 'remark-cli', 'remark-toc', 'remark-usage'],
52+
dependencies: {javascript: {development: [config, 'remark-cli', 'remark-toc', 'remark-usage']}},
5353
scripts: {
5454
'lint:md': 'remark . --frail',
5555
'generate:md': 'remark . --output'

src/coverage/c8/scaffolder.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export default async function ({projectRoot}) {
1313
});
1414

1515
return {
16-
devDependencies: ['cross-env', 'c8'],
16+
dependencies: {javascript: {development: ['cross-env', 'c8']}},
1717
vcsIgnore: {files: [], directories: ['/coverage/']},
1818
eslint: {ignore: {directories: ['/coverage/']}}
1919
};

src/coverage/c8/scaffolder.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ describe('c8 scaffolder', () => {
2020

2121
expect(await scaffoldC8({projectRoot, vcs: {owner: vcsOwner, name: vcsName, host: 'github'}, visibility: 'Public'}))
2222
.toEqual({
23-
devDependencies: ['cross-env', 'c8'],
23+
dependencies: {javascript: {development: ['cross-env', 'c8']}},
2424
vcsIgnore: {files: [], directories: ['/coverage/']},
2525
eslint: {ignore: {directories: ['/coverage/']}}
2626
});

src/dependencies/processor.js

+15-3
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,24 @@ import {DEV_DEPENDENCY_TYPE, PROD_DEPENDENCY_TYPE} from '@form8ion/javascript-co
33

44
import install from './installer.js';
55

6-
export default async function ({dependencies, devDependencies, projectRoot, packageManager}) {
6+
export default async function ({dependencies = {}, devDependencies, projectRoot, packageManager}) {
77
info('Processing dependencies');
88

9+
if (Array.isArray(devDependencies)) {
10+
throw new Error(
11+
`devDependencies provided as: ${devDependencies}. Instead, provide under dependencies.javascript.development`
12+
);
13+
}
14+
15+
if (Array.isArray(dependencies)) {
16+
throw new Error(`Expected dependencies to be an object. Instead received: ${dependencies}`);
17+
}
18+
19+
const {javascript: {production = [], development = []} = {}} = dependencies;
20+
921
try {
10-
await install(dependencies || [], PROD_DEPENDENCY_TYPE, projectRoot, packageManager);
11-
await install(devDependencies || [], DEV_DEPENDENCY_TYPE, projectRoot, packageManager);
22+
await install(production, PROD_DEPENDENCY_TYPE, projectRoot, packageManager);
23+
await install(development, DEV_DEPENDENCY_TYPE, projectRoot, packageManager);
1224
} catch (e) {
1325
error('Failed to update dependencies');
1426
error(e, {level: 'secondary'});

src/dependencies/processor.test.js

+35-6
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ describe('dependencies processor', () => {
1313
const packageManager = any.word();
1414

1515
it('should process the provided dependency lists', async () => {
16-
const dependencies = any.listOf(any.word);
17-
const devDependencies = any.listOf(any.word);
16+
const production = any.listOf(any.word);
17+
const development = any.listOf(any.word);
1818

19-
await processDependencies({dependencies, devDependencies, projectRoot, packageManager});
19+
await processDependencies({dependencies: {javascript: {production, development}}, projectRoot, packageManager});
2020

21-
expect(installDependencies).toHaveBeenCalledWith(dependencies, PROD_DEPENDENCY_TYPE, projectRoot, packageManager);
22-
expect(installDependencies).toHaveBeenCalledWith(devDependencies, DEV_DEPENDENCY_TYPE, projectRoot, packageManager);
21+
expect(installDependencies).toHaveBeenCalledWith(production, PROD_DEPENDENCY_TYPE, projectRoot, packageManager);
22+
expect(installDependencies).toHaveBeenCalledWith(development, DEV_DEPENDENCY_TYPE, projectRoot, packageManager);
2323
});
2424

2525
it('should process as empty lists when dependencies are not provided', async () => {
@@ -29,9 +29,38 @@ describe('dependencies processor', () => {
2929
expect(installDependencies).toHaveBeenCalledWith([], DEV_DEPENDENCY_TYPE, projectRoot, packageManager);
3030
});
3131

32+
it('should process as empty lists when javascript dependencies are not provided', async () => {
33+
await processDependencies({projectRoot, packageManager, dependencies: {}});
34+
35+
expect(installDependencies).toHaveBeenCalledWith([], PROD_DEPENDENCY_TYPE, projectRoot, packageManager);
36+
expect(installDependencies).toHaveBeenCalledWith([], DEV_DEPENDENCY_TYPE, projectRoot, packageManager);
37+
});
38+
39+
it('should process as empty lists when dependency types are not provided', async () => {
40+
await processDependencies({projectRoot, packageManager, dependencies: {javascript: {}}});
41+
42+
expect(installDependencies).toHaveBeenCalledWith([], PROD_DEPENDENCY_TYPE, projectRoot, packageManager);
43+
expect(installDependencies).toHaveBeenCalledWith([], DEV_DEPENDENCY_TYPE, projectRoot, packageManager);
44+
});
45+
3246
it('should prevent an installation error from bubbling', async () => {
3347
installDependencies.mockRejectedValue(new Error());
3448

35-
await expect(() => processDependencies({})).not.toThrowError();
49+
await expect(() => processDependencies({dependencies: {javascript: {}}})).not.toThrowError();
50+
});
51+
52+
it('should throw an error if dependencies is defined as an array rather than an object', async () => {
53+
const dependencies = any.listOf(any.word);
54+
55+
await expect(() => processDependencies({dependencies}))
56+
.rejects.toThrowError(`Expected dependencies to be an object. Instead received: ${dependencies}`);
57+
});
58+
59+
it('should throw an error if devDependencies is defined as an array', async () => {
60+
const devDependencies = any.listOf(any.word);
61+
62+
await expect(() => processDependencies({devDependencies})).rejects.toThrowError(
63+
`devDependencies provided as: ${devDependencies}. Instead, provide under dependencies.javascript.development`
64+
);
3665
});
3766
});

0 commit comments

Comments
 (0)