create-instantsearch-app 6.3.1 → 6.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-instantsearch-app",
3
- "version": "6.3.1",
3
+ "version": "6.4.1",
4
4
  "license": "MIT",
5
5
  "description": "⚡️ Build InstantSearch apps at the speed of thought",
6
6
  "keywords": [
@@ -33,17 +33,16 @@
33
33
  },
34
34
  "dependencies": {
35
35
  "@algolia/cache-in-memory": "4",
36
+ "@metalsmith/in-place": "4.6.0",
37
+ "@metalsmith/remove": "1.3.0",
36
38
  "algoliasearch": "4",
37
39
  "chalk": "3.0.0",
38
40
  "commander": "4.1.1",
39
41
  "inquirer": "8.0.0",
40
42
  "jstransformer-handlebars": "1.1.0",
41
- "latest-semver": "2.0.0",
42
43
  "load-json-file": "6.2.0",
43
44
  "lodash.camelcase": "4.3.0",
44
- "metalsmith": "2.3.0",
45
- "metalsmith-ignore": "1.0.0",
46
- "metalsmith-in-place": "4.4.1",
45
+ "metalsmith": "2.5.1",
47
46
  "metalsmith-rename": "1.0.0",
48
47
  "prettier": "1.19.1",
49
48
  "semver": "6.1.1",
@@ -53,5 +52,5 @@
53
52
  "jest-image-snapshot": "2.12.0",
54
53
  "walk-sync": "2.0.2"
55
54
  },
56
- "gitHead": "c483ae31e1e615be61dffb5d0bc04a4927960a67"
55
+ "gitHead": "f4acbc0c1106a4fd7c7ad95a3e02de4fdac1ad27"
57
56
  }
@@ -1,4 +1,5 @@
1
1
  const path = require('path');
2
+
2
3
  const createInstantSearchAppFactory = require('../');
3
4
 
4
5
  let setupSpy;
@@ -1,4 +1,5 @@
1
1
  const path = require('path');
2
+
2
3
  const resolveTemplate = require('../resolve-template');
3
4
 
4
5
  describe('resolveTemplate', () => {
@@ -1,5 +1,6 @@
1
- const path = require('path');
2
1
  const fs = require('fs');
2
+ const path = require('path');
3
+
3
4
  const { checkAppName, checkAppPath } = require('../utils');
4
5
 
5
6
  function getOptions({ supportedTemplates }) {
package/src/api/index.js CHANGED
@@ -1,10 +1,12 @@
1
1
  const path = require('path');
2
- const checkConfig = require('./check-config');
3
- const resolveTemplate = require('./resolve-template');
2
+
4
3
  const buildTask = require('../tasks/common/build');
5
4
  const cleanTask = require('../tasks/common/clean');
6
5
  const { getAllTemplates } = require('../utils');
7
6
 
7
+ const checkConfig = require('./check-config');
8
+ const resolveTemplate = require('./resolve-template');
9
+
8
10
  const supportedTemplates = getAllTemplates();
9
11
 
10
12
  function noop() {}
@@ -1,5 +1,7 @@
1
1
  const path = require('path');
2
+
2
3
  const semver = require('semver');
4
+
3
5
  const { getAppTemplateConfig } = require('../utils');
4
6
 
5
7
  function getTemplateNameByLibraryVersion({
@@ -1,4 +1,5 @@
1
1
  const loadJsonFile = require('load-json-file');
2
+
2
3
  const getConfiguration = require('../getConfiguration');
3
4
 
4
5
  jest.mock('load-json-file');
@@ -1,4 +1,5 @@
1
1
  const algoliasearch = require('algoliasearch');
2
+
2
3
  const getInformationFromIndex = require('../getInformationFromIndex');
3
4
 
4
5
  jest.mock('algoliasearch', () => {
@@ -1,5 +1,5 @@
1
- const postProcessAnswers = require('../postProcessAnswers');
2
1
  const utils = require('../../utils');
2
+ const postProcessAnswers = require('../postProcessAnswers');
3
3
 
4
4
  jest.mock('../../utils', () => ({
5
5
  ...jest.requireActual('../../utils'),
@@ -80,32 +80,109 @@ test('creates alternative names', async () => {
80
80
  );
81
81
  });
82
82
 
83
- test('detects dynamic widgets', async () => {
84
- expect(
85
- await postProcessAnswers({
86
- configuration: {},
87
- templateConfig: {},
88
- optionsFromArguments: {},
89
- answers: { attributesForFaceting: ['ais.dynamicWidgets', 'test'] },
90
- })
91
- ).toEqual(
92
- expect.objectContaining({
93
- attributesForFaceting: ['test'],
94
- flags: { dynamicWidgets: true },
95
- })
96
- );
83
+ describe('flags', () => {
84
+ describe('dynamicWidgets', () => {
85
+ test('with usage of dynamicWidgets in attributesForFaceting', async () => {
86
+ expect(
87
+ await postProcessAnswers({
88
+ configuration: {},
89
+ templateConfig: {},
90
+ optionsFromArguments: {},
91
+ answers: { attributesForFaceting: ['ais.dynamicWidgets', 'test'] },
92
+ })
93
+ ).toEqual(
94
+ expect.objectContaining({
95
+ attributesForFaceting: ['test'],
96
+ flags: expect.objectContaining({ dynamicWidgets: true }),
97
+ })
98
+ );
99
+ });
97
100
 
98
- expect(
99
- await postProcessAnswers({
100
- configuration: {},
101
- templateConfig: {},
102
- optionsFromArguments: {},
103
- answers: { attributesForFaceting: ['test'] },
104
- })
105
- ).toEqual(
106
- expect.objectContaining({
107
- attributesForFaceting: ['test'],
108
- flags: { dynamicWidgets: false },
109
- })
110
- );
101
+ test('without usage of dynamicWidgets in attributesForFaceting', async () => {
102
+ expect(
103
+ await postProcessAnswers({
104
+ configuration: {},
105
+ templateConfig: {},
106
+ optionsFromArguments: {},
107
+ answers: { attributesForFaceting: ['test'] },
108
+ })
109
+ ).toEqual(
110
+ expect.objectContaining({
111
+ attributesForFaceting: ['test'],
112
+ flags: expect.objectContaining({ dynamicWidgets: false }),
113
+ })
114
+ );
115
+ });
116
+
117
+ test('without attributes', async () => {
118
+ expect(
119
+ await postProcessAnswers({
120
+ configuration: {},
121
+ templateConfig: {},
122
+ optionsFromArguments: {},
123
+ answers: {},
124
+ })
125
+ ).toEqual(
126
+ expect.objectContaining({
127
+ flags: expect.objectContaining({ dynamicWidgets: false }),
128
+ })
129
+ );
130
+ });
131
+ });
132
+
133
+ describe('insights', () => {
134
+ test('with a valid version', async () => {
135
+ utils.fetchLibraryVersions.mockImplementationOnce(() =>
136
+ Promise.resolve(['1.2.0'])
137
+ );
138
+
139
+ expect(
140
+ (
141
+ await postProcessAnswers({
142
+ configuration: {},
143
+ templateConfig: {
144
+ libraryName: 'instantsearch.js',
145
+ flags: {
146
+ insights: '>= 1',
147
+ },
148
+ },
149
+ optionsFromArguments: {},
150
+ })
151
+ ).flags
152
+ ).toEqual(expect.objectContaining({ insights: true }));
153
+ });
154
+
155
+ test('with an invalid version', async () => {
156
+ utils.fetchLibraryVersions.mockImplementationOnce(() =>
157
+ Promise.resolve(['1.2.0'])
158
+ );
159
+
160
+ expect(
161
+ (
162
+ await postProcessAnswers({
163
+ configuration: {},
164
+ templateConfig: {
165
+ libraryName: 'instantsearch.js',
166
+ flags: {
167
+ insights: '>= 1.3',
168
+ },
169
+ },
170
+ optionsFromArguments: {},
171
+ })
172
+ ).flags
173
+ ).toEqual(expect.objectContaining({ insights: false }));
174
+ });
175
+
176
+ test('without config', async () => {
177
+ expect(
178
+ (
179
+ await postProcessAnswers({
180
+ configuration: {},
181
+ templateConfig: {},
182
+ optionsFromArguments: {},
183
+ })
184
+ ).flags
185
+ ).toEqual(expect.objectContaining({ insights: false }));
186
+ });
187
+ });
111
188
  });
@@ -1,5 +1,5 @@
1
- const algoliasearch = require('algoliasearch');
2
1
  const { createInMemoryCache } = require('@algolia/cache-in-memory');
2
+ const algoliasearch = require('algoliasearch');
3
3
 
4
4
  const clients = new Map();
5
5
  function getClient(appId, apiKey) {
package/src/cli/index.js CHANGED
@@ -1,13 +1,14 @@
1
1
  #!/usr/bin/env node
2
+ const os = require('os');
2
3
  const path = require('path');
3
4
  const process = require('process');
4
- const os = require('os');
5
+
6
+ const chalk = require('chalk');
5
7
  const program = require('commander');
6
8
  const inquirer = require('inquirer');
7
- const chalk = require('chalk');
8
- const latestSemver = require('latest-semver');
9
9
  const semver = require('semver');
10
10
 
11
+ const { version } = require('../../package.json');
11
12
  const createInstantSearchApp = require('../api');
12
13
  const {
13
14
  checkAppPath,
@@ -18,13 +19,13 @@ const {
18
19
  getTemplatePath,
19
20
  splitArray,
20
21
  } = require('../utils');
22
+
23
+ const getAnswersDefaultValues = require('./getAnswersDefaultValues');
21
24
  const getAttributesFromIndex = require('./getAttributesFromIndex');
25
+ const getConfiguration = require('./getConfiguration');
22
26
  const getFacetsFromIndex = require('./getFacetsFromIndex');
23
- const getAnswersDefaultValues = require('./getAnswersDefaultValues');
24
27
  const isQuestionAsked = require('./isQuestionAsked');
25
- const getConfiguration = require('./getConfiguration');
26
28
  const postProcessAnswers = require('./postProcessAnswers');
27
- const { version } = require('../../package.json');
28
29
 
29
30
  let appPathFromArgument;
30
31
 
@@ -75,7 +76,9 @@ const getQuestions = ({ appName }) => ({
75
76
 
76
77
  try {
77
78
  const versions = await fetchLibraryVersions(libraryName);
78
- const latestStableVersion = latestSemver(versions);
79
+ const latestStableVersion = semver.maxSatisfying(versions, '*', {
80
+ includePrerelease: false,
81
+ });
79
82
 
80
83
  if (!latestStableVersion) {
81
84
  return versions;
@@ -1,5 +1,5 @@
1
1
  const camelCase = require('lodash.camelcase');
2
- const latestSemver = require('latest-semver');
2
+ const semver = require('semver');
3
3
 
4
4
  const { fetchLibraryVersions } = require('../utils');
5
5
 
@@ -24,10 +24,13 @@ async function getLibraryVersion(config, templateConfig) {
24
24
 
25
25
  if (libraryName && !libraryVersion) {
26
26
  const versions = await fetchLibraryVersions(libraryName);
27
+ const latestStableVersion = semver.maxSatisfying(versions, '*', {
28
+ includePrerelease: false,
29
+ });
27
30
 
28
31
  // Return the latest available version when
29
32
  // the stable version is not available
30
- return latestSemver(versions) || versions[0];
33
+ return latestStableVersion || versions[0];
31
34
  }
32
35
 
33
36
  return libraryVersion;
@@ -71,6 +74,9 @@ async function postProcessAnswers({
71
74
  dynamicWidgets:
72
75
  Array.isArray(combinedAnswers.attributesForFaceting) &&
73
76
  combinedAnswers.attributesForFaceting.includes('ais.dynamicWidgets'),
77
+ insights:
78
+ Boolean(templateConfig.flags && templateConfig.flags.insights) &&
79
+ semver.satisfies(libraryVersion, templateConfig.flags.insights),
74
80
  },
75
81
  };
76
82
  }
@@ -1,7 +1,7 @@
1
+ const inPlace = require('@metalsmith/in-place');
2
+ const remove = require('@metalsmith/remove');
1
3
  const metalsmith = require('metalsmith');
2
- const inPlace = require('metalsmith-in-place');
3
4
  const rename = require('metalsmith-rename');
4
- const ignore = require('metalsmith-ignore');
5
5
 
6
6
  module.exports = function build(config) {
7
7
  return new Promise((resolve, reject) => {
@@ -9,7 +9,7 @@ module.exports = function build(config) {
9
9
  .source(config.template)
10
10
  .destination(config.path)
11
11
  .metadata(config)
12
- .use(ignore(['.template.js']))
12
+ .use(remove(['.template.js']))
13
13
  .use(
14
14
  // Add the `.hbs` extension to any templating files that need
15
15
  // their placeholders to get filled with `metalsmith-in-place`
@@ -1,4 +1,5 @@
1
1
  const util = require('util');
2
+
2
3
  const exec = util.promisify(require('child_process').exec);
3
4
  const chalk = require('chalk');
4
5
 
@@ -1,4 +1,5 @@
1
1
  const { execSync } = require('child_process');
2
+
2
3
  const chalk = require('chalk');
3
4
 
4
5
  module.exports = function install(config) {
@@ -1,4 +1,5 @@
1
1
  const { execSync } = require('child_process');
2
+
2
3
  const chalk = require('chalk');
3
4
 
4
5
  module.exports = function setup(config) {
@@ -1,6 +1,8 @@
1
- const process = require('process');
2
1
  const { execSync } = require('child_process');
2
+ const process = require('process');
3
+
3
4
  const chalk = require('chalk');
5
+
4
6
  const { isYarnAvailable } = require('../../utils');
5
7
 
6
8
  module.exports = function install(config) {
@@ -1,6 +1,8 @@
1
- const path = require('path');
2
1
  const { execSync } = require('child_process');
2
+ const path = require('path');
3
+
3
4
  const chalk = require('chalk');
5
+
4
6
  const { isYarnAvailable } = require('../../utils');
5
7
 
6
8
  module.exports = function teardown(config) {
@@ -7,6 +7,7 @@ module.exports = {
7
7
  supportedVersion: '>= 3.0.0 < 5.0.0',
8
8
  flags: {
9
9
  dynamicWidgets: '>= 4.30',
10
+ insights: '>= 4.55',
10
11
  },
11
12
  templateName: 'instantsearch.js',
12
13
  appName: 'instantsearch.js-app',
@@ -5,6 +5,7 @@ const searchClient = algoliasearch('{{appId}}', '{{apiKey}}');
5
5
  const search = instantsearch({
6
6
  indexName: '{{indexName}}',
7
7
  searchClient,
8
+ {{#if flags.insights}}insights: true,{{/if}}
8
9
  });
9
10
 
10
11
  search.addWidgets([
@@ -18,12 +19,12 @@ search.addWidgets([
18
19
  container: '#hits',
19
20
  {{#if attributesToDisplay}}
20
21
  templates: {
21
- item: `
22
+ item: (hit, { html, components }) => html`
22
23
  <article>
23
- <h1>\{{#helpers.highlight}}{ "attribute": "{{attributesToDisplay.[0]}}" }\{{/helpers.highlight}}</h1>
24
+ <h1>${components.Highlight({hit, attribute: "{{attributesToDisplay.[0]}}"})}</h1>
24
25
  {{#each attributesToDisplay}}
25
26
  {{#unless @first}}
26
- <p>\{{#helpers.highlight}}{ "attribute": "{{this}}" }\{{/helpers.highlight}}</p>
27
+ <p>${components.Highlight({hit, attribute: "{{this}}"})}</p>
27
28
  {{/unless}}
28
29
  {{/each}}
29
30
  </article>
@@ -38,7 +39,7 @@ search.addWidgets([
38
39
  instantsearch.widgets.dynamicWidgets({
39
40
  container: '#dynamic-widgets',
40
41
  fallbackWidget({ container, attribute }) {
41
- return instantsearch.widgets.panel({ templates: { header: attribute } })(
42
+ return instantsearch.widgets.panel({ templates: { header: () => attribute } })(
42
43
  instantsearch.widgets.refinementList
43
44
  )({
44
45
  container,
@@ -49,7 +50,7 @@ search.addWidgets([
49
50
  {{#each attributesForFaceting}}
50
51
  container =>
51
52
  instantsearch.widgets.panel({
52
- templates: { header: '{{this}}' },
53
+ templates: { header: () => '{{this}}' },
53
54
  })(instantsearch.widgets.refinementList)({
54
55
  container,
55
56
  attribute: '{{this}}',
@@ -60,7 +61,7 @@ search.addWidgets([
60
61
  {{else}}
61
62
  {{#each attributesForFaceting}}
62
63
  instantsearch.widgets.panel({
63
- templates: { header: '{{this}}' },
64
+ templates: { header: () => '{{this}}' },
64
65
  })(instantsearch.widgets.refinementList)({
65
66
  container: '#{{this}}-list',
66
67
  attribute: '{{this}}',
@@ -7,6 +7,7 @@ module.exports = {
7
7
  supportedVersion: '>= 6.0.0 < 7.0.0',
8
8
  flags: {
9
9
  dynamicWidgets: '>=6.16',
10
+ insights: '>=6.43',
10
11
  },
11
12
  templateName: 'react-instantsearch-hooks',
12
13
  appName: 'react-instantsearch-hooks-app',
@@ -8,7 +8,6 @@
8
8
  },
9
9
  "dependencies": {
10
10
  "algoliasearch": "4",
11
- "instantsearch.js": "4.43.1",
12
11
  "react": "18.1.0",
13
12
  "react-dom": "18.1.0",
14
13
  "react-instantsearch-hooks-web": "{{libraryVersion}}"
@@ -47,7 +47,7 @@ export function App() {
47
47
  </header>
48
48
 
49
49
  <div className="container">
50
- <InstantSearch searchClient={searchClient} indexName="{{indexName}}">
50
+ <InstantSearch searchClient={searchClient} indexName="{{indexName}}" {{#if flags.insights}}insights{{/if}}>
51
51
  <Configure hitsPerPage={8} />
52
52
  <div className="search-panel">
53
53
  <div className="search-panel__filters">
@@ -14,7 +14,6 @@
14
14
  "algoliasearch": "4.12.1",
15
15
  "expo": "~44.0.0",
16
16
  "expo-status-bar": "~1.2.0",
17
- "instantsearch.js": "4.38.1",
18
17
  "react": "17.0.1",
19
18
  "react-dom": "17.0.1",
20
19
  "react-instantsearch-hooks": "{{libraryVersion}}",
@@ -6,7 +6,8 @@ module.exports = {
6
6
  libraryName: 'vue-instantsearch',
7
7
  supportedVersion: '>= 3.0.0 < 5.0.0',
8
8
  flags: {
9
- dynamicWidgets: '>=4.2.0',
9
+ dynamicWidgets: '>= 4.2.0',
10
+ insights: '>= 4.9.0',
10
11
  },
11
12
  templateName: 'vue-instantsearch',
12
13
  appName: 'vue-instantsearch-app',
@@ -18,6 +18,7 @@
18
18
  <ais-instant-search
19
19
  :search-client="searchClient"
20
20
  index-name="{{indexName}}"
21
+ {{#if flags.insights}}insights{{/if}}
21
22
  >
22
23
  <ais-configure :hits-per-page.camel="8" />
23
24
  <div class="search-panel">
@@ -6,7 +6,8 @@ module.exports = {
6
6
  libraryName: 'vue-instantsearch',
7
7
  supportedVersion: '>= 4.3.3 < 5.0.0',
8
8
  flags: {
9
- dynamicWidgets: '>=4.2.0',
9
+ dynamicWidgets: '>= 4.2.0',
10
+ insights: '>= 4.9.0',
10
11
  },
11
12
  templateName: 'vue-instantsearch-vue3',
12
13
  appName: 'vue-instantsearch-app',
@@ -16,6 +16,7 @@
16
16
  <ais-instant-search
17
17
  :search-client="searchClient"
18
18
  index-name="{{indexName}}"
19
+ {{#if flags.insights}}insights{{/if}}
19
20
  >
20
21
  <ais-configure :hits-per-page.camel="8" />
21
22
  <div class="search-panel">
@@ -1,10 +1,11 @@
1
+ const { execSync } = require('child_process');
1
2
  const fs = require('fs');
2
3
  const path = require('path');
3
- const { execSync } = require('child_process');
4
+
5
+ const algoliasearch = require('algoliasearch');
4
6
  const chalk = require('chalk');
5
7
  const semver = require('semver');
6
8
  const validateProjectName = require('validate-npm-package-name');
7
- const algoliasearch = require('algoliasearch');
8
9
 
9
10
  const TEMPLATES_FOLDER = path.join(__dirname, '../templates');
10
11