Skip to content
This repository was archived by the owner on Dec 16, 2022. It is now read-only.

Commit e48f9c6

Browse files
feat(template): add widget template (#455)
* feat(template): add widget template this changes the questions asked into two categories, and asks one extra question for the integration type. Alternatively for the questions, the template question could come first, and then the category could be implied * make tests pass * update tests * avoid undefined if from prompted * Apply suggestions from code review Co-authored-by: François Chalifour <[email protected]> * readme feedback * update test * update inquirer * use library version * fix typos * chore: remove limitation * add versioning * update tests * use && in build script * fix nits Co-authored-by: François Chalifour <[email protected]>
1 parent 7bb892e commit e48f9c6

File tree

20 files changed

+1523
-176
lines changed

20 files changed

+1523
-176
lines changed

e2e/__snapshots__/templates.test.js.snap

Lines changed: 617 additions & 0 deletions
Large diffs are not rendered by default.

e2e/templates.test.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ describe('Templates', () => {
3737
name: templateConfig.appName,
3838
template: templateName,
3939
// We fetch the earliest supported version in order to not change
40-
// the test output everytime we release a new version of a library.
40+
// the test output every time we release a new version of a library.
4141
libraryVersion: await getEarliestLibraryVersion({
4242
libraryName: templateConfig.libraryName,
4343
supportedVersion: templateConfig.supportedVersion,
@@ -48,6 +48,7 @@ describe('Templates', () => {
4848
searchPlaceholder: 'Search placeholder',
4949
attributesToDisplay: ['attribute1', 'attribute2'],
5050
attributesForFaceting: ['facet1', 'facet2'],
51+
organization: 'algolia',
5152
};
5253

5354
configFilePath = `${temporaryDirectory}/${templateConfig.appName}.config.json`;

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
"algoliasearch": "3.35.1",
4040
"chalk": "3.0.0",
4141
"commander": "4.0.1",
42-
"inquirer": "7.0.1",
42+
"inquirer": "8.0.0",
4343
"jstransformer-handlebars": "1.1.0",
4444
"latest-semver": "2.0.0",
4545
"load-json-file": "6.2.0",

src/api/__tests__/__snapshots__/index.test.js.snap

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ exports[`Options with invalid name throws 1`] = `
66
- name can only contain URL-friendly characters"
77
`;
88

9-
exports[`Options with unknown template throws 1`] = `"The template directory must contain a configuration file \`.template.js\` or must be one of those: Angular InstantSearch, Autocomplete.js, InstantSearch Android, InstantSearch iOS, InstantSearch.js, InstantSearch.js 2, JavaScript Client, JavaScript Helper, JavaScript Helper 2, React InstantSearch, React InstantSearch Native, Vue InstantSearch, Vue InstantSearch 1, Vue InstantSearch 2"`;
9+
exports[`Options with unknown template throws 1`] = `"The template directory must contain a configuration file \`.template.js\` or must be one of those: Angular InstantSearch, Autocomplete.js, InstantSearch Android, InstantSearch iOS, InstantSearch.js, InstantSearch.js 2, InstantSearch.js widget, JavaScript Client, JavaScript Helper, JavaScript Helper 2, React InstantSearch, React InstantSearch Native, Vue InstantSearch, Vue InstantSearch 1, Vue InstantSearch 2"`;
1010

11-
exports[`Options with wrong template path throws 1`] = `"The template directory must contain a configuration file \`.template.js\` or must be one of those: Angular InstantSearch, Autocomplete.js, InstantSearch Android, InstantSearch iOS, InstantSearch.js, InstantSearch.js 2, JavaScript Client, JavaScript Helper, JavaScript Helper 2, React InstantSearch, React InstantSearch Native, Vue InstantSearch, Vue InstantSearch 1, Vue InstantSearch 2"`;
11+
exports[`Options with wrong template path throws 1`] = `"The template directory must contain a configuration file \`.template.js\` or must be one of those: Angular InstantSearch, Autocomplete.js, InstantSearch Android, InstantSearch iOS, InstantSearch.js, InstantSearch.js 2, InstantSearch.js widget, JavaScript Client, JavaScript Helper, JavaScript Helper 2, React InstantSearch, React InstantSearch Native, Vue InstantSearch, Vue InstantSearch 1, Vue InstantSearch 2"`;
1212

1313
exports[`Options without path throws 1`] = `"The option \`path\` is required."`;
1414

15-
exports[`Options without template throws 1`] = `"The template directory must contain a configuration file \`.template.js\` or must be one of those: Angular InstantSearch, Autocomplete.js, InstantSearch Android, InstantSearch iOS, InstantSearch.js, InstantSearch.js 2, JavaScript Client, JavaScript Helper, JavaScript Helper 2, React InstantSearch, React InstantSearch Native, Vue InstantSearch, Vue InstantSearch 1, Vue InstantSearch 2"`;
15+
exports[`Options without template throws 1`] = `"The template directory must contain a configuration file \`.template.js\` or must be one of those: Angular InstantSearch, Autocomplete.js, InstantSearch Android, InstantSearch iOS, InstantSearch.js, InstantSearch.js 2, InstantSearch.js widget, JavaScript Client, JavaScript Helper, JavaScript Helper 2, React InstantSearch, React InstantSearch Native, Vue InstantSearch, Vue InstantSearch 1, Vue InstantSearch 2"`;

src/cli/__tests__/getConfiguration.test.js

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
const path = require('path');
21
const loadJsonFile = require('load-json-file');
32
const utils = require('../../utils');
4-
const getConfiguration = require('../getConfiguration');
3+
const { getConfiguration, getLibraryVersion } = require('../getConfiguration');
54

65
jest.mock('load-json-file');
76

@@ -18,18 +17,6 @@ test('without template throws', async () => {
1817
);
1918
});
2019

21-
test('with template transforms to its relative path', async () => {
22-
const configuration = await getConfiguration({
23-
answers: { template: 'InstantSearch.js' },
24-
});
25-
26-
expect(configuration).toEqual(
27-
expect.objectContaining({
28-
template: path.resolve('src/templates/InstantSearch.js'),
29-
})
30-
);
31-
});
32-
3320
test('with options from arguments and prompt merge', async () => {
3421
const configuration = await getConfiguration({
3522
options: {
@@ -54,13 +41,14 @@ test('without stable version available', async () => {
5441
Promise.resolve(['1.0.0-beta.0'])
5542
);
5643

57-
const configuration = await getConfiguration({
58-
answers: {
44+
const libraryVersion = await getLibraryVersion(
45+
{
5946
template: 'InstantSearch.js',
6047
},
61-
});
48+
utils.getAppTemplateConfig(utils.getTemplatePath('InstantSearch.js'))
49+
);
6250

63-
expect(configuration.libraryVersion).toBe('1.0.0-beta.0');
51+
expect(libraryVersion).toBe('1.0.0-beta.0');
6452
});
6553

6654
test('with config file overrides all options', async () => {

src/cli/getConfiguration.js

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,38 @@
11
const latestSemver = require('latest-semver');
22
const loadJsonFile = require('load-json-file');
3+
const camelCase = require('lodash.camelcase');
34

4-
const {
5-
getAppTemplateConfig,
6-
fetchLibraryVersions,
7-
getTemplatePath,
8-
} = require('../utils');
5+
const { fetchLibraryVersions } = require('../utils');
96

10-
module.exports = async function getConfiguration({
11-
options = {},
12-
answers = {},
13-
} = {}) {
7+
function capitalize(str) {
8+
return str.substr(0, 1).toUpperCase() + str.substr(1);
9+
}
10+
11+
function createNameAlternatives({ organization, name }) {
12+
return {
13+
packageName: `@${organization}/${name}`,
14+
widgetType: `${organization}.${name}`,
15+
camelCaseName: camelCase(name),
16+
pascalCaseName: capitalize(camelCase(name)),
17+
};
18+
}
19+
20+
async function getLibraryVersion(config, templateConfig) {
21+
const { libraryName } = templateConfig;
22+
const { libraryVersion } = config;
23+
24+
if (libraryName && !libraryVersion) {
25+
const versions = await fetchLibraryVersions(libraryName);
26+
27+
// Return the latest available version when
28+
// the stable version is not available
29+
return latestSemver(versions) || versions[0];
30+
}
31+
32+
return libraryVersion;
33+
}
34+
35+
async function getConfiguration({ options = {}, answers = {} } = {}) {
1436
const config = options.config
1537
? await loadJsonFile(options.config) // From configuration file given as an argument
1638
: { ...options, ...answers }; // From the arguments and the prompt
@@ -19,24 +41,11 @@ module.exports = async function getConfiguration({
1941
throw new Error('The template is required in the config.');
2042
}
2143

22-
const templatePath = getTemplatePath(config.template);
23-
const templateConfig = getAppTemplateConfig(templatePath);
24-
let { libraryVersion } = config;
25-
26-
if (templateConfig.libraryName && !libraryVersion) {
27-
libraryVersion = await fetchLibraryVersions(
28-
templateConfig.libraryName
29-
).then(
30-
versions =>
31-
// Return the lastest available version when
32-
// the stable version is not available
33-
latestSemver(versions) || versions[0]
34-
);
35-
}
44+
return config;
45+
}
3646

37-
return {
38-
...config,
39-
libraryVersion,
40-
template: templatePath,
41-
};
47+
module.exports = {
48+
getConfiguration,
49+
getLibraryVersion,
50+
createNameAlternatives,
4251
};

0 commit comments

Comments
 (0)