@loopback/cli 4.1.8 → 4.2.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/.yo-rc.json CHANGED
@@ -1278,6 +1278,12 @@
1278
1278
  "name": "outDir",
1279
1279
  "hide": false
1280
1280
  },
1281
+ "models": {
1282
+ "type": "String",
1283
+ "description": "Discover specific models without prompting users to select e.g:--models=table1,table2",
1284
+ "name": "models",
1285
+ "hide": false
1286
+ },
1281
1287
  "optionalId": {
1282
1288
  "type": "Boolean",
1283
1289
  "description": "Boolean to mark id property as optional field",
@@ -7,8 +7,7 @@
7
7
 
8
8
  const fse = require('fs-extra');
9
9
  const _ = require('lodash');
10
- const {promisify} = require('util');
11
- const glob = promisify(require('glob'));
10
+ const {glob} = require('glob');
12
11
 
13
12
  const defaultFS = {
14
13
  write: fse.writeFile,
@@ -38,7 +37,7 @@ async function jsOrTsFiles(cwd, paths = []) {
38
37
  });
39
38
  }
40
39
  paths = await Promise.all(globs);
41
- paths = _.flatten(paths);
40
+ paths = _.map(_.flatten(paths), pathString => pathString.replace(/\\/g, '/'));
42
41
  return _.filter(paths, /\.(js|ts)$/);
43
42
  }
44
43
 
@@ -57,6 +57,14 @@ module.exports = class DiscoveryGenerator extends ArtifactGenerator {
57
57
  default: undefined,
58
58
  });
59
59
 
60
+ this.option('models', {
61
+ type: String,
62
+ description: g.f(
63
+ 'Discover specific models without prompting users to select e.g:--models=table1,table2',
64
+ ),
65
+ default: undefined,
66
+ });
67
+
60
68
  this.option('optionalId', {
61
69
  type: Boolean,
62
70
  description: g.f('Boolean to mark id property as optional field'),
@@ -124,7 +132,6 @@ module.exports = class DiscoveryGenerator extends ArtifactGenerator {
124
132
  path.resolve(dsDir, `${utils.toFileName(s)}.datasource.js`),
125
133
  ),
126
134
  );
127
-
128
135
  if (this.options.dataSource) {
129
136
  if (
130
137
  this.dataSourceChoices
@@ -201,6 +208,16 @@ module.exports = class DiscoveryGenerator extends ArtifactGenerator {
201
208
  this.discoveringModels = this.modelChoices;
202
209
  }
203
210
 
211
+ if (this.options.models) {
212
+ const answers = {discoveringModels: this.options.models.split(',')};
213
+ debug(`Models specified: ${JSON.stringify(answers)}`);
214
+ this.discoveringModels = [];
215
+ answers.discoveringModels.forEach(m => {
216
+ this.discoveringModels.push(this.modelChoices.find(c => c.name === m));
217
+ });
218
+ return;
219
+ }
220
+
204
221
  const prompts = [
205
222
  {
206
223
  name: 'discoveringModels',
@@ -291,6 +308,11 @@ module.exports = class DiscoveryGenerator extends ArtifactGenerator {
291
308
  // eslint-disable-next-line @typescript-eslint/prefer-for-of
292
309
  for (let i = 0; i < this.discoveringModels.length; i++) {
293
310
  const modelInfo = this.discoveringModels[i];
311
+ // passing connector specific options from the cli through connectorDiscoveryOptions
312
+ let discoveryOptions = {};
313
+ if (this.options.connectorDiscoveryOptions) {
314
+ discoveryOptions = JSON.parse(this.options.connectorDiscoveryOptions);
315
+ }
294
316
  debug(`Discovering: ${modelInfo.name}...`);
295
317
  const modelDefinition = await modelMaker.discoverSingleModel(
296
318
  this.artifactInfo.dataSource,
@@ -299,6 +321,7 @@ module.exports = class DiscoveryGenerator extends ArtifactGenerator {
299
321
  schema: modelInfo.owner,
300
322
  disableCamelCase: this.artifactInfo.disableCamelCase,
301
323
  associations: this.options.relations,
324
+ ...discoveryOptions,
302
325
  },
303
326
  );
304
327
  if (this.options.optionalId) {
@@ -38,6 +38,8 @@ function createPropertyTemplateData(val) {
38
38
  }
39
39
  } else if (val.type === 'buffer') {
40
40
  val.tsType = 'Buffer';
41
+ } else if (val.type === 'Binary') {
42
+ val.tsType = 'Buffer';
41
43
  }
42
44
 
43
45
  if (NON_TS_TYPES.includes(val.tsType)) {
@@ -77,6 +77,7 @@ module.exports = class BaseRelationGenerator extends ArtifactGenerator {
77
77
  const imports = this._getRepositoryRequiredImports(
78
78
  options.destinationModel,
79
79
  this.artifactInfo.dstRepositoryClassName,
80
+ options.sourceModel,
80
81
  );
81
82
 
82
83
  relationUtils.addRequiredImports(
@@ -187,8 +188,12 @@ module.exports = class BaseRelationGenerator extends ArtifactGenerator {
187
188
  this.artifactInfo.relationName = options.relationName;
188
189
  }
189
190
 
190
- _getRepositoryRequiredImports(dstModelClassName, dstRepositoryClassName) {
191
- return [
191
+ _getRepositoryRequiredImports(
192
+ dstModelClassName,
193
+ dstRepositoryClassName,
194
+ srcModelClass,
195
+ ) {
196
+ const imports = [
192
197
  {
193
198
  name: dstModelClassName,
194
199
  module: '../models',
@@ -201,11 +206,14 @@ module.exports = class BaseRelationGenerator extends ArtifactGenerator {
201
206
  name: 'Getter',
202
207
  module: '@loopback/core',
203
208
  },
204
- {
209
+ ];
210
+ if (dstModelClassName !== srcModelClass) {
211
+ imports.push({
205
212
  name: dstRepositoryClassName,
206
213
  module: `./${utils.toFileName(dstModelClassName)}.repository`,
207
- },
208
- ];
214
+ });
215
+ }
216
+ return imports;
209
217
  }
210
218
 
211
219
  _getRepositoryRelationPropertyName() {
@@ -106,7 +106,11 @@ module.exports = class BelongsToRelationGenerator extends (
106
106
  );
107
107
 
108
108
  relationUtils.addProperty(sourceClass, modelProperty);
109
- const imports = relationUtils.getRequiredImports(targetModel, relationType);
109
+ const imports = relationUtils.getRequiredImports(
110
+ targetModel,
111
+ relationType,
112
+ sourceModel,
113
+ );
110
114
  relationUtils.addRequiredImports(sourceFile, imports);
111
115
 
112
116
  sourceClass.formatText();
@@ -147,6 +151,7 @@ module.exports = class BelongsToRelationGenerator extends (
147
151
  const importsArray = super._getRepositoryRequiredImports(
148
152
  dstModelClassName,
149
153
  dstRepositoryClassName,
154
+ this.artifactInfo.srcModelClass,
150
155
  );
151
156
  importsArray.push({
152
157
  name: 'BelongsToAccessor',
@@ -6,8 +6,8 @@ import {
6
6
  get,
7
7
  getModelSchemaRef,
8
8
  } from '@loopback/rest';
9
- import {
10
- <%= sourceModelClassName %>,
9
+ import {<%if (sourceModelClassName != targetModelClassName) { %>
10
+ <%= sourceModelClassName %>,<% } %>
11
11
  <%= targetModelClassName %>,
12
12
  } from '../models';
13
13
  import {<%= sourceRepositoryClassName %>} from '../repositories';
@@ -24,7 +24,7 @@ export class <%= controllerClassName %> {
24
24
  description: '<%= targetModelClassName %> belonging to <%= sourceModelClassName %>',
25
25
  content: {
26
26
  'application/json': {
27
- schema: {type: 'array', items: getModelSchemaRef(<%= targetModelClassName %>)},
27
+ schema: getModelSchemaRef(<%= targetModelClassName %>),
28
28
  },
29
29
  },
30
30
  },
@@ -209,17 +209,20 @@ exports.addRequiredImports = function (sourceFile, imports) {
209
209
  }
210
210
  };
211
211
 
212
- exports.getRequiredImports = function (targetModel, relationType) {
213
- return [
214
- {
215
- name: targetModel,
216
- module: './' + utils.toFileName(targetModel) + '.model',
217
- },
212
+ exports.getRequiredImports = function (targetModel, relationType, sourceModel) {
213
+ const requiredImports = [
218
214
  {
219
215
  name: relationType,
220
216
  module: '@loopback/repository',
221
217
  },
222
218
  ];
219
+ if (sourceModel !== targetModel) {
220
+ requiredImports.push({
221
+ name: targetModel,
222
+ module: './' + utils.toFileName(targetModel) + '.model',
223
+ });
224
+ }
225
+ return requiredImports;
223
226
  };
224
227
 
225
228
  exports.addCurrentImport = function (sourceFile, currentImport) {
@@ -424,7 +424,9 @@ module.exports = class RepositoryGenerator extends ArtifactGenerator {
424
424
  name: 'repositoryBaseClass',
425
425
  message: PROMPT_BASE_REPOSITORY_CLASS,
426
426
  choices: availableRepositoryList,
427
- when: this.artifactInfo.repositoryBaseClass === undefined,
427
+ when:
428
+ this.artifactInfo.repositoryBaseClass === undefined ||
429
+ availableRepositoryList.length > 2,
428
430
  default:
429
431
  this.artifactInfo.repositoryBaseClass === undefined
430
432
  ? availableRepositoryList[0]
@@ -8,8 +8,9 @@ import {<%= modelName %>} from '../models';
8
8
  import {<%=repositoryBaseClass %>} from './<%=repositoryBaseFile %>';
9
9
  <% } -%>
10
10
 
11
- export class <%= className %>Repository extends <%= repositoryBaseClass %><
12
- <%= modelName %>
11
+ <% if (isRepositoryBaseBuiltin) { %>export class <%= className %>Repository extends <%= repositoryTypeClass %><
12
+ <%} else { %>export class <%= className %>Repository extends <%= repositoryBaseClass %><
13
+ <% } %><%= modelName %>
13
14
  > {
14
15
  constructor(
15
16
  @inject('datasources.<%= dataSourceName %>') dataSource: <%= dataSourceClassName %>,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@loopback/cli",
3
3
  "description": "Yeoman generator for LoopBack 4",
4
- "version": "4.1.8",
4
+ "version": "4.2.1",
5
5
  "keywords": [
6
6
  "LoopBack",
7
7
  "CLI",
@@ -40,26 +40,26 @@
40
40
  ],
41
41
  "dependencies": {
42
42
  "@lerna/project": "^6.4.1",
43
- "@openapi-contrib/openapi-schema-to-json-schema": "^3.2.0",
44
- "@phenomnomnominal/tsquery": "^5.0.0",
43
+ "@openapi-contrib/openapi-schema-to-json-schema": "^3.3.2",
44
+ "@phenomnomnominal/tsquery": "^5.0.1",
45
45
  "camelcase-keys": "^7.0.2",
46
46
  "chalk": "^4.1.2",
47
47
  "change-case": "^4.1.2",
48
48
  "debug": "^4.3.4",
49
- "fs-extra": "^10.1.0",
50
- "glob": "^8.1.0",
49
+ "fs-extra": "^11.1.1",
50
+ "glob": "^10.0.0",
51
51
  "inquirer-autocomplete-prompt": "^2.0.0",
52
52
  "json5": "^2.2.3",
53
53
  "latest-version": "^5.1.0",
54
54
  "lodash": "^4.17.21",
55
- "minimatch": "^6.1.6",
56
- "minimist": "^1.2.7",
57
- "mkdirp": "^2.1.3",
55
+ "minimatch": "^9.0.0",
56
+ "minimist": "^1.2.8",
57
+ "mkdirp": "^3.0.0",
58
58
  "natural-compare": "^1.4.0",
59
- "pacote": "^15.0.8",
59
+ "pacote": "^15.1.1",
60
60
  "pluralize": "^8.0.0",
61
61
  "regenerate": "^1.4.2",
62
- "semver": "^7.3.8",
62
+ "semver": "^7.4.0",
63
63
  "slash": "^3.0.0",
64
64
  "spdx-license-list": "^6.6.0",
65
65
  "stringify-object": "^3.3.0",
@@ -70,33 +70,34 @@
70
70
  "terminal-link": "^2.1.1",
71
71
  "tildify": "^2.0.0",
72
72
  "ts-morph": "^17.0.1",
73
- "typescript": "~4.9.4",
73
+ "typescript": "~4.9.5",
74
74
  "unicode-10.0.0": "^0.7.5",
75
75
  "untildify": "^4.0.0",
76
76
  "update-notifier": "^5.1.0",
77
77
  "url-slug": "^3.0.4",
78
78
  "validate-npm-package-name": "^5.0.0",
79
79
  "write-file-atomic": "^5.0.0",
80
- "yeoman-environment": "^3.13.0",
81
- "yeoman-generator": "^5.7.0"
80
+ "yeoman-environment": "^3.15.1",
81
+ "yeoman-generator": "^5.8.0"
82
82
  },
83
83
  "devDependencies": {
84
- "@loopback/build": "^9.0.8",
85
- "@loopback/eslint-config": "^13.0.8",
86
- "@loopback/testlab": "^5.0.8",
87
- "@types/ejs": "^3.1.1",
88
- "@types/fs-extra": "^9.0.13",
84
+ "@lerna/bootstrap": "6.5.1",
85
+ "@loopback/build": "^9.0.10",
86
+ "@loopback/eslint-config": "^13.0.10",
87
+ "@loopback/testlab": "^5.0.10",
88
+ "@types/ejs": "^3.1.2",
89
+ "@types/fs-extra": "^11.0.1",
89
90
  "@types/minimatch": "^5.1.2",
90
- "@types/node": "^14.18.36",
91
+ "@types/node": "^14.18.42",
91
92
  "@types/yeoman-environment": "^2.10.8",
92
93
  "@types/yeoman-generator": "^5.2.11",
93
94
  "loopback": "^3.28.0",
94
- "loopback-datasource-juggler": "^4.28.2",
95
- "mem-fs": "^2.2.1",
96
- "mem-fs-editor": "^9.6.0",
95
+ "loopback-datasource-juggler": "^4.28.3",
96
+ "mem-fs": "^2.3.0",
97
+ "mem-fs-editor": "^9.7.0",
97
98
  "mock-stdin": "^1.0.0",
98
- "rimraf": "^3.0.2",
99
- "sinon": "^15.0.1",
99
+ "rimraf": "^5.0.0",
100
+ "sinon": "^15.0.3",
100
101
  "strong-globalize-cli": "7.1.0",
101
102
  "yeoman-assert": "^3.1.1",
102
103
  "yeoman-test": "^6.3.0"
@@ -105,96 +106,97 @@
105
106
  "templateDependencies": {
106
107
  "tslib": "^2.0.0",
107
108
  "@types/mocha": "^10.0.1",
108
- "@types/node": "^14.18.36",
109
+ "@types/node": "^14.18.42",
109
110
  "cross-spawn": "^7.0.3",
110
111
  "debug": "^4.3.4",
111
- "fs-extra": "^10.1.0",
112
+ "fs-extra": "^11.1.1",
112
113
  "mocha": "^10.2.0",
113
114
  "nyc": "^15.1.0",
114
- "prettier": "^2.8.3",
115
- "rimraf": "^3.0.2",
115
+ "prettier": "^2.8.7",
116
+ "rimraf": "^5.0.0",
116
117
  "source-map-support": "^0.5.21",
117
- "typescript": "~4.9.4",
118
- "@loopback/authentication": "^9.0.8",
119
- "@loopback/boot": "^5.0.8",
120
- "@loopback/build": "^9.0.8",
121
- "@loopback/cli": "^4.1.8",
122
- "@loopback/context": "^5.0.8",
123
- "@loopback/core": "^4.0.8",
124
- "@loopback/metadata": "^5.0.8",
125
- "@loopback/openapi-spec-builder": "^5.0.8",
126
- "@loopback/openapi-v3": "^8.0.8",
127
- "@loopback/repository-json-schema": "^6.1.2",
128
- "@loopback/repository": "^5.1.3",
129
- "@loopback/rest": "^12.0.8",
130
- "@loopback/testlab": "^5.0.8",
131
- "@loopback/docs": "^5.1.7",
132
- "glob": "^8.1.0",
133
- "@loopback/example-hello-world": "^5.0.8",
134
- "@loopback/example-log-extension": "^5.0.8",
135
- "@loopback/example-rpc-server": "^5.0.8",
136
- "@loopback/example-todo": "^6.0.8",
137
- "@loopback/example-soap-calculator": "^5.0.8",
138
- "@loopback/service-proxy": "^5.0.8",
139
- "@loopback/http-caching-proxy": "^4.0.8",
140
- "@loopback/http-server": "^4.0.8",
141
- "@loopback/example-todo-list": "^6.0.8",
118
+ "typescript": "~4.9.5",
119
+ "@loopback/authentication": "^9.0.10",
120
+ "@loopback/boot": "^5.0.10",
121
+ "@loopback/build": "^9.0.10",
122
+ "@loopback/cli": "^4.2.1",
123
+ "@loopback/context": "^5.0.10",
124
+ "@loopback/core": "^4.0.10",
125
+ "@loopback/metadata": "^5.0.10",
126
+ "@loopback/openapi-spec-builder": "^5.0.10",
127
+ "@loopback/openapi-v3": "^8.0.10",
128
+ "@loopback/repository-json-schema": "^6.1.4",
129
+ "@loopback/repository": "^5.1.5",
130
+ "@loopback/rest": "^12.0.10",
131
+ "@loopback/testlab": "^5.0.10",
132
+ "@loopback/docs": "^5.2.1",
133
+ "glob": "^10.0.0",
134
+ "@loopback/example-hello-world": "^5.0.10",
135
+ "@loopback/example-log-extension": "^5.0.10",
136
+ "@loopback/example-rpc-server": "^5.0.10",
137
+ "@loopback/example-todo": "^6.0.10",
138
+ "@loopback/example-soap-calculator": "^5.0.10",
139
+ "@loopback/service-proxy": "^5.0.10",
140
+ "@loopback/http-caching-proxy": "^4.0.10",
141
+ "@loopback/http-server": "^4.0.10",
142
+ "@loopback/example-todo-list": "^6.0.10",
142
143
  "@loopback/dist-util": "^0.4.0",
143
- "@loopback/rest-explorer": "^5.0.8",
144
- "@loopback/eslint-config": "^13.0.8",
144
+ "@loopback/rest-explorer": "^5.0.10",
145
+ "@loopback/eslint-config": "^13.0.10",
145
146
  "express-composition": "^1.1.0",
146
- "@loopback/example-express-composition": "^5.0.8",
147
- "@loopback/example-greeter-extension": "^5.0.8",
148
- "@loopback/booter-lb3app": "^4.0.8",
149
- "@loopback/example-lb3-application": "^5.0.8",
150
- "eslint": "^8.33.0",
147
+ "@loopback/example-express-composition": "^5.0.10",
148
+ "@loopback/example-greeter-extension": "^5.0.10",
149
+ "@loopback/booter-lb3app": "^4.0.10",
150
+ "@loopback/example-lb3-application": "^5.0.10",
151
+ "eslint": "^8.38.0",
151
152
  "eslint-plugin-mocha": "^10.1.0",
152
- "@loopback/example-greeting-app": "^5.0.8",
153
- "@loopback/example-context": "^5.0.8",
154
- "@typescript-eslint/eslint-plugin": "^5.51.0",
155
- "@typescript-eslint/parser": "^5.51.0",
153
+ "@loopback/example-greeting-app": "^5.0.10",
154
+ "@loopback/example-context": "^5.0.10",
155
+ "@typescript-eslint/eslint-plugin": "^5.58.0",
156
+ "@typescript-eslint/parser": "^5.58.0",
156
157
  "eslint-plugin-eslint-plugin": "^5.0.8",
157
- "eslint-config-prettier": "^8.6.0",
158
- "@loopback/repository-tests": "^0.21.8",
159
- "@loopback/health": "^0.11.8",
160
- "@loopback/authorization": "^0.12.8",
161
- "@loopback/rest-crud": "^0.15.7",
162
- "@loopback/security": "^0.8.8",
163
- "@loopback/authentication-passport": "^5.0.8",
164
- "@loopback/example-metrics-prometheus": "^0.10.8",
165
- "@loopback/metrics": "^0.11.8",
166
- "@loopback/model-api-builder": "^4.0.8",
167
- "@loopback/logging": "^0.9.8",
168
- "@loopback/example-access-control-migration": "^5.0.8",
169
- "@loopback/example-file-transfer": "^4.0.8",
170
- "@loopback/example-rest-crud": "^4.0.8",
171
- "@loopback/apiconnect": "^0.10.8",
172
- "@loopback/example-validation-app": "^4.0.8",
173
- "@loopback/cron": "^0.9.8",
174
- "@loopback/example-multi-tenancy": "^0.13.8",
175
- "@loopback/example-passport-login": "^4.0.8",
176
- "@loopback/authentication-jwt": "^0.12.8",
177
- "@loopback/context-explorer": "^0.8.8",
178
- "@loopback/express": "^5.0.8",
158
+ "eslint-config-prettier": "^8.8.0",
159
+ "@loopback/repository-tests": "^0.21.10",
160
+ "@loopback/health": "^0.11.10",
161
+ "@loopback/authorization": "^0.12.10",
162
+ "@loopback/rest-crud": "^0.15.9",
163
+ "@loopback/security": "^0.8.10",
164
+ "@loopback/authentication-passport": "^5.0.10",
165
+ "@loopback/example-metrics-prometheus": "^0.10.10",
166
+ "@loopback/metrics": "^0.11.10",
167
+ "@loopback/model-api-builder": "^4.0.10",
168
+ "@loopback/logging": "^0.9.10",
169
+ "@loopback/example-access-control-migration": "^5.0.10",
170
+ "@loopback/example-file-transfer": "^4.0.10",
171
+ "@loopback/example-rest-crud": "^4.0.10",
172
+ "@loopback/apiconnect": "^0.10.10",
173
+ "@loopback/example-validation-app": "^4.0.10",
174
+ "@loopback/cron": "^0.9.10",
175
+ "@loopback/example-multi-tenancy": "^0.13.10",
176
+ "@loopback/example-passport-login": "^4.0.10",
177
+ "@loopback/authentication-jwt": "^0.12.10",
178
+ "@loopback/context-explorer": "^0.8.10",
179
+ "@loopback/express": "^5.0.10",
179
180
  "@types/js-yaml": "^3.12.4",
180
181
  "js-yaml": "^3.13.1",
181
- "@loopback/example-todo-jwt": "^4.0.8",
182
- "@loopback/mock-oauth2-provider": "^0.6.8",
182
+ "@loopback/example-todo-jwt": "^4.0.10",
183
+ "@loopback/mock-oauth2-provider": "^0.6.10",
183
184
  "lodash": "^4.17.21",
184
- "@loopback/pooling": "^0.8.8",
185
- "@loopback/typeorm": "^0.7.8",
186
- "@loopback/example-graphql": "^0.7.8",
187
- "@loopback/graphql": "^0.8.8",
188
- "@loopback/filter": "^3.0.8",
189
- "@loopback/rest-msgpack": "^0.8.8",
190
- "@loopback/example-binding-resolution": "^0.7.8",
191
- "@loopback/example-webpack": "^0.8.8",
192
- "@loopback/example-socketio": "^0.6.8",
193
- "@loopback/socketio": "^0.6.8",
194
- "@loopback/monorepo": "^0.5.8",
195
- "@loopback/tsdocs": "^4.0.8",
196
- "@loopback/example-references-many": "^6.0.8"
185
+ "@loopback/pooling": "^0.8.10",
186
+ "@loopback/typeorm": "^0.7.10",
187
+ "@loopback/example-graphql": "^0.7.10",
188
+ "@loopback/graphql": "^0.8.10",
189
+ "@loopback/filter": "^3.0.10",
190
+ "@loopback/rest-msgpack": "^0.8.10",
191
+ "@loopback/example-binding-resolution": "^0.7.10",
192
+ "@loopback/example-webpack": "^0.8.10",
193
+ "@loopback/example-socketio": "^0.6.10",
194
+ "@loopback/socketio": "^0.6.10",
195
+ "@loopback/monorepo": "^0.5.10",
196
+ "@loopback/tsdocs": "^4.0.10",
197
+ "@loopback/example-references-many": "^6.0.10",
198
+ "@loopback/sequelize": "^0.2.0"
197
199
  }
198
200
  },
199
- "gitHead": "3025b353fa04f6918cd7b435ae7c5864ba2eb9f9"
201
+ "gitHead": "3a98ded2622420d0f09dbc3c0fe961c0234b097f"
200
202
  }