create-instantsearch-app 4.10.2 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +94 -0
- package/README.md +1 -0
- package/package.json +4 -3
- package/src/api/__tests__/__snapshots__/index.test.js.snap +3 -3
- package/src/cli/__tests__/getAnswersDefaultValues.js +15 -0
- package/src/cli/__tests__/getAttributesFromIndex.test.js +18 -24
- package/src/cli/__tests__/getConfiguration.test.js +1 -22
- package/src/cli/__tests__/getFacetsFromIndex.test.js +39 -0
- package/src/cli/__tests__/getInformationFromIndex.js +68 -0
- package/src/cli/__tests__/isQuestionAsked.test.js +32 -10
- package/src/cli/__tests__/postProcessAnswers.js +111 -0
- package/src/cli/getAnswersDefaultValues.js +13 -0
- package/src/cli/getAttributesFromIndex.js +6 -4
- package/src/cli/getConfiguration.js +1 -38
- package/src/cli/getFacetsFromIndex.js +18 -0
- package/src/cli/getInformationFromIndex.js +40 -0
- package/src/cli/index.js +191 -113
- package/src/cli/isQuestionAsked.js +9 -16
- package/src/cli/postProcessAnswers.js +77 -0
- package/src/templates/Angular InstantSearch/angular.json +1 -0
- package/src/templates/Angular InstantSearch/package.json +25 -25
- package/src/templates/Angular InstantSearch/src/index.html +1 -0
- package/src/templates/Angular InstantSearch/src/styles.css +10 -2
- package/src/templates/Angular InstantSearch/tsconfig.json +1 -0
- package/src/templates/Autocomplete/.editorconfig +9 -0
- package/src/templates/Autocomplete/.eslintignore +3 -0
- package/src/templates/Autocomplete/.eslintrc.js +20 -0
- package/src/templates/Autocomplete/.gitignore.template +22 -0
- package/src/templates/Autocomplete/.prettierrc +5 -0
- package/src/templates/Autocomplete/.template.js +14 -0
- package/src/templates/Autocomplete/README.md +21 -0
- package/src/templates/Autocomplete/app.js.hbs +53 -0
- package/src/templates/Autocomplete/favicon.png +0 -0
- package/src/templates/Autocomplete/index.html.hbs +19 -0
- package/src/templates/Autocomplete/manifest.webmanifest +15 -0
- package/src/templates/Autocomplete/package.json +36 -0
- package/src/templates/Autocomplete/style.css +20 -0
- package/src/templates/{Autocomplete.js → Autocomplete.js 0}/.editorconfig +0 -0
- package/src/templates/{Autocomplete.js → Autocomplete.js 0}/.eslintignore +0 -0
- package/src/templates/{Autocomplete.js → Autocomplete.js 0}/.eslintrc.js +0 -0
- package/src/templates/{Autocomplete.js → Autocomplete.js 0}/.gitignore.template +0 -0
- package/src/templates/{Autocomplete.js → Autocomplete.js 0}/.prettierrc +0 -0
- package/src/templates/{Autocomplete.js/.template.js → Autocomplete.js 0/.template.js } +1 -1
- package/src/templates/{Autocomplete.js → Autocomplete.js 0}/README.md +0 -0
- package/src/templates/{Autocomplete.js → Autocomplete.js 0}/favicon.png +0 -0
- package/src/templates/{Autocomplete.js → Autocomplete.js 0}/index.html.hbs +0 -0
- package/src/templates/{Autocomplete.js → Autocomplete.js 0}/manifest.webmanifest +0 -0
- package/src/templates/{Autocomplete.js → Autocomplete.js 0}/package.json +0 -0
- package/src/templates/{Autocomplete.js → Autocomplete.js 0}/src/app.css +0 -0
- package/src/templates/{Autocomplete.js → Autocomplete.js 0}/src/app.js.hbs +0 -0
- package/src/templates/{Autocomplete.js → Autocomplete.js 0}/src/index.css +0 -0
- package/src/templates/InstantSearch.js/.template.js +3 -0
- package/src/templates/InstantSearch.js/index.html.hbs +4 -0
- package/src/templates/InstantSearch.js/src/app.js.hbs +25 -1
- package/src/templates/React InstantSearch/.template.js +4 -0
- package/src/templates/React InstantSearch/src/App.js.hbs +13 -0
- package/src/templates/Vue InstantSearch/.template.js +4 -1
- package/src/templates/Vue InstantSearch/src/App.vue +9 -0
- package/src/utils/__tests__/__snapshots__/index.test.js.snap +0 -4
- package/src/utils/__tests__/index.test.js +31 -3
- package/src/utils/index.js +14 -1
- package/src/cli/__tests__/getOptionsFromArguments.test.js +0 -72
- package/src/cli/getOptionsFromArguments.js +0 -21
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const algoliasearch = require('algoliasearch');
|
|
2
|
+
const { createInMemoryCache } = require('@algolia/cache-in-memory');
|
|
3
|
+
|
|
4
|
+
const clients = new Map();
|
|
5
|
+
function getClient(appId, apiKey) {
|
|
6
|
+
const key = [appId, apiKey].join('__');
|
|
7
|
+
let client = clients.get(key);
|
|
8
|
+
if (!client) {
|
|
9
|
+
client = algoliasearch(appId, apiKey, {
|
|
10
|
+
responsesCache: createInMemoryCache(),
|
|
11
|
+
requestsCache: createInMemoryCache(),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
clients.set(key, client);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return client;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function getInformationFromIndex({ appId, apiKey, indexName }) {
|
|
21
|
+
try {
|
|
22
|
+
const client = getClient(appId, apiKey);
|
|
23
|
+
return await client
|
|
24
|
+
.search([
|
|
25
|
+
{
|
|
26
|
+
indexName,
|
|
27
|
+
params: {
|
|
28
|
+
hitsPerPage: 1,
|
|
29
|
+
facets: '*',
|
|
30
|
+
maxValuesPerFacet: 1,
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
])
|
|
34
|
+
.then(({ results: [result] }) => result);
|
|
35
|
+
} catch (err) {
|
|
36
|
+
return {};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports = getInformationFromIndex;
|
package/src/cli/index.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const process = require('process');
|
|
4
|
+
const os = require('os');
|
|
4
5
|
const program = require('commander');
|
|
5
6
|
const inquirer = require('inquirer');
|
|
6
7
|
const chalk = require('chalk');
|
|
7
8
|
const latestSemver = require('latest-semver');
|
|
8
|
-
const
|
|
9
|
+
const semver = require('semver');
|
|
9
10
|
|
|
10
11
|
const createInstantSearchApp = require('../api');
|
|
11
12
|
const {
|
|
@@ -15,22 +16,22 @@ const {
|
|
|
15
16
|
fetchLibraryVersions,
|
|
16
17
|
getTemplatesByCategory,
|
|
17
18
|
getTemplatePath,
|
|
19
|
+
splitArray,
|
|
18
20
|
} = require('../utils');
|
|
19
|
-
const getOptionsFromArguments = require('./getOptionsFromArguments');
|
|
20
21
|
const getAttributesFromIndex = require('./getAttributesFromIndex');
|
|
22
|
+
const getFacetsFromIndex = require('./getFacetsFromIndex');
|
|
23
|
+
const getAnswersDefaultValues = require('./getAnswersDefaultValues');
|
|
21
24
|
const isQuestionAsked = require('./isQuestionAsked');
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
getLibraryVersion,
|
|
25
|
-
createNameAlternatives,
|
|
26
|
-
} = require('./getConfiguration');
|
|
25
|
+
const getConfiguration = require('./getConfiguration');
|
|
26
|
+
const postProcessAnswers = require('./postProcessAnswers');
|
|
27
27
|
const { version } = require('../../package.json');
|
|
28
28
|
|
|
29
29
|
let appPathFromArgument;
|
|
30
|
-
let options = {};
|
|
31
30
|
|
|
32
31
|
program
|
|
32
|
+
.storeOptionsAsProperties(false)
|
|
33
33
|
.version(version, '-v, --version')
|
|
34
|
+
.name('create-instantsearch-app')
|
|
34
35
|
.arguments('<project-directory>')
|
|
35
36
|
.usage(`${chalk.green('<project-directory>')} [options]`)
|
|
36
37
|
.option('--name <name>', 'The name of the application or widget')
|
|
@@ -39,27 +40,29 @@ program
|
|
|
39
40
|
.option('--index-name <indexName>', 'The main index of your search')
|
|
40
41
|
.option(
|
|
41
42
|
'--attributes-to-display <attributesToDisplay>',
|
|
42
|
-
'The attributes of your index to display'
|
|
43
|
+
'The attributes of your index to display in hits',
|
|
44
|
+
splitArray
|
|
43
45
|
)
|
|
44
46
|
.option(
|
|
45
47
|
'--attributes-for-faceting <attributesForFaceting>',
|
|
46
|
-
'The attributes
|
|
48
|
+
'The attributes to display as filters',
|
|
49
|
+
splitArray
|
|
47
50
|
)
|
|
48
51
|
.option('--template <template>', 'The InstantSearch template to use')
|
|
49
52
|
.option('--library-version <version>', 'The version of the library')
|
|
50
53
|
.option('--config <config>', 'The configuration file to get the options from')
|
|
51
54
|
.option('--no-installation', 'Ignore dependency installation')
|
|
52
|
-
.
|
|
55
|
+
.option('--no-interactive', 'Ask no interactive questions')
|
|
56
|
+
.action(dest => {
|
|
53
57
|
appPathFromArgument = dest;
|
|
54
|
-
options = opts;
|
|
55
58
|
})
|
|
56
59
|
.parse(process.argv);
|
|
57
60
|
|
|
58
|
-
const optionsFromArguments =
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
const optionsFromArguments = program.opts();
|
|
62
|
+
const {
|
|
63
|
+
attributesToDisplay = [],
|
|
64
|
+
attributesForFaceting = [],
|
|
65
|
+
} = optionsFromArguments;
|
|
63
66
|
|
|
64
67
|
const getQuestions = ({ appName }) => ({
|
|
65
68
|
application: [
|
|
@@ -153,7 +156,49 @@ const getQuestions = ({ appName }) => ({
|
|
|
153
156
|
],
|
|
154
157
|
filter: attributes => attributes.filter(Boolean),
|
|
155
158
|
when: ({ appId, apiKey, indexName }) =>
|
|
156
|
-
|
|
159
|
+
attributesToDisplay.length === 0 && appId && apiKey && indexName,
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
type: 'checkbox',
|
|
163
|
+
name: 'attributesForFaceting',
|
|
164
|
+
message: 'Attributes to display',
|
|
165
|
+
suffix: `\n ${chalk.gray('Used to filter the search interface')}`,
|
|
166
|
+
pageSize: 10,
|
|
167
|
+
choices: async answers => {
|
|
168
|
+
const templatePath = getTemplatePath(answers.template);
|
|
169
|
+
const templateConfig = getAppTemplateConfig(templatePath);
|
|
170
|
+
|
|
171
|
+
const selectedLibraryVersion = answers.libraryVersion;
|
|
172
|
+
const requiredLibraryVersion =
|
|
173
|
+
templateConfig.flags && templateConfig.flags.dynamicWidgets;
|
|
174
|
+
const supportsDynamicWidgets =
|
|
175
|
+
selectedLibraryVersion &&
|
|
176
|
+
requiredLibraryVersion &&
|
|
177
|
+
semver.satisfies(selectedLibraryVersion, requiredLibraryVersion, {
|
|
178
|
+
includePrerelease: true,
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const dynamicWidgets = supportsDynamicWidgets
|
|
182
|
+
? [
|
|
183
|
+
{
|
|
184
|
+
name: 'Dynamic widgets',
|
|
185
|
+
value: 'ais.dynamicWidgets',
|
|
186
|
+
checked: true,
|
|
187
|
+
},
|
|
188
|
+
new inquirer.Separator(),
|
|
189
|
+
]
|
|
190
|
+
: [];
|
|
191
|
+
|
|
192
|
+
return [
|
|
193
|
+
...dynamicWidgets,
|
|
194
|
+
new inquirer.Separator('From your index'),
|
|
195
|
+
...(await getFacetsFromIndex(answers)),
|
|
196
|
+
new inquirer.Separator(),
|
|
197
|
+
];
|
|
198
|
+
},
|
|
199
|
+
filter: attributes => attributes.filter(Boolean),
|
|
200
|
+
when: ({ appId, apiKey, indexName }) =>
|
|
201
|
+
attributesForFaceting.length === 0 && appId && apiKey && indexName,
|
|
157
202
|
},
|
|
158
203
|
],
|
|
159
204
|
widget: [
|
|
@@ -179,95 +224,141 @@ const getQuestions = ({ appName }) => ({
|
|
|
179
224
|
},
|
|
180
225
|
},
|
|
181
226
|
],
|
|
182
|
-
|
|
227
|
+
initial: [
|
|
228
|
+
{
|
|
229
|
+
type: 'input',
|
|
230
|
+
name: 'appPath',
|
|
231
|
+
message: 'Project directory',
|
|
232
|
+
askAnswered: true,
|
|
233
|
+
validate(input) {
|
|
234
|
+
try {
|
|
235
|
+
return checkAppPath(input);
|
|
236
|
+
} catch (err) {
|
|
237
|
+
console.log();
|
|
238
|
+
console.error(err.message);
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
when(answers) {
|
|
243
|
+
try {
|
|
244
|
+
return (
|
|
245
|
+
answers.interactive &&
|
|
246
|
+
!answers.config &&
|
|
247
|
+
!checkAppPath(answers.appPath)
|
|
248
|
+
);
|
|
249
|
+
} catch (err) {
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
type: 'input',
|
|
256
|
+
name: 'appName',
|
|
257
|
+
message: 'The name of the application or widget',
|
|
258
|
+
askAnswered: true,
|
|
259
|
+
default(answers) {
|
|
260
|
+
return path.basename(answers.appPath);
|
|
261
|
+
},
|
|
262
|
+
validate(input) {
|
|
263
|
+
try {
|
|
264
|
+
return checkAppName(input);
|
|
265
|
+
} catch (err) {
|
|
266
|
+
console.log();
|
|
267
|
+
console.error(err.message);
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
when(answers) {
|
|
272
|
+
try {
|
|
273
|
+
return (
|
|
274
|
+
answers.interactive &&
|
|
275
|
+
!answers.config &&
|
|
276
|
+
!checkAppName(answers.appName)
|
|
277
|
+
);
|
|
278
|
+
} catch (err) {
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
type: 'list',
|
|
285
|
+
pageSize: 10,
|
|
286
|
+
name: 'template',
|
|
287
|
+
message: 'InstantSearch template',
|
|
288
|
+
askAnswered: true,
|
|
289
|
+
choices: () => {
|
|
290
|
+
const templatesByCategory = getTemplatesByCategory();
|
|
183
291
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
292
|
+
return Object.entries(templatesByCategory).reduce(
|
|
293
|
+
(templates, [category, values]) => [
|
|
294
|
+
...templates,
|
|
295
|
+
new inquirer.Separator(category),
|
|
296
|
+
...values,
|
|
297
|
+
],
|
|
298
|
+
[]
|
|
299
|
+
);
|
|
192
300
|
},
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
199
|
-
try {
|
|
200
|
-
checkAppPath(appPath);
|
|
201
|
-
} catch (err) {
|
|
202
|
-
console.error(err.message);
|
|
203
|
-
console.log();
|
|
301
|
+
validate(input) {
|
|
302
|
+
// if a config is given, path is optional
|
|
303
|
+
if (optionsFromArguments.config) {
|
|
304
|
+
return true;
|
|
305
|
+
}
|
|
204
306
|
|
|
205
|
-
|
|
206
|
-
|
|
307
|
+
const isValid = Boolean(input);
|
|
308
|
+
if (!isValid) {
|
|
309
|
+
console.log('template is required');
|
|
310
|
+
}
|
|
311
|
+
return isValid;
|
|
312
|
+
},
|
|
313
|
+
when(answers) {
|
|
314
|
+
return answers.interactive && !answers.config && !answers.template;
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
],
|
|
318
|
+
});
|
|
207
319
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
).appName;
|
|
220
|
-
}
|
|
320
|
+
async function run() {
|
|
321
|
+
const args = {
|
|
322
|
+
...optionsFromArguments,
|
|
323
|
+
appPath: appPathFromArgument,
|
|
324
|
+
appName: optionsFromArguments.name,
|
|
325
|
+
};
|
|
326
|
+
const initialQuestions = getQuestions({}).initial;
|
|
327
|
+
const initialAnswers = {
|
|
328
|
+
...args,
|
|
329
|
+
...(await inquirer.prompt(initialQuestions, args)),
|
|
330
|
+
};
|
|
221
331
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
332
|
+
initialQuestions.forEach(question => {
|
|
333
|
+
// .default doesn't get executed when "when" returns false
|
|
334
|
+
if (!initialAnswers[question.name] && question.default) {
|
|
335
|
+
const defaultValue = question.default(initialAnswers);
|
|
336
|
+
initialAnswers[question.name] = defaultValue;
|
|
337
|
+
}
|
|
338
|
+
if (!question.validate(initialAnswers[question.name])) {
|
|
339
|
+
process.exit(1);
|
|
340
|
+
}
|
|
341
|
+
});
|
|
227
342
|
|
|
228
|
-
|
|
343
|
+
if (initialAnswers.appPath.startsWith('~/')) {
|
|
344
|
+
initialAnswers.appPath = path.join(
|
|
345
|
+
os.homedir(),
|
|
346
|
+
initialAnswers.appPath.slice(2)
|
|
347
|
+
);
|
|
229
348
|
}
|
|
230
349
|
|
|
350
|
+
const { appPath, appName, template } = initialAnswers;
|
|
351
|
+
|
|
231
352
|
console.log();
|
|
232
353
|
console.log(`Creating a new InstantSearch app in ${chalk.green(appPath)}.`);
|
|
233
354
|
console.log();
|
|
234
355
|
|
|
235
|
-
const { template = optionsFromArguments.template } = await inquirer.prompt(
|
|
236
|
-
[
|
|
237
|
-
{
|
|
238
|
-
type: 'list',
|
|
239
|
-
pageSize: 10,
|
|
240
|
-
name: 'template',
|
|
241
|
-
message: 'InstantSearch template',
|
|
242
|
-
choices: () => {
|
|
243
|
-
const templatesByCategory = getTemplatesByCategory();
|
|
244
|
-
|
|
245
|
-
return Object.entries(templatesByCategory).reduce(
|
|
246
|
-
(templates, [category, values]) => [
|
|
247
|
-
...templates,
|
|
248
|
-
new inquirer.Separator(category),
|
|
249
|
-
...values,
|
|
250
|
-
],
|
|
251
|
-
[]
|
|
252
|
-
);
|
|
253
|
-
},
|
|
254
|
-
validate(input) {
|
|
255
|
-
return Boolean(input);
|
|
256
|
-
},
|
|
257
|
-
},
|
|
258
|
-
].filter(question =>
|
|
259
|
-
isQuestionAsked({ question, args: optionsFromArguments })
|
|
260
|
-
),
|
|
261
|
-
optionsFromArguments
|
|
262
|
-
);
|
|
263
|
-
|
|
264
356
|
const configuration = await getConfiguration({
|
|
265
357
|
options: {
|
|
266
358
|
...optionsFromArguments,
|
|
267
359
|
name: appName,
|
|
268
|
-
attributesToDisplay,
|
|
269
360
|
},
|
|
270
|
-
answers:
|
|
361
|
+
answers: initialAnswers,
|
|
271
362
|
});
|
|
272
363
|
|
|
273
364
|
const templatePath = getTemplatePath(configuration.template);
|
|
@@ -277,34 +368,21 @@ async function run() {
|
|
|
277
368
|
templateConfig.category === 'Widget' ? 'widget' : 'application';
|
|
278
369
|
|
|
279
370
|
const answers = await inquirer.prompt(
|
|
280
|
-
getQuestions({ appName })[implementationType].filter(
|
|
281
|
-
isQuestionAsked({ question, args: optionsFromArguments })
|
|
371
|
+
getQuestions({ appName })[implementationType].filter(
|
|
372
|
+
question => !isQuestionAsked({ question, args: optionsFromArguments })
|
|
282
373
|
),
|
|
283
|
-
|
|
284
|
-
);
|
|
285
|
-
|
|
286
|
-
const alternativeNames = createNameAlternatives({
|
|
287
|
-
...configuration,
|
|
288
|
-
...answers,
|
|
289
|
-
templateConfig,
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
const libraryVersion = await getLibraryVersion(
|
|
293
|
-
{ ...configuration, ...answers },
|
|
294
|
-
templateConfig
|
|
374
|
+
getAnswersDefaultValues(optionsFromArguments, configuration, template)
|
|
295
375
|
);
|
|
296
376
|
|
|
297
377
|
const app = createInstantSearchApp(
|
|
298
378
|
appPath,
|
|
299
|
-
{
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
currentYear: new Date().getFullYear(),
|
|
307
|
-
},
|
|
379
|
+
await postProcessAnswers({
|
|
380
|
+
configuration,
|
|
381
|
+
answers,
|
|
382
|
+
optionsFromArguments,
|
|
383
|
+
templatePath,
|
|
384
|
+
templateConfig,
|
|
385
|
+
}),
|
|
308
386
|
templateConfig.tasks
|
|
309
387
|
);
|
|
310
388
|
|
|
@@ -1,22 +1,15 @@
|
|
|
1
1
|
module.exports = function isQuestionAsked({ question, args }) {
|
|
2
|
-
if
|
|
3
|
-
|
|
2
|
+
// if there's a config, ask no questions, even if it would be invalid
|
|
3
|
+
if (args.config || !args.interactive) {
|
|
4
|
+
return true;
|
|
4
5
|
}
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
(question.validate && question.validate(args[optionName]))
|
|
12
|
-
) {
|
|
13
|
-
return false;
|
|
14
|
-
}
|
|
15
|
-
} else if (!question.validate) {
|
|
16
|
-
// Skip if the question is optional and not given in the command
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
7
|
+
const argument = args[question.name];
|
|
8
|
+
|
|
9
|
+
// Skip if the arg in the command is valid
|
|
10
|
+
if (question.validate) {
|
|
11
|
+
return question.validate(argument);
|
|
19
12
|
}
|
|
20
13
|
|
|
21
|
-
return
|
|
14
|
+
return argument !== undefined;
|
|
22
15
|
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
const camelCase = require('lodash.camelcase');
|
|
2
|
+
const latestSemver = require('latest-semver');
|
|
3
|
+
|
|
4
|
+
const { fetchLibraryVersions } = require('../utils');
|
|
5
|
+
|
|
6
|
+
function capitalize(str) {
|
|
7
|
+
return str.substr(0, 1).toUpperCase() + str.substr(1);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function createNameAlternatives({ organization, name, templateConfig }) {
|
|
11
|
+
return {
|
|
12
|
+
packageName: `@${organization}/${templateConfig.packageNamePrefix ||
|
|
13
|
+
''}${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 postProcessAnswers({
|
|
36
|
+
configuration,
|
|
37
|
+
answers,
|
|
38
|
+
optionsFromArguments,
|
|
39
|
+
templatePath,
|
|
40
|
+
templateConfig,
|
|
41
|
+
}) {
|
|
42
|
+
const combinedAnswers = {
|
|
43
|
+
...configuration,
|
|
44
|
+
...answers,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const alternativeNames = createNameAlternatives({
|
|
48
|
+
...combinedAnswers,
|
|
49
|
+
templateConfig,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const libraryVersion = await getLibraryVersion(
|
|
53
|
+
combinedAnswers,
|
|
54
|
+
templateConfig
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
...combinedAnswers,
|
|
59
|
+
...alternativeNames,
|
|
60
|
+
libraryVersion,
|
|
61
|
+
template: templatePath,
|
|
62
|
+
installation: optionsFromArguments.installation,
|
|
63
|
+
currentYear: new Date().getFullYear(),
|
|
64
|
+
attributesForFaceting:
|
|
65
|
+
Array.isArray(combinedAnswers.attributesForFaceting) &&
|
|
66
|
+
combinedAnswers.attributesForFaceting.filter(
|
|
67
|
+
attribute => attribute !== 'ais.dynamicWidgets'
|
|
68
|
+
),
|
|
69
|
+
flags: {
|
|
70
|
+
dynamicWidgets:
|
|
71
|
+
Array.isArray(combinedAnswers.attributesForFaceting) &&
|
|
72
|
+
combinedAnswers.attributesForFaceting.includes('ais.dynamicWidgets'),
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
module.exports = postProcessAnswers;
|
|
@@ -10,33 +10,33 @@
|
|
|
10
10
|
},
|
|
11
11
|
"private": true,
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@angular/animations": "
|
|
14
|
-
"@angular/common": "
|
|
15
|
-
"@angular/compiler": "
|
|
16
|
-
"@angular/core": "
|
|
17
|
-
"@angular/forms": "
|
|
18
|
-
"@angular/platform-browser": "
|
|
19
|
-
"@angular/platform-browser-dynamic": "
|
|
20
|
-
"@angular/router": "
|
|
21
|
-
"algoliasearch": "
|
|
13
|
+
"@angular/animations": "12.2.0",
|
|
14
|
+
"@angular/common": "12.2.0",
|
|
15
|
+
"@angular/compiler": "12.2.0",
|
|
16
|
+
"@angular/core": "12.2.0",
|
|
17
|
+
"@angular/forms": "12.2.0",
|
|
18
|
+
"@angular/platform-browser": "12.2.0",
|
|
19
|
+
"@angular/platform-browser-dynamic": "12.2.0",
|
|
20
|
+
"@angular/router": "12.2.0",
|
|
21
|
+
"algoliasearch": "4.10.5",
|
|
22
22
|
"angular-instantsearch": "{{libraryVersion}}",
|
|
23
|
-
"rxjs": "
|
|
24
|
-
"tslib": "
|
|
25
|
-
"zone.js": "
|
|
23
|
+
"rxjs": "6.6.0",
|
|
24
|
+
"tslib": "2.3.0",
|
|
25
|
+
"zone.js": "0.11.4"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@angular-devkit/build-angular": "
|
|
29
|
-
"@angular/cli": "
|
|
30
|
-
"@angular/compiler-cli": "
|
|
31
|
-
"@types/algoliasearch": "
|
|
32
|
-
"@types/jasmine": "
|
|
33
|
-
"@types/node": "
|
|
34
|
-
"jasmine-core": "
|
|
35
|
-
"karma": "
|
|
36
|
-
"karma-chrome-launcher": "
|
|
37
|
-
"karma-coverage": "
|
|
38
|
-
"karma-jasmine": "
|
|
39
|
-
"karma-jasmine-html-reporter": "
|
|
40
|
-
"typescript": "
|
|
28
|
+
"@angular-devkit/build-angular": "12.2.3",
|
|
29
|
+
"@angular/cli": "12.2.3",
|
|
30
|
+
"@angular/compiler-cli": "12.2.0",
|
|
31
|
+
"@types/algoliasearch": "4.0.0",
|
|
32
|
+
"@types/jasmine": "3.8.0",
|
|
33
|
+
"@types/node": "12.11.1",
|
|
34
|
+
"jasmine-core": "3.8.0",
|
|
35
|
+
"karma": "6.3.0",
|
|
36
|
+
"karma-chrome-launcher": "3.1.0",
|
|
37
|
+
"karma-coverage": "2.0.3",
|
|
38
|
+
"karma-jasmine": "4.0.0",
|
|
39
|
+
"karma-jasmine-html-reporter": "1.7.0",
|
|
40
|
+
"typescript": "4.3.5"
|
|
41
41
|
}
|
|
42
42
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
<base href="/">
|
|
7
7
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
8
8
|
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
|
9
|
+
<link href="https://cdn.jsdelivr.net/npm/instantsearch.css@7/themes/satellite.css" rel="stylesheet" />
|
|
9
10
|
</head>
|
|
10
11
|
<body>
|
|
11
12
|
<app-root></app-root>
|
|
@@ -1,3 +1,11 @@
|
|
|
1
1
|
/* You can add global styles to this file, and also import other style files */
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
body,
|
|
3
|
+
h1 {
|
|
4
|
+
margin: 0;
|
|
5
|
+
padding: 0;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
body {
|
|
9
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica,
|
|
10
|
+
Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
|
|
11
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/* eslint-disable import/no-commonjs */
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
extends: ['algolia', 'algolia/react'],
|
|
5
|
+
settings: {
|
|
6
|
+
react: {
|
|
7
|
+
pragma: 'React',
|
|
8
|
+
version: 'preact',
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
rules: {
|
|
12
|
+
'jsdoc/check-tag-names': [
|
|
13
|
+
'error',
|
|
14
|
+
{
|
|
15
|
+
jsxTags: true,
|
|
16
|
+
},
|
|
17
|
+
],
|
|
18
|
+
'react/jsx-filename-extension': 'off',
|
|
19
|
+
},
|
|
20
|
+
};
|