swagger-typescript-api 13.0.8 → 13.0.10

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.
Files changed (67) hide show
  1. package/README.md +1 -1
  2. package/cli/index.d.ts +7 -6
  3. package/dist/chunk-3S356DIU.cjs +105 -0
  4. package/dist/chunk-3S356DIU.cjs.map +1 -0
  5. package/dist/chunk-MTWJNW6B.js +65 -0
  6. package/dist/chunk-MTWJNW6B.js.map +1 -0
  7. package/dist/cli.cjs +43 -0
  8. package/dist/cli.cjs.map +1 -0
  9. package/dist/cli.js +36 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/lib.cjs +21 -0
  12. package/dist/lib.cjs.map +1 -0
  13. package/dist/lib.js +4 -0
  14. package/dist/lib.js.map +1 -0
  15. package/package.json +30 -16
  16. package/cli/constants.js +0 -10
  17. package/cli/execute.js +0 -182
  18. package/cli/index.js +0 -96
  19. package/cli/operations/display-help.js +0 -179
  20. package/cli/operations/display-version.js +0 -5
  21. package/cli/parse-args.js +0 -26
  22. package/cli/process-option.js +0 -77
  23. package/index.js +0 -349
  24. package/src/code-formatter.js +0 -116
  25. package/src/code-gen-process.js +0 -571
  26. package/src/commands/generate-templates/configuration.js +0 -33
  27. package/src/commands/generate-templates/index.js +0 -16
  28. package/src/commands/generate-templates/templates-gen-process.js +0 -204
  29. package/src/component-type-name-resolver.js +0 -44
  30. package/src/configuration.js +0 -448
  31. package/src/constants.js +0 -65
  32. package/src/index.js +0 -26
  33. package/src/schema-components-map.js +0 -78
  34. package/src/schema-parser/base-schema-parsers/array.js +0 -43
  35. package/src/schema-parser/base-schema-parsers/complex.js +0 -51
  36. package/src/schema-parser/base-schema-parsers/discriminator.js +0 -307
  37. package/src/schema-parser/base-schema-parsers/enum.js +0 -158
  38. package/src/schema-parser/base-schema-parsers/object.js +0 -105
  39. package/src/schema-parser/base-schema-parsers/primitive.js +0 -63
  40. package/src/schema-parser/complex-schema-parsers/all-of.js +0 -26
  41. package/src/schema-parser/complex-schema-parsers/any-of.js +0 -27
  42. package/src/schema-parser/complex-schema-parsers/not.js +0 -9
  43. package/src/schema-parser/complex-schema-parsers/one-of.js +0 -27
  44. package/src/schema-parser/mono-schema-parser.js +0 -48
  45. package/src/schema-parser/schema-formatters.js +0 -166
  46. package/src/schema-parser/schema-parser-fabric.js +0 -132
  47. package/src/schema-parser/schema-parser.js +0 -300
  48. package/src/schema-parser/schema-utils.js +0 -322
  49. package/src/schema-parser/util/enum-key-resolver.js +0 -26
  50. package/src/schema-routes/schema-routes.js +0 -1213
  51. package/src/schema-routes/util/specific-arg-name-resolver.js +0 -26
  52. package/src/schema-walker.js +0 -93
  53. package/src/swagger-schema-resolver.js +0 -197
  54. package/src/templates-worker.js +0 -243
  55. package/src/translators/javascript.js +0 -83
  56. package/src/translators/translator.js +0 -35
  57. package/src/type-name-formatter.js +0 -113
  58. package/src/util/file-system.js +0 -95
  59. package/src/util/id.js +0 -9
  60. package/src/util/internal-case.js +0 -5
  61. package/src/util/logger.js +0 -144
  62. package/src/util/name-resolver.js +0 -105
  63. package/src/util/object-assign.js +0 -19
  64. package/src/util/pascal-case.js +0 -5
  65. package/src/util/random.js +0 -14
  66. package/src/util/request.js +0 -65
  67. package/src/util/sort-by-property.js +0 -17
@@ -1,571 +0,0 @@
1
- const { SwaggerSchemaResolver } = require("./swagger-schema-resolver.js");
2
- const { SchemaComponentsMap } = require("./schema-components-map.js");
3
- const { NameResolver } = require("./util/name-resolver");
4
- const { Logger } = require("./util/logger.js");
5
- const { TypeNameFormatter } = require("./type-name-formatter.js");
6
- const _ = require("lodash");
7
- const { SchemaParserFabric } = require("./schema-parser/schema-parser-fabric");
8
- const { SchemaRoutes } = require("./schema-routes/schema-routes.js");
9
- const { CodeGenConfig } = require("./configuration.js");
10
- const { SchemaWalker } = require("./schema-walker");
11
- const { FileSystem } = require("./util/file-system");
12
- const { TemplatesWorker } = require("./templates-worker");
13
- const { JavascriptTranslator } = require("./translators/javascript");
14
- const ts = require("typescript");
15
- const { CodeFormatter } = require("./code-formatter");
16
- const { pascalCase } = require("./util/pascal-case");
17
- const { internalCase } = require("./util/internal-case");
18
- const { sortByProperty } = require("./util/sort-by-property");
19
-
20
- const PATCHABLE_INSTANCES = [
21
- "schemaWalker",
22
- "swaggerSchemaResolver",
23
- "schemaComponentsMap",
24
- "typeNameFormatter",
25
- "templatesWorker",
26
- "codeFormatter",
27
- "schemaParserFabric",
28
- "schemaRoutes",
29
- "javascriptTranslator",
30
- ];
31
-
32
- class CodeGenProcess {
33
- /** @type {CodeGenConfig} */
34
- config;
35
- /** @type {SwaggerSchemaResolver} */
36
- swaggerSchemaResolver;
37
- /** @type {SchemaComponentsMap} */
38
- schemaComponentsMap;
39
- /** @type {Logger} */
40
- logger;
41
- /** @type {TypeNameFormatter} */
42
- typeNameFormatter;
43
- /** @type {SchemaParserFabric} */
44
- schemaParserFabric;
45
- /** @type {SchemaRoutes} */
46
- schemaRoutes;
47
- /** @type {FileSystem} */
48
- fileSystem;
49
- /** @type {CodeFormatter} */
50
- codeFormatter;
51
- /** type {TemplatesWorker} */
52
- templatesWorker;
53
- /** @type {SchemaWalker} */
54
- schemaWalker;
55
- /** @type {JavascriptTranslator} */
56
- javascriptTranslator;
57
-
58
- /**
59
- *
60
- * @param config {Partial<import("../index.d.ts").GenerateApiConfiguration['config']>}
61
- */
62
- constructor(config) {
63
- this.config = new CodeGenConfig(config);
64
- this.logger = new Logger(this);
65
- this.fileSystem = new FileSystem(this);
66
- this.schemaWalker = new SchemaWalker(this);
67
- this.swaggerSchemaResolver = new SwaggerSchemaResolver(this);
68
- this.schemaComponentsMap = new SchemaComponentsMap(this);
69
- this.typeNameFormatter = new TypeNameFormatter(this);
70
- this.templatesWorker = new TemplatesWorker(this);
71
- this.codeFormatter = new CodeFormatter(this);
72
- this.schemaParserFabric = new SchemaParserFabric(this);
73
- this.schemaRoutes = new SchemaRoutes(this);
74
- this.javascriptTranslator = new JavascriptTranslator(this);
75
- this.config.componentTypeNameResolver.logger = this.logger;
76
- }
77
-
78
- async start() {
79
- this.config.update({
80
- templatePaths: this.templatesWorker.getTemplatePaths(this.config),
81
- });
82
- this.config.update({
83
- templatesToRender: this.templatesWorker.getTemplates(this.config),
84
- });
85
-
86
- const swagger = await this.swaggerSchemaResolver.create();
87
-
88
- this.swaggerSchemaResolver.fixSwaggerSchema(swagger);
89
-
90
- this.config.update({
91
- swaggerSchema: swagger.usageSchema,
92
- originalSchema: swagger.originalSchema,
93
- });
94
-
95
- this.schemaWalker.addSchema("$usage", swagger.usageSchema);
96
- this.schemaWalker.addSchema("$original", swagger.originalSchema);
97
-
98
- this.logger.event("start generating your typescript api");
99
-
100
- this.config.update(
101
- this.config.hooks.onInit(this.config, this) || this.config,
102
- );
103
-
104
- this.schemaComponentsMap.clear();
105
-
106
- _.each(swagger.usageSchema.components, (component, componentName) =>
107
- _.each(component, (rawTypeData, typeName) => {
108
- this.schemaComponentsMap.createComponent(
109
- this.schemaComponentsMap.createRef([
110
- "components",
111
- componentName,
112
- typeName,
113
- ]),
114
- rawTypeData,
115
- );
116
- }),
117
- );
118
-
119
- /**
120
- * @type {SchemaComponent[]}
121
- */
122
- const componentsToParse = this.schemaComponentsMap.filter(
123
- _.compact(["schemas", this.config.extractResponses && "responses"]),
124
- );
125
-
126
- const parsedSchemas = componentsToParse.map((schemaComponent) => {
127
- const parsed = this.schemaParserFabric.parseSchema(
128
- schemaComponent.rawTypeData,
129
- schemaComponent.typeName,
130
- );
131
- schemaComponent.typeData = parsed;
132
- return parsed;
133
- });
134
-
135
- this.schemaRoutes.attachSchema({
136
- usageSchema: swagger.usageSchema,
137
- parsedSchemas,
138
- });
139
-
140
- const rawConfiguration = {
141
- apiConfig: this.createApiConfig(swagger.usageSchema),
142
- config: this.config,
143
- modelTypes: this.collectModelTypes(),
144
- hasSecurityRoutes: this.schemaRoutes.hasSecurityRoutes,
145
- hasQueryRoutes: this.schemaRoutes.hasQueryRoutes,
146
- hasFormDataRoutes: this.schemaRoutes.hasFormDataRoutes,
147
- generateResponses: this.config.generateResponses,
148
- routes: this.schemaRoutes.getGroupedRoutes(),
149
- extraTemplates: this.config.extraTemplates,
150
- fileName: this.config.fileName,
151
- translateToJavaScript: this.config.toJS,
152
- customTranslator: this.config.customTranslator
153
- ? new this.config.customTranslator(this)
154
- : null,
155
- utils: this.getRenderTemplateData().utils,
156
- };
157
-
158
- const configuration =
159
- this.config.hooks.onPrepareConfig(rawConfiguration) || rawConfiguration;
160
-
161
- if (this.fileSystem.pathIsExist(this.config.output)) {
162
- if (this.config.cleanOutput) {
163
- this.logger.debug(`cleaning dir ${this.config.output}`);
164
- this.fileSystem.cleanDir(this.config.output);
165
- }
166
- } else {
167
- this.logger.debug(
168
- `path ${this.config.output} is not exist. creating dir by this path`,
169
- );
170
- this.fileSystem.createDir(this.config.output);
171
- }
172
-
173
- const files = await this.generateOutputFiles({
174
- configuration: configuration,
175
- });
176
-
177
- const isDirPath = this.fileSystem.pathIsDir(this.config.output);
178
-
179
- if (isDirPath) {
180
- files.forEach((file) => {
181
- this.fileSystem.createFile({
182
- path: this.config.output,
183
- fileName: `${file.fileName}${file.fileExtension}`,
184
- content: file.fileContent,
185
- withPrefix: true,
186
- });
187
-
188
- this.logger.success(
189
- "api file",
190
- `"${file.fileName}${file.fileExtension}"`,
191
- `created in ${this.config.output}`,
192
- );
193
- });
194
- }
195
-
196
- return {
197
- files,
198
- configuration,
199
- getTemplate: this.templatesWorker.getTemplate,
200
- renderTemplate: this.templatesWorker.renderTemplate,
201
- createFile: this.fileSystem.createFile,
202
- formatTSContent: this.codeFormatter.formatCode,
203
- };
204
- }
205
-
206
- getRenderTemplateData = () => {
207
- return {
208
- utils: {
209
- Ts: this.config.Ts,
210
- formatDescription:
211
- this.schemaParserFabric.schemaFormatters.formatDescription,
212
- internalCase: internalCase,
213
- classNameCase: pascalCase,
214
- pascalCase: pascalCase,
215
- getInlineParseContent: this.schemaParserFabric.getInlineParseContent,
216
- getParseContent: this.schemaParserFabric.getParseContent,
217
- getComponentByRef: this.schemaComponentsMap.get,
218
- parseSchema: this.schemaParserFabric.parseSchema,
219
- checkAndAddNull: this.schemaParserFabric.schemaUtils.safeAddNullToType,
220
- safeAddNullToType:
221
- this.schemaParserFabric.schemaUtils.safeAddNullToType,
222
- isNeedToAddNull:
223
- this.schemaParserFabric.schemaUtils.isNullMissingInType,
224
- inlineExtraFormatters: this.schemaParserFabric.schemaFormatters.inline,
225
- formatters: this.schemaParserFabric.schemaFormatters.base,
226
- formatModelName: this.typeNameFormatter.format,
227
- fmtToJSDocLine: function fmtToJSDocLine(line, { eol = true }) {
228
- return ` * ${line}${eol ? "\n" : ""}`;
229
- },
230
- NameResolver: NameResolver,
231
- _,
232
- require: this.templatesWorker.requireFnFromTemplate,
233
- },
234
- config: this.config,
235
- };
236
- };
237
-
238
- collectModelTypes = () => {
239
- const components = this.schemaComponentsMap.getComponents();
240
- let modelTypes = [];
241
-
242
- const modelTypeComponents = _.compact([
243
- "schemas",
244
- this.config.extractResponses && "responses",
245
- ]);
246
-
247
- const getSchemaComponentsCount = () =>
248
- this.schemaComponentsMap.filter(...modelTypeComponents).length;
249
-
250
- let schemaComponentsCount = getSchemaComponentsCount();
251
- let processedCount = 0;
252
-
253
- while (processedCount < schemaComponentsCount) {
254
- modelTypes = [];
255
- processedCount = 0;
256
- for (const component of components) {
257
- if (modelTypeComponents.includes(component.componentName)) {
258
- const modelType = this.prepareModelType(component);
259
- if (modelType) {
260
- modelTypes.push(modelType);
261
- }
262
- processedCount++;
263
- }
264
- }
265
- schemaComponentsCount = getSchemaComponentsCount();
266
- }
267
-
268
- if (this.config.sortTypes) {
269
- return modelTypes.sort(sortByProperty("name"));
270
- }
271
-
272
- return modelTypes;
273
- };
274
-
275
- prepareModelType = (typeInfo) => {
276
- if (typeInfo.$prepared) return typeInfo.$prepared;
277
-
278
- if (!typeInfo.typeData) {
279
- typeInfo.typeData = this.schemaParserFabric.parseSchema(
280
- typeInfo.rawTypeData,
281
- typeInfo.typeName,
282
- );
283
- }
284
- const rawTypeData = typeInfo.typeData;
285
- const typeData = this.schemaParserFabric.schemaFormatters.base[
286
- rawTypeData.type
287
- ]
288
- ? this.schemaParserFabric.schemaFormatters.base[rawTypeData.type](
289
- rawTypeData,
290
- )
291
- : rawTypeData;
292
- let { typeIdentifier, name: originalName, content, description } = typeData;
293
- const name = this.typeNameFormatter.format(originalName);
294
-
295
- if (name === null) return null;
296
-
297
- const preparedModelType = {
298
- ...typeData,
299
- typeIdentifier,
300
- name,
301
- description,
302
- $content: rawTypeData.content,
303
- rawContent: rawTypeData.content,
304
- content: content,
305
- typeData,
306
- };
307
-
308
- typeInfo.$prepared = preparedModelType;
309
-
310
- return preparedModelType;
311
- };
312
-
313
- /**
314
- *
315
- * @param configuration
316
- * @returns {Promise<TranslatorIO[]>}
317
- */
318
- generateOutputFiles = async ({ configuration }) => {
319
- const { modular, templatesToRender } = this.config;
320
-
321
- const output = modular
322
- ? await this.createMultipleFileInfos(templatesToRender, configuration)
323
- : await this.createSingleFileInfo(templatesToRender, configuration);
324
-
325
- if (!_.isEmpty(configuration.extraTemplates)) {
326
- for (const extraTemplate of configuration.extraTemplates) {
327
- const content = this.templatesWorker.renderTemplate(
328
- this.fileSystem.getFileContent(extraTemplate.path),
329
- configuration,
330
- );
331
- output.push(
332
- ...(await this.createOutputFileInfo(
333
- configuration,
334
- extraTemplate.name,
335
- content,
336
- )),
337
- );
338
- }
339
- }
340
-
341
- return output.filter((fileInfo) => !!fileInfo && !!fileInfo.fileContent);
342
- };
343
-
344
- /**
345
- * @param templatesToRender
346
- * @param configuration
347
- * @returns {Promise<TranslatorIO[]>}
348
- */
349
- createMultipleFileInfos = async (templatesToRender, configuration) => {
350
- const { routes } = configuration;
351
- const { fileNames, generateRouteTypes, generateClient } =
352
- configuration.config;
353
- /**
354
- * @type {TranslatorIO[]}
355
- */
356
- const modularApiFileInfos = [];
357
-
358
- if (routes.$outOfModule) {
359
- if (generateRouteTypes) {
360
- const outOfModuleRouteContent = this.templatesWorker.renderTemplate(
361
- templatesToRender.routeTypes,
362
- {
363
- ...configuration,
364
- route: configuration.routes.$outOfModule,
365
- },
366
- );
367
-
368
- modularApiFileInfos.push(
369
- ...(await this.createOutputFileInfo(
370
- configuration,
371
- fileNames.outOfModuleApi,
372
- outOfModuleRouteContent,
373
- )),
374
- );
375
- }
376
- if (generateClient) {
377
- const outOfModuleApiContent = this.templatesWorker.renderTemplate(
378
- templatesToRender.api,
379
- {
380
- ...configuration,
381
- route: configuration.routes.$outOfModule,
382
- },
383
- );
384
-
385
- modularApiFileInfos.push(
386
- ...(await this.createOutputFileInfo(
387
- configuration,
388
- fileNames.outOfModuleApi,
389
- outOfModuleApiContent,
390
- )),
391
- );
392
- }
393
- }
394
-
395
- if (routes.combined) {
396
- for (const route of routes.combined) {
397
- if (generateRouteTypes) {
398
- const routeModuleContent = this.templatesWorker.renderTemplate(
399
- templatesToRender.routeTypes,
400
- {
401
- ...configuration,
402
- route,
403
- },
404
- );
405
-
406
- modularApiFileInfos.push(
407
- ...(await this.createOutputFileInfo(
408
- configuration,
409
- pascalCase(`${route.moduleName}_Route`),
410
- routeModuleContent,
411
- )),
412
- );
413
- }
414
-
415
- if (generateClient) {
416
- const apiModuleContent = this.templatesWorker.renderTemplate(
417
- templatesToRender.api,
418
- {
419
- ...configuration,
420
- route,
421
- },
422
- );
423
-
424
- modularApiFileInfos.push(
425
- ...(await this.createOutputFileInfo(
426
- configuration,
427
- pascalCase(route.moduleName),
428
- apiModuleContent,
429
- )),
430
- );
431
- }
432
- }
433
- }
434
-
435
- return [
436
- ...(await this.createOutputFileInfo(
437
- configuration,
438
- fileNames.dataContracts,
439
- this.templatesWorker.renderTemplate(
440
- templatesToRender.dataContracts,
441
- configuration,
442
- ),
443
- )),
444
- ...(generateClient
445
- ? await this.createOutputFileInfo(
446
- configuration,
447
- fileNames.httpClient,
448
- this.templatesWorker.renderTemplate(
449
- templatesToRender.httpClient,
450
- configuration,
451
- ),
452
- )
453
- : []),
454
- ...modularApiFileInfos,
455
- ];
456
- };
457
-
458
- /**
459
- *
460
- * @param templatesToRender
461
- * @param configuration
462
- * @returns {Promise<TranslatorIO[]>}
463
- */
464
- createSingleFileInfo = async (templatesToRender, configuration) => {
465
- const { generateRouteTypes, generateClient } = configuration.config;
466
-
467
- return await this.createOutputFileInfo(
468
- configuration,
469
- configuration.fileName,
470
- _.compact([
471
- this.templatesWorker.renderTemplate(
472
- templatesToRender.dataContracts,
473
- configuration,
474
- ),
475
- generateRouteTypes &&
476
- this.templatesWorker.renderTemplate(
477
- templatesToRender.routeTypes,
478
- configuration,
479
- ),
480
- generateClient &&
481
- this.templatesWorker.renderTemplate(
482
- templatesToRender.httpClient,
483
- configuration,
484
- ),
485
- generateClient &&
486
- this.templatesWorker.renderTemplate(
487
- templatesToRender.api,
488
- configuration,
489
- ),
490
- ]).join("\n"),
491
- );
492
- };
493
-
494
- /**
495
- *
496
- * @param configuration
497
- * @param fileNameFull
498
- * @param content
499
- * @returns {Promise<TranslatorIO[]>}
500
- */
501
- createOutputFileInfo = async (configuration, fileNameFull, content) => {
502
- const fileName = this.fileSystem.cropExtension(fileNameFull);
503
- const fileExtension = ts.Extension.Ts;
504
-
505
- if (configuration.translateToJavaScript) {
506
- this.logger.debug("using js translator for", fileName);
507
- return await this.javascriptTranslator.translate({
508
- fileName: fileName,
509
- fileExtension: fileExtension,
510
- fileContent: content,
511
- });
512
- }
513
-
514
- if (configuration.customTranslator) {
515
- this.logger.debug("using custom translator for", fileName);
516
- return await configuration.customTranslator.translate({
517
- fileName: fileName,
518
- fileExtension: fileExtension,
519
- fileContent: content,
520
- });
521
- }
522
-
523
- this.logger.debug("generating output for", `${fileName}${fileExtension}`);
524
-
525
- return [
526
- {
527
- fileName,
528
- fileExtension: fileExtension,
529
- fileContent: await this.codeFormatter.formatCode(content),
530
- },
531
- ];
532
- };
533
-
534
- createApiConfig = (swaggerSchema) => {
535
- const { info, servers, host, basePath, externalDocs, tags } = swaggerSchema;
536
- const server = servers?.[0] || { url: "" };
537
- const { title = "No title", version } = info || {};
538
- const { url: serverUrl } = server;
539
-
540
- return {
541
- info: info || {},
542
- servers: servers || [],
543
- basePath,
544
- host,
545
- externalDocs: _.merge(
546
- {
547
- url: "",
548
- description: "",
549
- },
550
- externalDocs,
551
- ),
552
- tags: _.compact(tags),
553
- baseUrl: serverUrl,
554
- title,
555
- version,
556
- };
557
- };
558
-
559
- injectClassInstance = (key, value) => {
560
- this[key] = value;
561
- PATCHABLE_INSTANCES.forEach((instanceKey) => {
562
- if (instanceKey !== key && key in this[instanceKey]) {
563
- this[instanceKey][key] = value;
564
- }
565
- });
566
- };
567
- }
568
-
569
- module.exports = {
570
- CodeGenProcess,
571
- };
@@ -1,33 +0,0 @@
1
- const { objectAssign } = require("../../util/object-assign");
2
- const { HTTP_CLIENT, PROJECT_VERSION } = require("../../constants");
3
-
4
- /**
5
- * @type {GenerateTemplatesParams}}
6
- */
7
- class TemplatesGenConfig {
8
- cleanOutput = false;
9
- output = undefined;
10
- httpClientType = HTTP_CLIENT.FETCH;
11
- modular = false;
12
- silent = false;
13
- version = PROJECT_VERSION;
14
- rewrite = false;
15
-
16
- /**
17
- * @param config {GenerateTemplatesParams}
18
- */
19
- constructor(config) {
20
- this.update(config);
21
- }
22
-
23
- /**
24
- * @param update {Partial<GenerateTemplatesParams>}
25
- */
26
- update = (update) => {
27
- objectAssign(this, update);
28
- };
29
- }
30
-
31
- module.exports = {
32
- TemplatesGenConfig,
33
- };
@@ -1,16 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // Copyright (c) 2019-present acacode
4
- // Node module: swagger-typescript-api
5
- // This file is licensed under the MIT License.
6
- // License text available at https://opensource.org/licenses/MIT
7
- // Repository https://github.com/acacode/swagger-typescript-api
8
-
9
- const { TemplatesGenProcess } = require("./templates-gen-process");
10
-
11
- module.exports = {
12
- generateTemplates: async (config) => {
13
- const codeGenProcess = new TemplatesGenProcess(config);
14
- return await codeGenProcess.start();
15
- },
16
- };