create-instantsearch-app 4.10.3 → 5.0.1
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 +55 -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 -2
- package/src/templates/InstantSearch.js/src/app.js.hbs +24 -0
- package/src/templates/React InstantSearch/.template.js +4 -0
- package/src/templates/React InstantSearch/src/App.js.hbs +13 -2
- package/src/templates/Vue InstantSearch/.template.js +4 -1
- package/src/templates/Vue InstantSearch/src/App.vue +9 -2
- 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,21 @@
|
|
|
1
|
+
# {{name}}
|
|
2
|
+
|
|
3
|
+
_This project was generated with [create-instantsearch-app](https://github.com/algolia/create-instantsearch-app) by [Algolia](https://algolia.com)._
|
|
4
|
+
|
|
5
|
+
## Get started
|
|
6
|
+
|
|
7
|
+
To run this project locally, install the dependencies and run the local server:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install
|
|
11
|
+
npm start
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Alternatively, you may use [Yarn](https://http://yarnpkg.com/):
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
yarn
|
|
18
|
+
yarn start
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Open http://localhost:3000 to see your app.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** @jsx h */
|
|
2
|
+
import { autocomplete, getAlgoliaResults } from '@algolia/autocomplete-js';
|
|
3
|
+
import algoliasearch from 'algoliasearch';
|
|
4
|
+
import { h } from 'preact';
|
|
5
|
+
|
|
6
|
+
import '@algolia/autocomplete-theme-classic';
|
|
7
|
+
|
|
8
|
+
const searchClient = algoliasearch('{{appId}}', '{{apiKey}}');
|
|
9
|
+
|
|
10
|
+
autocomplete({
|
|
11
|
+
container: '#autocomplete',
|
|
12
|
+
placeholder: '{{placeholder}}',
|
|
13
|
+
debug: true,
|
|
14
|
+
getSources({ query }) {
|
|
15
|
+
return [
|
|
16
|
+
{
|
|
17
|
+
sourceId: 'items',
|
|
18
|
+
getItems() {
|
|
19
|
+
return getAlgoliaResults({
|
|
20
|
+
searchClient,
|
|
21
|
+
queries: [
|
|
22
|
+
{
|
|
23
|
+
indexName: '{{indexName}}',
|
|
24
|
+
query,
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
});
|
|
28
|
+
},
|
|
29
|
+
templates: {
|
|
30
|
+
item({ item, components }) {
|
|
31
|
+
return (
|
|
32
|
+
<div className="aa-ItemWrapper">
|
|
33
|
+
<div className="aa-ItemContent">
|
|
34
|
+
<div className="aa-ItemContentBody">
|
|
35
|
+
<div className="aa-ItemContentTitle">
|
|
36
|
+
<components.Highlight
|
|
37
|
+
hit={item}
|
|
38
|
+
attribute="{{attributesToDisplay.[0]}}"
|
|
39
|
+
/>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
);
|
|
45
|
+
},
|
|
46
|
+
noResults() {
|
|
47
|
+
return 'No matching items.';
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
];
|
|
52
|
+
},
|
|
53
|
+
});
|
|
Binary file
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<html lang="en">
|
|
2
|
+
<head>
|
|
3
|
+
<meta charset="UTF-8" />
|
|
4
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
5
|
+
|
|
6
|
+
<link rel="shortcut icon" href="favicon.png" type="image/x-icon" />
|
|
7
|
+
<link rel="stylesheet" href="style.css" />
|
|
8
|
+
|
|
9
|
+
<title>{{name}}</title>
|
|
10
|
+
</head>
|
|
11
|
+
|
|
12
|
+
<body>
|
|
13
|
+
<div class="container">
|
|
14
|
+
<div id="autocomplete"></div>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<script src="app.js"></script>
|
|
18
|
+
</body>
|
|
19
|
+
</html>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"short_name": "{{name}}",
|
|
3
|
+
"name": "{{name}} Sample",
|
|
4
|
+
"icons": [
|
|
5
|
+
{
|
|
6
|
+
"src": "favicon.png",
|
|
7
|
+
"sizes": "64x64 32x32 24x24 16x16",
|
|
8
|
+
"type": "image/x-icon"
|
|
9
|
+
}
|
|
10
|
+
],
|
|
11
|
+
"start_url": "./index.html",
|
|
12
|
+
"display": "standalone",
|
|
13
|
+
"theme_color": "#000000",
|
|
14
|
+
"background_color": "#ffffff"
|
|
15
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{name}}",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "parcel build index.html",
|
|
7
|
+
"start": "parcel index.html --port 3000",
|
|
8
|
+
"lint": "eslint ."
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@algolia/autocomplete-js": "{{libraryVersion}}",
|
|
12
|
+
"@algolia/autocomplete-theme-classic": "{{libraryVersion}}",
|
|
13
|
+
"algoliasearch": "4.10.5",
|
|
14
|
+
"preact": "10.5.14"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"babel-eslint": "10.1.0",
|
|
18
|
+
"eslint": "7.32.0",
|
|
19
|
+
"eslint-config-algolia": "19.0.2",
|
|
20
|
+
"eslint-config-prettier": "8.3.0",
|
|
21
|
+
"eslint-plugin-eslint-comments": "3.2.0",
|
|
22
|
+
"eslint-plugin-import": "2.24.2",
|
|
23
|
+
"eslint-plugin-jsdoc": "36.1.0",
|
|
24
|
+
"eslint-plugin-jsx-a11y": "6.4.1",
|
|
25
|
+
"eslint-plugin-prettier": "4.0.0",
|
|
26
|
+
"eslint-plugin-react": "7.26.0",
|
|
27
|
+
"eslint-plugin-react-hooks": "4.2.0",
|
|
28
|
+
"parcel": "2.0.0-beta.2",
|
|
29
|
+
"prettier": "1.19.1"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"algolia",
|
|
33
|
+
"autocomplete",
|
|
34
|
+
"javascript"
|
|
35
|
+
]
|
|
36
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
* {
|
|
2
|
+
box-sizing: border-box;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
body {
|
|
6
|
+
background-color: rgb(244, 244, 249);
|
|
7
|
+
color: rgb(65, 65, 65);
|
|
8
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
|
9
|
+
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
|
10
|
+
sans-serif;
|
|
11
|
+
-webkit-font-smoothing: antialiased;
|
|
12
|
+
-moz-osx-font-smoothing: grayscale;
|
|
13
|
+
padding: 1rem;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.container {
|
|
17
|
+
margin: 0 auto;
|
|
18
|
+
max-width: 640px;
|
|
19
|
+
width: 100%;
|
|
20
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -3,7 +3,7 @@ const teardown = require('../../tasks/node/teardown');
|
|
|
3
3
|
|
|
4
4
|
module.exports = {
|
|
5
5
|
libraryName: 'autocomplete.js',
|
|
6
|
-
templateName: 'autocomplete.js',
|
|
6
|
+
templateName: 'autocomplete.js-0.x',
|
|
7
7
|
appName: 'autocomplete.js-app',
|
|
8
8
|
keywords: ['algolia', 'Autocomplete', 'autocomplete.js'],
|
|
9
9
|
tasks: {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -5,6 +5,9 @@ module.exports = {
|
|
|
5
5
|
category: 'Web',
|
|
6
6
|
libraryName: 'instantsearch.js',
|
|
7
7
|
supportedVersion: '>= 3.0.0 < 5.0.0',
|
|
8
|
+
flags: {
|
|
9
|
+
dynamicWidgets: '>= 4.30',
|
|
10
|
+
},
|
|
8
11
|
templateName: 'instantsearch.js',
|
|
9
12
|
appName: 'instantsearch.js-app',
|
|
10
13
|
keywords: ['algolia', 'InstantSearch', 'Vanilla', 'instantsearch.js'],
|
|
@@ -31,14 +31,16 @@
|
|
|
31
31
|
|
|
32
32
|
<div class="container">
|
|
33
33
|
<div class="search-panel">
|
|
34
|
-
{{#if attributesForFaceting}}
|
|
35
34
|
<div class="search-panel__filters">
|
|
35
|
+
{{#if flags.dynamicWidgets}}
|
|
36
|
+
<div id="dynamic-widgets"></div>
|
|
37
|
+
{{else}}
|
|
36
38
|
{{#each attributesForFaceting}}
|
|
37
39
|
<div id="{{this}}-list"></div>
|
|
38
40
|
{{/each}}
|
|
41
|
+
{{/if}}
|
|
39
42
|
</div>
|
|
40
43
|
|
|
41
|
-
{{/if}}
|
|
42
44
|
<div class="search-panel__results">
|
|
43
45
|
<div id="searchbox"></div>
|
|
44
46
|
<div id="hits"></div>
|
|
@@ -31,12 +31,36 @@ search.addWidgets([
|
|
|
31
31
|
},
|
|
32
32
|
{{/if}}
|
|
33
33
|
}),
|
|
34
|
+
{{#if flags.dynamicWidgets}}
|
|
35
|
+
instantsearch.widgets.configure({
|
|
36
|
+
facets: ['*'],
|
|
37
|
+
maxValuesPerFacet: 20,
|
|
38
|
+
}),
|
|
39
|
+
instantsearch.widgets.dynamicWidgets({
|
|
40
|
+
container: '#dynamic-widgets',
|
|
41
|
+
fallbackWidget({ container, attribute }) {
|
|
42
|
+
return instantsearch.widgets.refinementList({
|
|
43
|
+
container,
|
|
44
|
+
attribute,
|
|
45
|
+
});
|
|
46
|
+
},
|
|
47
|
+
widgets: [
|
|
48
|
+
{{#each attributesForFaceting}}
|
|
49
|
+
container => instantsearch.widgets.refinementList({
|
|
50
|
+
container,
|
|
51
|
+
attribute: '{{this}}',
|
|
52
|
+
}),
|
|
53
|
+
{{/each}}
|
|
54
|
+
],
|
|
55
|
+
}),
|
|
56
|
+
{{else}}
|
|
34
57
|
{{#each attributesForFaceting}}
|
|
35
58
|
instantsearch.widgets.refinementList({
|
|
36
59
|
container: '#{{this}}-list',
|
|
37
60
|
attribute: '{{this}}',
|
|
38
61
|
}),
|
|
39
62
|
{{/each}}
|
|
63
|
+
{{/if}}
|
|
40
64
|
instantsearch.widgets.pagination({
|
|
41
65
|
container: '#pagination',
|
|
42
66
|
}),
|
|
@@ -4,6 +4,10 @@ const teardown = require('../../tasks/node/teardown');
|
|
|
4
4
|
module.exports = {
|
|
5
5
|
category: 'Web',
|
|
6
6
|
libraryName: 'react-instantsearch-dom',
|
|
7
|
+
supportedVersion: '>= 5.0.0 < 7.0.0',
|
|
8
|
+
flags: {
|
|
9
|
+
dynamicWidgets: '>=6.12',
|
|
10
|
+
},
|
|
7
11
|
templateName: 'react-instantsearch',
|
|
8
12
|
appName: 'react-instantsearch-app',
|
|
9
13
|
keywords: ['algolia', 'InstantSearch', 'React', 'react-instantsearch'],
|
|
@@ -4,6 +4,10 @@ import {
|
|
|
4
4
|
InstantSearch,
|
|
5
5
|
Hits,
|
|
6
6
|
SearchBox,
|
|
7
|
+
{{#if flags.dynamicWidgets}}
|
|
8
|
+
Configure,
|
|
9
|
+
ExperimentalDynamicWidgets,
|
|
10
|
+
{{/if}}
|
|
7
11
|
{{#if attributesForFaceting}}
|
|
8
12
|
RefinementList,
|
|
9
13
|
{{/if}}
|
|
@@ -35,14 +39,21 @@ function App() {
|
|
|
35
39
|
<div className="container">
|
|
36
40
|
<InstantSearch searchClient={searchClient} indexName="{{indexName}}">
|
|
37
41
|
<div className="search-panel">
|
|
38
|
-
{{#if attributesForFaceting}}
|
|
39
42
|
<div className="search-panel__filters">
|
|
43
|
+
{{#if flags.dynamicWidgets}}
|
|
44
|
+
<Configure facets={['*']} maxValuesPerFacet={20} />
|
|
45
|
+
<ExperimentalDynamicWidgets fallbackWidget={RefinementList}>
|
|
46
|
+
{{#each attributesForFaceting}}
|
|
47
|
+
<RefinementList attribute="{{this}}" />
|
|
48
|
+
{{/each}}
|
|
49
|
+
</ExperimentalDynamicWidgets>
|
|
50
|
+
{{else}}
|
|
40
51
|
{{#each attributesForFaceting}}
|
|
41
52
|
<RefinementList attribute="{{this}}" />
|
|
42
53
|
{{/each}}
|
|
54
|
+
{{/if}}
|
|
43
55
|
</div>
|
|
44
56
|
|
|
45
|
-
{{/if}}
|
|
46
57
|
<div className="search-panel__results">
|
|
47
58
|
<SearchBox
|
|
48
59
|
className="searchbox"
|
|
@@ -4,8 +4,11 @@ const teardown = require('../../tasks/node/teardown');
|
|
|
4
4
|
module.exports = {
|
|
5
5
|
category: 'Web',
|
|
6
6
|
libraryName: 'vue-instantsearch',
|
|
7
|
-
templateName: 'vue-instantsearch',
|
|
8
7
|
supportedVersion: '>= 3.0.0 < 5.0.0',
|
|
8
|
+
flags: {
|
|
9
|
+
dynamicWidgets: '>=3.8.0',
|
|
10
|
+
},
|
|
11
|
+
templateName: 'vue-instantsearch',
|
|
9
12
|
appName: 'vue-instantsearch-app',
|
|
10
13
|
keywords: ['algolia', 'InstantSearch', 'Vue', 'vue-instantsearch'],
|
|
11
14
|
tasks: {
|
|
@@ -17,14 +17,21 @@
|
|
|
17
17
|
<div class="container">
|
|
18
18
|
<ais-instant-search :search-client="searchClient" index-name="{{indexName}}">
|
|
19
19
|
<div class="search-panel">
|
|
20
|
-
{{#if attributesForFaceting.length}}
|
|
21
20
|
<div class="search-panel__filters">
|
|
21
|
+
{{#if flags.dynamicWidgets}}
|
|
22
|
+
<ais-configure :facets="['*']" :max-values-per-facet.camel="20" />
|
|
23
|
+
<ais-experimental-dynamic-widgets>
|
|
24
|
+
{{#each attributesForFaceting}}
|
|
25
|
+
<ais-refinement-list attribute="{{this}}" />
|
|
26
|
+
{{/each}}
|
|
27
|
+
</ais-experimental-dynamic-widgets>
|
|
28
|
+
{{else}}
|
|
22
29
|
{{#each attributesForFaceting}}
|
|
23
30
|
<ais-refinement-list attribute="{{this}}" />
|
|
24
31
|
{{/each}}
|
|
32
|
+
{{/if}}
|
|
25
33
|
</div>
|
|
26
34
|
|
|
27
|
-
{{/if}}
|
|
28
35
|
<div class="search-panel__results">
|
|
29
36
|
<div class="searchbox">
|
|
30
37
|
<ais-search-box placeholder="{{searchPlaceholder}}" />
|
|
@@ -5,7 +5,3 @@ exports[`checkAppName throws with correct error message 1`] = `
|
|
|
5
5
|
- name cannot start with a period
|
|
6
6
|
- name can only contain URL-friendly characters"
|
|
7
7
|
`;
|
|
8
|
-
|
|
9
|
-
exports[`checkAppPath with existing file as path should throw with correct error 1`] = `"Could not create project at path [31mpath[39m because a file of the same name already exists."`;
|
|
10
|
-
|
|
11
|
-
exports[`checkAppPath with non empty directory as path should throw with correct error 1`] = `"Could not create project in destination folder \\"[31mpath[39m\\" because it is not empty."`;
|
|
@@ -23,7 +23,7 @@ describe('checkAppName', () => {
|
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
describe('checkAppPath', () => {
|
|
26
|
-
describe('with non
|
|
26
|
+
describe('with non existing directory as path', () => {
|
|
27
27
|
beforeAll(() => {
|
|
28
28
|
mockExistsSync.mockImplementation(() => false);
|
|
29
29
|
});
|
|
@@ -45,7 +45,11 @@ describe('checkAppPath', () => {
|
|
|
45
45
|
});
|
|
46
46
|
|
|
47
47
|
test('should throw with correct error', () => {
|
|
48
|
-
expect(() =>
|
|
48
|
+
expect(() =>
|
|
49
|
+
utils.checkAppPath('path')
|
|
50
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
51
|
+
`"Could not create project in destination folder \\"[31mpath[39m\\" because it is not empty."`
|
|
52
|
+
);
|
|
49
53
|
});
|
|
50
54
|
|
|
51
55
|
afterAll(() => {
|
|
@@ -64,7 +68,31 @@ describe('checkAppPath', () => {
|
|
|
64
68
|
});
|
|
65
69
|
|
|
66
70
|
test('should throw with correct error', () => {
|
|
67
|
-
expect(() =>
|
|
71
|
+
expect(() =>
|
|
72
|
+
utils.checkAppPath('path')
|
|
73
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
74
|
+
`"Could not create project at path [31mpath[39m because a file of the same name already exists."`
|
|
75
|
+
);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
afterAll(() => {
|
|
79
|
+
mockExistsSync.mockReset();
|
|
80
|
+
mockLstatSync.mockReset();
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe('with empty string as path', () => {
|
|
85
|
+
beforeAll(() => {
|
|
86
|
+
mockExistsSync.mockImplementation(() => false);
|
|
87
|
+
mockLstatSync.mockImplementation(() => ({
|
|
88
|
+
isDirectory: () => false,
|
|
89
|
+
}));
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test('should throw with correct error', () => {
|
|
93
|
+
expect(() => utils.checkAppPath('')).toThrowErrorMatchingInlineSnapshot(
|
|
94
|
+
`"Could not create project without directory"`
|
|
95
|
+
);
|
|
68
96
|
});
|
|
69
97
|
|
|
70
98
|
afterAll(() => {
|
package/src/utils/index.js
CHANGED
|
@@ -56,6 +56,10 @@ function checkAppPath(appPath) {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
if (!appPath) {
|
|
60
|
+
throw new Error('Could not create project without directory');
|
|
61
|
+
}
|
|
62
|
+
|
|
59
63
|
return true;
|
|
60
64
|
}
|
|
61
65
|
|
|
@@ -126,7 +130,9 @@ function getTemplatePath(templateName) {
|
|
|
126
130
|
}
|
|
127
131
|
|
|
128
132
|
async function fetchLibraryVersions(libraryName) {
|
|
129
|
-
const library = await index.getObject(libraryName
|
|
133
|
+
const library = await index.getObject(libraryName, {
|
|
134
|
+
attributesToRetrieve: ['versions'],
|
|
135
|
+
});
|
|
130
136
|
|
|
131
137
|
return Object.keys(library.versions).reverse();
|
|
132
138
|
}
|
|
@@ -147,6 +153,12 @@ async function getEarliestLibraryVersion(...args) {
|
|
|
147
153
|
return await getLibraryVersion(...args)(semver.minSatisfying);
|
|
148
154
|
}
|
|
149
155
|
|
|
156
|
+
const splitArray = string =>
|
|
157
|
+
string
|
|
158
|
+
.split(',')
|
|
159
|
+
.filter(Boolean)
|
|
160
|
+
.map(x => x.trim());
|
|
161
|
+
|
|
150
162
|
module.exports = {
|
|
151
163
|
checkAppName,
|
|
152
164
|
checkAppPath,
|
|
@@ -158,4 +170,5 @@ module.exports = {
|
|
|
158
170
|
getAllTemplates,
|
|
159
171
|
getTemplatePath,
|
|
160
172
|
getTemplatesByCategory,
|
|
173
|
+
splitArray,
|
|
161
174
|
};
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
const getOptionsFromArguments = require('../getOptionsFromArguments');
|
|
2
|
-
|
|
3
|
-
test('with a single option', () => {
|
|
4
|
-
expect(getOptionsFromArguments('cmd --appId APP_ID'.split(' '))).toEqual({
|
|
5
|
-
appId: 'APP_ID',
|
|
6
|
-
});
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
test('with multiple options', () => {
|
|
10
|
-
expect(
|
|
11
|
-
getOptionsFromArguments([
|
|
12
|
-
'cmd',
|
|
13
|
-
'--appId',
|
|
14
|
-
'APP_ID',
|
|
15
|
-
'--apiKey',
|
|
16
|
-
'API_KEY',
|
|
17
|
-
'--indexName',
|
|
18
|
-
'INDEX_NAME',
|
|
19
|
-
'--template',
|
|
20
|
-
'Vue InstantSearch',
|
|
21
|
-
])
|
|
22
|
-
).toEqual({
|
|
23
|
-
appId: 'APP_ID',
|
|
24
|
-
apiKey: 'API_KEY',
|
|
25
|
-
indexName: 'INDEX_NAME',
|
|
26
|
-
template: 'Vue InstantSearch',
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
test('with different commands', () => {
|
|
31
|
-
expect(
|
|
32
|
-
getOptionsFromArguments(['yarn', 'start', '--appId', 'APP_ID'])
|
|
33
|
-
).toEqual({
|
|
34
|
-
appId: 'APP_ID',
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
expect(
|
|
38
|
-
getOptionsFromArguments(['node', 'index', '--appId', 'APP_ID'])
|
|
39
|
-
).toEqual({
|
|
40
|
-
appId: 'APP_ID',
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
expect(
|
|
44
|
-
getOptionsFromArguments([
|
|
45
|
-
'npm',
|
|
46
|
-
'init',
|
|
47
|
-
'instantsearch-app',
|
|
48
|
-
'--appId',
|
|
49
|
-
'APP_ID',
|
|
50
|
-
])
|
|
51
|
-
).toEqual({
|
|
52
|
-
appId: 'APP_ID',
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
expect(
|
|
56
|
-
getOptionsFromArguments([
|
|
57
|
-
'yarn',
|
|
58
|
-
'create',
|
|
59
|
-
'instantsearch-app',
|
|
60
|
-
'--appId',
|
|
61
|
-
'APP_ID',
|
|
62
|
-
])
|
|
63
|
-
).toEqual({
|
|
64
|
-
appId: 'APP_ID',
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
expect(
|
|
68
|
-
getOptionsFromArguments(['create-instantsearch-app', '--appId', 'APP_ID'])
|
|
69
|
-
).toEqual({
|
|
70
|
-
appId: 'APP_ID',
|
|
71
|
-
});
|
|
72
|
-
});
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
const camelCase = require('lodash.camelcase');
|
|
2
|
-
|
|
3
|
-
module.exports = function getOptionsFromArguments(rawArgs) {
|
|
4
|
-
let argIndex = 0;
|
|
5
|
-
|
|
6
|
-
return rawArgs.reduce((allArgs, currentArg) => {
|
|
7
|
-
argIndex++;
|
|
8
|
-
|
|
9
|
-
if (!currentArg.startsWith('--') || currentArg.startsWith('--no-')) {
|
|
10
|
-
return allArgs;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const argumentName = camelCase(currentArg.split('--')[1]);
|
|
14
|
-
const argumentValue = rawArgs[argIndex];
|
|
15
|
-
|
|
16
|
-
return {
|
|
17
|
-
...allArgs,
|
|
18
|
-
[argumentName]: argumentValue,
|
|
19
|
-
};
|
|
20
|
-
}, {});
|
|
21
|
-
};
|