@weclapp/sdk 2.0.0-dev.50 → 2.0.0-dev.51
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/dist/cli.js +407 -355
- package/package.json +10 -6
package/dist/cli.js
CHANGED
|
@@ -4,7 +4,7 @@ import { rollup } from 'rollup';
|
|
|
4
4
|
import terser from '@rollup/plugin-terser';
|
|
5
5
|
import ts from '@rollup/plugin-typescript';
|
|
6
6
|
import indentString from 'indent-string';
|
|
7
|
-
import { snakeCase,
|
|
7
|
+
import { snakeCase, pascalCase, camelCase } from 'change-case';
|
|
8
8
|
import chalk from 'chalk';
|
|
9
9
|
import { OpenAPIV3 } from 'openapi-types';
|
|
10
10
|
import { createHash } from 'crypto';
|
|
@@ -157,8 +157,8 @@ const resolveImports = (target) => {
|
|
|
157
157
|
};
|
|
158
158
|
const resolveMappings = (target) => `const wrapResponse = ${isRXTarget(target) ? 'defer' : '(v: (...args: any[]) => any) => v()'};`;
|
|
159
159
|
const resolveBinaryClass = (target) => `const resolveBinaryObject = () => ${resolveBinaryType(target)};`;
|
|
160
|
-
const generateBase = (target,
|
|
161
|
-
return generateStatements(resolveImports(target), `const apiVersion = ${apiVersion}`, resolveMappings(target), resolveBinaryClass(target), globalConfig, types, utils, root,
|
|
160
|
+
const generateBase = (apiVersion, { target, useQueryLanguage, generateUnique }) => {
|
|
161
|
+
return generateStatements(resolveImports(target), `const apiVersion = ${apiVersion}`, resolveMappings(target), resolveBinaryClass(target), globalConfig, types, utils, root, useQueryLanguage ? queriesWithQueryLanguage : queriesWithFilter, generateUnique ? unique : '', multiRequest);
|
|
162
162
|
};
|
|
163
163
|
|
|
164
164
|
const transformKey = (s) => snakeCase(s).toUpperCase();
|
|
@@ -191,22 +191,10 @@ const isArraySchemaObject = (v) => {
|
|
|
191
191
|
const isResponseObject = (v) => {
|
|
192
192
|
return isObject(v) && typeof v.description === 'string';
|
|
193
193
|
};
|
|
194
|
-
const isNonArraySchemaObject = (v) => {
|
|
195
|
-
return isObject(v) && ['string', 'undefined'].includes(typeof v.type);
|
|
196
|
-
};
|
|
197
|
-
const isFilterPathsSchemaObject = (v) => {
|
|
198
|
-
return isObject(v) && v.type === 'object' && isObject(v['x-weclapp-filterPaths']);
|
|
199
|
-
};
|
|
200
|
-
const isFilterPropertySchemaObject = (v) => {
|
|
201
|
-
return isObject(v) && v.type === 'object' && isObject(v['x-weclapp-filterProperties']);
|
|
202
|
-
};
|
|
203
|
-
const isRelatedEntitySchema = (v) => {
|
|
204
|
-
return isObject(v) && isNonArraySchemaObject(v) && 'x-weclapp' in v && isObject(v['x-weclapp']);
|
|
205
|
-
};
|
|
206
194
|
|
|
207
|
-
const generateEnums = (
|
|
195
|
+
const generateEnums = (context) => {
|
|
208
196
|
const enums = new Map();
|
|
209
|
-
for (const [schemaName, schema] of schemas) {
|
|
197
|
+
for (const [schemaName, schema] of context.schemas) {
|
|
210
198
|
if (isEnumSchemaObject(schema)) {
|
|
211
199
|
const enumName = loosePascalCase(schemaName);
|
|
212
200
|
if (!enums.has(enumName)) {
|
|
@@ -232,6 +220,23 @@ const concat = (strings, separator = ', ', maxLength = 80) => {
|
|
|
232
220
|
}
|
|
233
221
|
};
|
|
234
222
|
|
|
223
|
+
const convertParametersToSchemaObject = (parameters) => {
|
|
224
|
+
const properties = [];
|
|
225
|
+
const required = [];
|
|
226
|
+
for (const param of parameters) {
|
|
227
|
+
if (param.in === 'query' && param.schema) {
|
|
228
|
+
properties.push([param.name, param.schema]);
|
|
229
|
+
if (param.required)
|
|
230
|
+
required.push(param.name);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return {
|
|
234
|
+
type: 'object',
|
|
235
|
+
properties: Object.fromEntries(properties),
|
|
236
|
+
required
|
|
237
|
+
};
|
|
238
|
+
};
|
|
239
|
+
|
|
235
240
|
const createReferenceType = (value) => ({
|
|
236
241
|
type: 'reference',
|
|
237
242
|
toString: () => loosePascalCase(value)
|
|
@@ -274,7 +279,10 @@ const getRefName = (obj) => {
|
|
|
274
279
|
return obj.$ref.replace(/.*\//, '');
|
|
275
280
|
};
|
|
276
281
|
const convertToTypeScriptType = (schema) => {
|
|
277
|
-
if (
|
|
282
|
+
if (Array.isArray(schema)) {
|
|
283
|
+
return convertToTypeScriptType(convertParametersToSchemaObject(schema));
|
|
284
|
+
}
|
|
285
|
+
else if (isReferenceObject(schema)) {
|
|
278
286
|
return createReferenceType(getRefName(schema));
|
|
279
287
|
}
|
|
280
288
|
else {
|
|
@@ -293,7 +301,7 @@ const convertToTypeScriptType = (schema) => {
|
|
|
293
301
|
return createRawType('boolean');
|
|
294
302
|
case 'object': {
|
|
295
303
|
const { properties = {}, required = [] } = schema;
|
|
296
|
-
return createObjectType(Object.fromEntries(Object.entries(properties).map((
|
|
304
|
+
return createObjectType(Object.fromEntries(Object.entries(properties).map(([prop, propSchema]) => [prop, convertToTypeScriptType(propSchema)])), required);
|
|
297
305
|
}
|
|
298
306
|
case 'array':
|
|
299
307
|
return createArrayType(convertToTypeScriptType(schema.items));
|
|
@@ -303,40 +311,43 @@ const convertToTypeScriptType = (schema) => {
|
|
|
303
311
|
}
|
|
304
312
|
};
|
|
305
313
|
|
|
306
|
-
const
|
|
314
|
+
const setReferenceMeta = (prop, metaData, context) => {
|
|
307
315
|
const referenceName = getRefName(prop);
|
|
308
|
-
const
|
|
309
|
-
if (
|
|
310
|
-
|
|
316
|
+
const referenceSchema = context.schemas.get(referenceName);
|
|
317
|
+
if (isEnumSchemaObject(referenceSchema)) {
|
|
318
|
+
metaData.enum = loosePascalCase(referenceName);
|
|
311
319
|
}
|
|
312
320
|
else {
|
|
313
|
-
|
|
321
|
+
metaData.entity = referenceName;
|
|
314
322
|
}
|
|
315
323
|
};
|
|
316
|
-
const extractPropertyMetaData = (
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
324
|
+
const extractPropertyMetaData = (prop, context) => {
|
|
325
|
+
const metaData = {};
|
|
326
|
+
const weclappExtension = prop['x-weclapp'];
|
|
327
|
+
if (weclappExtension) {
|
|
328
|
+
metaData.service = weclappExtension.service;
|
|
329
|
+
metaData.entity = weclappExtension.entity;
|
|
330
|
+
}
|
|
321
331
|
if (isReferenceObject(prop)) {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
332
|
+
metaData.type = 'reference';
|
|
333
|
+
setReferenceMeta(prop, metaData, context);
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
metaData.type = prop.type;
|
|
337
|
+
metaData.format = prop.format;
|
|
338
|
+
metaData.maxLength = prop.maxLength;
|
|
339
|
+
metaData.pattern = prop.pattern;
|
|
340
|
+
if (isArraySchemaObject(prop)) {
|
|
341
|
+
if (isReferenceObject(prop.items)) {
|
|
342
|
+
metaData.format = 'reference';
|
|
343
|
+
setReferenceMeta(prop.items, metaData, context);
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
metaData.format = 'string';
|
|
347
|
+
}
|
|
337
348
|
}
|
|
338
349
|
}
|
|
339
|
-
return
|
|
350
|
+
return metaData;
|
|
340
351
|
};
|
|
341
352
|
|
|
342
353
|
const generateInlineComment = (comment) => `/** ${comment} */`;
|
|
@@ -383,108 +394,6 @@ const generateInterfaceType = (name, entries, extend) => {
|
|
|
383
394
|
return generateType(name, typeDefinition);
|
|
384
395
|
};
|
|
385
396
|
|
|
386
|
-
const FILTER_PROPS_SUFFIX = 'Filter_Props';
|
|
387
|
-
const generateEntities = (schemas, enums) => {
|
|
388
|
-
const entities = new Map();
|
|
389
|
-
for (const [schemaName, schema] of schemas) {
|
|
390
|
-
// Enums are generated separately
|
|
391
|
-
if (isEnumSchemaObject(schema)) {
|
|
392
|
-
continue;
|
|
393
|
-
}
|
|
394
|
-
const entityInterfaceName = loosePascalCase(schemaName);
|
|
395
|
-
let parentEntityInterfaceName = undefined;
|
|
396
|
-
const entityInterfaceProperties = [];
|
|
397
|
-
const filterableInterfaceProperties = [];
|
|
398
|
-
const properties = new Map();
|
|
399
|
-
const processProperties = (props = {}, isXweclappFilterProp) => {
|
|
400
|
-
for (const [name, property] of Object.entries(props)) {
|
|
401
|
-
const meta = isRelatedEntitySchema(property) ? property['x-weclapp'] : {};
|
|
402
|
-
const type = convertToTypeScriptType(property).toString();
|
|
403
|
-
const comment = isNonArraySchemaObject(property)
|
|
404
|
-
? property.deprecated
|
|
405
|
-
? '@deprecated will be removed.'
|
|
406
|
-
: property.format
|
|
407
|
-
? `format: ${property.format}`
|
|
408
|
-
: undefined
|
|
409
|
-
: undefined;
|
|
410
|
-
if (meta.filterable !== false) {
|
|
411
|
-
filterableInterfaceProperties.push({ name, type });
|
|
412
|
-
}
|
|
413
|
-
if (!isXweclappFilterProp) {
|
|
414
|
-
entityInterfaceProperties.push({
|
|
415
|
-
name,
|
|
416
|
-
type,
|
|
417
|
-
comment,
|
|
418
|
-
required: meta.required,
|
|
419
|
-
filterable: meta.filterable ?? true,
|
|
420
|
-
readonly: !isReferenceObject(property) && property.readOnly
|
|
421
|
-
});
|
|
422
|
-
properties.set(name, extractPropertyMetaData(enums, meta, property));
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
};
|
|
426
|
-
if (schema.allOf?.length) {
|
|
427
|
-
for (const item of schema.allOf) {
|
|
428
|
-
if (isReferenceObject(item)) {
|
|
429
|
-
parentEntityInterfaceName = convertToTypeScriptType(item).toString();
|
|
430
|
-
}
|
|
431
|
-
else if (isObjectSchemaObject(item)) {
|
|
432
|
-
processProperties(item.properties);
|
|
433
|
-
if (isFilterPropertySchemaObject(item)) {
|
|
434
|
-
processProperties(item['x-weclapp-filterProperties'], true);
|
|
435
|
-
}
|
|
436
|
-
if (isFilterPathsSchemaObject(item)) {
|
|
437
|
-
const fPaths = item['x-weclapp-filterPaths'];
|
|
438
|
-
for (const path in fPaths) {
|
|
439
|
-
if (!path.includes('.')) {
|
|
440
|
-
filterableInterfaceProperties.push({ name: path, type: fPaths[path] });
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
processProperties(schema.properties);
|
|
448
|
-
entities.set(schemaName, {
|
|
449
|
-
name: schemaName,
|
|
450
|
-
properties,
|
|
451
|
-
filterableInterfaceProperties: filterableInterfaceProperties.sort((propA, propB) => propA.name.localeCompare(propB.name)),
|
|
452
|
-
parentName: parentEntityInterfaceName ? camelCase(parentEntityInterfaceName) : undefined,
|
|
453
|
-
source: generateStatements(generateInterface(entityInterfaceName, entityInterfaceProperties, parentEntityInterfaceName))
|
|
454
|
-
});
|
|
455
|
-
}
|
|
456
|
-
return entities;
|
|
457
|
-
};
|
|
458
|
-
const generateEntityFilterProps = (entities, enums) => {
|
|
459
|
-
const entityFilterProps = new Map();
|
|
460
|
-
const transformFilterProps = (props) => {
|
|
461
|
-
return props.map((prop) => {
|
|
462
|
-
if (!prop.type ||
|
|
463
|
-
enums.has(prop.type) ||
|
|
464
|
-
prop.type === 'string' ||
|
|
465
|
-
prop.type === 'number' ||
|
|
466
|
-
prop.type === 'boolean' ||
|
|
467
|
-
prop.type === '{}' ||
|
|
468
|
-
prop.type.endsWith('[]') ||
|
|
469
|
-
prop.type.includes("'")) {
|
|
470
|
-
return prop;
|
|
471
|
-
}
|
|
472
|
-
return { ...prop, type: `${pascalCase(prop.type)}_${FILTER_PROPS_SUFFIX}` };
|
|
473
|
-
});
|
|
474
|
-
};
|
|
475
|
-
entities.forEach((entity, name) => {
|
|
476
|
-
const entityFilterName = `${pascalCase(name)}_${FILTER_PROPS_SUFFIX}`;
|
|
477
|
-
const parentName = entity.parentName ? `${pascalCase(entity.parentName)}_${FILTER_PROPS_SUFFIX}` : undefined;
|
|
478
|
-
const filterableInterfaceProperties = transformFilterProps(entity.filterableInterfaceProperties);
|
|
479
|
-
entityFilterProps.set(entityFilterName, {
|
|
480
|
-
name: entityFilterName,
|
|
481
|
-
parentName,
|
|
482
|
-
source: generateStatements(generateInterface(entityFilterName, filterableInterfaceProperties, parentName))
|
|
483
|
-
});
|
|
484
|
-
});
|
|
485
|
-
return entityFilterProps;
|
|
486
|
-
};
|
|
487
|
-
|
|
488
397
|
/**
|
|
489
398
|
* Pluralizes a word, most of the time correct.
|
|
490
399
|
* @param s String to pluralize.
|
|
@@ -554,6 +463,108 @@ const logger = new (class {
|
|
|
554
463
|
}
|
|
555
464
|
})();
|
|
556
465
|
|
|
466
|
+
const FILTER_PROPS_SUFFIX = 'Filter_Props';
|
|
467
|
+
const generateEntities = (context) => {
|
|
468
|
+
const entities = new Map();
|
|
469
|
+
for (const [schemaName, schema] of context.schemas) {
|
|
470
|
+
// Enums are generated separately
|
|
471
|
+
if (isEnumSchemaObject(schema)) {
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
const entityName = schemaName;
|
|
475
|
+
const entityInterfaceName = loosePascalCase(entityName);
|
|
476
|
+
const entityInterfaceProperties = [];
|
|
477
|
+
const properties = new Map();
|
|
478
|
+
let parentEntityName = undefined;
|
|
479
|
+
let parentEntityInterfaceName = undefined;
|
|
480
|
+
const entityFilterInterfaceName = `${entityInterfaceName}_${FILTER_PROPS_SUFFIX}`;
|
|
481
|
+
const entityFilterInterfaceProperties = [];
|
|
482
|
+
let parentEntityFilterInterfaceName = undefined;
|
|
483
|
+
const processProperties = (props = {}) => {
|
|
484
|
+
for (const [propertyName, propertySchema] of Object.entries(props)) {
|
|
485
|
+
const weclappExtension = propertySchema['x-weclapp'];
|
|
486
|
+
properties.set(propertyName, extractPropertyMetaData(propertySchema, context));
|
|
487
|
+
const type = convertToTypeScriptType(propertySchema).toString();
|
|
488
|
+
// cast to SchemaObject to access deprecated and readOnly properties (ReferenceObject can also include these props in OpenAPI 3.1)
|
|
489
|
+
const castedSchema = propertySchema;
|
|
490
|
+
const comment = castedSchema.deprecated
|
|
491
|
+
? '@deprecated will be removed.'
|
|
492
|
+
: castedSchema.format
|
|
493
|
+
? `format: ${castedSchema.format}`
|
|
494
|
+
: undefined;
|
|
495
|
+
if (weclappExtension?.filterable !== false) {
|
|
496
|
+
entityFilterInterfaceProperties.push({ name: propertyName, type, comment });
|
|
497
|
+
}
|
|
498
|
+
entityInterfaceProperties.push({
|
|
499
|
+
name: propertyName,
|
|
500
|
+
type,
|
|
501
|
+
required: weclappExtension?.required,
|
|
502
|
+
readonly: castedSchema.readOnly,
|
|
503
|
+
comment
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
const processExtraFilterProperties = (props = {}) => {
|
|
508
|
+
for (const [propertyName, propertySchema] of Object.entries(props)) {
|
|
509
|
+
if (isReferenceObject(propertySchema))
|
|
510
|
+
continue;
|
|
511
|
+
const type = convertToTypeScriptType(propertySchema).toString();
|
|
512
|
+
const comment = propertySchema.deprecated
|
|
513
|
+
? '@deprecated will be removed.'
|
|
514
|
+
: propertySchema.format
|
|
515
|
+
? `format: ${propertySchema.format}`
|
|
516
|
+
: undefined;
|
|
517
|
+
entityFilterInterfaceProperties.push({ name: propertyName, type, comment });
|
|
518
|
+
}
|
|
519
|
+
};
|
|
520
|
+
const processFilterPaths = (filterPaths = {}) => {
|
|
521
|
+
for (const [filterProp, entityName] of Object.entries(filterPaths)) {
|
|
522
|
+
if (!filterProp.includes('.') && context.schemas.get(entityName)) {
|
|
523
|
+
entityFilterInterfaceProperties.push({
|
|
524
|
+
name: filterProp,
|
|
525
|
+
type: `${loosePascalCase(entityName)}_${FILTER_PROPS_SUFFIX}`
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
};
|
|
530
|
+
if (schema.allOf?.length) {
|
|
531
|
+
if (schema.allOf.length > 2) {
|
|
532
|
+
logger.errorLn(`Failed to process schema for ${schemaName}: invalid allOf length`);
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
535
|
+
for (const item of schema.allOf) {
|
|
536
|
+
if (isReferenceObject(item)) {
|
|
537
|
+
parentEntityName = getRefName(item);
|
|
538
|
+
parentEntityInterfaceName = createReferenceType(parentEntityName).toString();
|
|
539
|
+
parentEntityFilterInterfaceName = `${parentEntityInterfaceName}_${FILTER_PROPS_SUFFIX}`;
|
|
540
|
+
}
|
|
541
|
+
else if (item.type === 'object') {
|
|
542
|
+
processProperties(item.properties);
|
|
543
|
+
processExtraFilterProperties(item['x-weclapp-filterProperties']);
|
|
544
|
+
processFilterPaths(item['x-weclapp-filterPaths']);
|
|
545
|
+
}
|
|
546
|
+
else {
|
|
547
|
+
logger.errorLn(`Failed to process schema for ${schemaName}: invalid schema type in allOf`);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
else {
|
|
552
|
+
processProperties(schema.properties);
|
|
553
|
+
}
|
|
554
|
+
entities.set(entityName, {
|
|
555
|
+
name: entityName,
|
|
556
|
+
interfaceName: entityInterfaceName,
|
|
557
|
+
properties,
|
|
558
|
+
source: generateStatements(generateInterface(entityInterfaceName, entityInterfaceProperties, parentEntityInterfaceName)),
|
|
559
|
+
filterInterfaceName: entityFilterInterfaceName,
|
|
560
|
+
filterSource: generateStatements(generateInterface(entityFilterInterfaceName, entityFilterInterfaceProperties, parentEntityFilterInterfaceName)),
|
|
561
|
+
parentName: parentEntityName,
|
|
562
|
+
parentInterfaceName: parentEntityInterfaceName
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
return entities;
|
|
566
|
+
};
|
|
567
|
+
|
|
557
568
|
/**
|
|
558
569
|
* ROOT => /article
|
|
559
570
|
* COUNT => /article/count
|
|
@@ -600,6 +611,31 @@ const parseEndpointPath = (path) => {
|
|
|
600
611
|
}
|
|
601
612
|
return undefined;
|
|
602
613
|
};
|
|
614
|
+
const isMultiPartUploadPath = (path) => {
|
|
615
|
+
const [, entity, ...rest] = path.split('/');
|
|
616
|
+
return entity && rest.length === 2 && rest[1] === 'multipartUpload';
|
|
617
|
+
};
|
|
618
|
+
const parseEndpointsPaths = (paths) => {
|
|
619
|
+
const endpoints = new Map();
|
|
620
|
+
for (const [rawPath, path] of Object.entries(paths)) {
|
|
621
|
+
const endpoint = parseEndpointPath(rawPath);
|
|
622
|
+
if (!endpoint || !path) {
|
|
623
|
+
// Todo: Should be removed if sdk supports multi part upload.
|
|
624
|
+
if (isMultiPartUploadPath(rawPath)) {
|
|
625
|
+
continue;
|
|
626
|
+
}
|
|
627
|
+
logger.errorLn(`Failed to parse ${rawPath}`);
|
|
628
|
+
continue;
|
|
629
|
+
}
|
|
630
|
+
if (endpoints.has(endpoint.service)) {
|
|
631
|
+
endpoints.get(endpoint.service)?.push({ endpoint, path });
|
|
632
|
+
}
|
|
633
|
+
else {
|
|
634
|
+
endpoints.set(endpoint.service, [{ endpoint, path }]);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
return endpoints;
|
|
638
|
+
};
|
|
603
639
|
|
|
604
640
|
const generateArrowFunction = ({ name, signature, returns, params }) => {
|
|
605
641
|
return `const ${name}: ${signature} = (${params?.join(', ') ?? ''}) =>\n${indent(returns)};`;
|
|
@@ -611,43 +647,40 @@ const generateArrowFunctionType = ({ type, returns = 'void', generics, params })
|
|
|
611
647
|
return generateType(type, `${genericsString + paramsString} =>\n${indent(returns)}`);
|
|
612
648
|
};
|
|
613
649
|
|
|
614
|
-
const
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
if (
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
if (param.required)
|
|
622
|
-
required.push(param.name);
|
|
623
|
-
}
|
|
650
|
+
const resolveParameters = (resolvableParameters = [], parameters) => {
|
|
651
|
+
if (!resolvableParameters)
|
|
652
|
+
return [];
|
|
653
|
+
return resolvableParameters.flatMap((param) => {
|
|
654
|
+
if (isReferenceObject(param)) {
|
|
655
|
+
const resolved = parameters.get(getRefName(param));
|
|
656
|
+
return resolved ? [resolved] : [];
|
|
624
657
|
}
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
type: 'object',
|
|
628
|
-
required,
|
|
629
|
-
properties: Object.fromEntries(properties)
|
|
630
|
-
};
|
|
658
|
+
return [param];
|
|
659
|
+
});
|
|
631
660
|
};
|
|
632
661
|
|
|
633
|
-
const generateCountEndpoint = ({
|
|
662
|
+
const generateCountEndpoint = ({ endpoint, operationObject, entities, context, options }) => {
|
|
634
663
|
const functionName = 'count';
|
|
635
664
|
const functionTypeName = `${pascalCase(endpoint.service)}Service_${pascalCase(functionName)}`;
|
|
636
|
-
const
|
|
665
|
+
const relatedEntityName = context.aliases.get(endpoint.service);
|
|
666
|
+
const relatedEntity = !!relatedEntityName && entities.get(relatedEntityName);
|
|
667
|
+
if (!relatedEntity) {
|
|
668
|
+
throw Error(`Related entity schema for service ${endpoint.service} not found`);
|
|
669
|
+
}
|
|
637
670
|
const parametersTypeName = `${functionTypeName}_Parameters`;
|
|
638
671
|
const parametersType = createObjectType({
|
|
639
|
-
params: convertToTypeScriptType(
|
|
672
|
+
params: convertToTypeScriptType(resolveParameters(operationObject.parameters, context.parameters))
|
|
640
673
|
});
|
|
641
674
|
const parametersTypeSource = generateInterfaceFromObject(parametersTypeName, parametersType, 'propagate');
|
|
642
675
|
const filterTypeName = `${functionTypeName}_Filter`;
|
|
643
|
-
const filterTypeSource = generateInterfaceType(filterTypeName, [], [`${
|
|
676
|
+
const filterTypeSource = generateInterfaceType(filterTypeName, [], [`${relatedEntity.filterInterfaceName}`]);
|
|
644
677
|
const functionTypeSource = generateArrowFunctionType({
|
|
645
678
|
type: functionTypeName,
|
|
646
679
|
params: [
|
|
647
|
-
`query${parametersType.isFullyOptional() ? '?' : ''}: CountQuery<${filterTypeName}>${
|
|
680
|
+
`query${parametersType.isFullyOptional() ? '?' : ''}: CountQuery<${filterTypeName}>${operationObject.parameters?.length ? ' & ' + parametersTypeName : ''}`,
|
|
648
681
|
'requestOptions?: RequestOptions'
|
|
649
682
|
],
|
|
650
|
-
returns: `${resolveResponseType(target)}<number>`
|
|
683
|
+
returns: `${resolveResponseType(options.target)}<number>`
|
|
651
684
|
});
|
|
652
685
|
const functionSource = generateArrowFunction({
|
|
653
686
|
name: functionName,
|
|
@@ -656,44 +689,51 @@ const generateCountEndpoint = ({ aliases, path, target, endpoint }) => {
|
|
|
656
689
|
params: ['query', 'requestOptions?: RequestOptions']
|
|
657
690
|
});
|
|
658
691
|
return {
|
|
659
|
-
entity,
|
|
660
692
|
name: functionName,
|
|
661
693
|
type: { name: functionTypeName, source: functionTypeSource },
|
|
662
694
|
func: { name: functionName, source: functionSource },
|
|
663
695
|
interfaces: [
|
|
664
|
-
...(
|
|
696
|
+
...(operationObject.parameters?.length ? [{ name: parametersTypeName, source: parametersTypeSource }] : []),
|
|
665
697
|
{ name: filterTypeName, source: filterTypeSource }
|
|
666
698
|
]
|
|
667
699
|
};
|
|
668
700
|
};
|
|
669
701
|
|
|
670
|
-
const
|
|
671
|
-
if (
|
|
672
|
-
return
|
|
673
|
-
}
|
|
702
|
+
const generateContentType = (body, fallback = 'unknown') => {
|
|
703
|
+
if (!body?.content)
|
|
704
|
+
return createRawType(fallback);
|
|
674
705
|
const types = [];
|
|
675
|
-
for (const { schema } of Object.values(body
|
|
706
|
+
for (const { schema } of Object.values(body.content)) {
|
|
676
707
|
if (schema) {
|
|
677
708
|
types.push(convertToTypeScriptType(schema));
|
|
678
709
|
}
|
|
679
710
|
}
|
|
680
|
-
return
|
|
711
|
+
return (types.length > 1 ? createTupleType(types) : types[0]) ?? createRawType(fallback);
|
|
681
712
|
};
|
|
682
713
|
|
|
683
|
-
const generateRequestBodyType = ({ requestBody }) => {
|
|
684
|
-
|
|
714
|
+
const generateRequestBodyType = ({ requestBody }, requestBodies) => {
|
|
715
|
+
const requestBodyObject = requestBody && isReferenceObject(requestBody) ? requestBodies.get(getRefName(requestBody)) : requestBody;
|
|
716
|
+
return generateContentType(requestBodyObject);
|
|
685
717
|
};
|
|
686
718
|
|
|
687
|
-
const
|
|
688
|
-
|
|
719
|
+
const resolveResponsesObject = (responses) => Object.entries(responses).find(([statusCode]) => statusCode.startsWith('2'))?.[1];
|
|
720
|
+
|
|
721
|
+
const generateResponseType = (operationObject, responses) => {
|
|
722
|
+
const response = resolveResponsesObject(operationObject.responses);
|
|
723
|
+
const responseObject = response && isReferenceObject(response) ? responses.get(getRefName(response)) : response;
|
|
724
|
+
return generateContentType(responseObject, 'void');
|
|
725
|
+
};
|
|
689
726
|
|
|
690
|
-
const generateCreateEndpoint = ({
|
|
727
|
+
const generateCreateEndpoint = ({ endpoint, operationObject, context, options }) => {
|
|
691
728
|
const functionName = 'create';
|
|
692
729
|
const functionTypeName = `${pascalCase(endpoint.service)}Service_${pascalCase(functionName)}`;
|
|
693
730
|
const functionTypeSource = generateArrowFunctionType({
|
|
694
731
|
type: functionTypeName,
|
|
695
|
-
params: [
|
|
696
|
-
|
|
732
|
+
params: [
|
|
733
|
+
`data: DeepPartial<${generateRequestBodyType(operationObject, context.requestBodies).toString()}>`,
|
|
734
|
+
'requestOptions?: RequestOptions'
|
|
735
|
+
],
|
|
736
|
+
returns: `${resolveResponseType(options.target)}<${generateResponseType(operationObject, context.responses).toString()}>`
|
|
697
737
|
});
|
|
698
738
|
const functionSource = generateArrowFunction({
|
|
699
739
|
name: functionName,
|
|
@@ -702,7 +742,6 @@ const generateCreateEndpoint = ({ target, path, endpoint }) => {
|
|
|
702
742
|
params: ['data', 'requestOptions?: RequestOptions']
|
|
703
743
|
});
|
|
704
744
|
return {
|
|
705
|
-
entity: pascalCase(endpoint.service),
|
|
706
745
|
name: functionName,
|
|
707
746
|
type: { name: functionTypeName, source: functionTypeSource },
|
|
708
747
|
func: { name: functionName, source: functionSource }
|
|
@@ -720,16 +759,19 @@ const insertPathPlaceholder = (path, record) => {
|
|
|
720
759
|
const wrapBody = (type, target) => {
|
|
721
760
|
return type.toString() === 'binary' ? createRawType(isNodeTarget(target) ? 'BodyInit' : 'Blob') : type; // node-fetch returns a Blob as well
|
|
722
761
|
};
|
|
723
|
-
const generateGenericEndpoint = (suffix) => ({
|
|
762
|
+
const generateGenericEndpoint = (suffix) => ({ method, endpoint, operationObject, context, options }) => {
|
|
724
763
|
const functionName = generateGenericFunctionName(endpoint.path, suffix, method);
|
|
725
764
|
const functionTypeName = `${pascalCase(endpoint.service)}Service_${pascalCase(functionName)}`;
|
|
726
765
|
const entityQuery = `${functionTypeName}_Query`;
|
|
727
766
|
const hasId = endpoint.path.includes('{id}');
|
|
728
767
|
const params = createObjectType({
|
|
729
|
-
params:
|
|
730
|
-
|
|
768
|
+
params: operationObject.parameters &&
|
|
769
|
+
convertToTypeScriptType(resolveParameters(operationObject.parameters, context.parameters)),
|
|
770
|
+
body: method === 'get'
|
|
771
|
+
? undefined
|
|
772
|
+
: wrapBody(generateRequestBodyType(operationObject, context.requestBodies), options.target)
|
|
731
773
|
});
|
|
732
|
-
const responseBody =
|
|
774
|
+
const responseBody = generateResponseType(operationObject, context.responses);
|
|
733
775
|
const functionTypeSource = generateArrowFunctionType({
|
|
734
776
|
type: functionTypeName,
|
|
735
777
|
params: [
|
|
@@ -737,7 +779,7 @@ const generateGenericEndpoint = (suffix) => ({ target, method, path, endpoint })
|
|
|
737
779
|
`query${params.isFullyOptional() ? '?' : ''}: ${entityQuery}`,
|
|
738
780
|
'requestOptions?: RequestOptions'
|
|
739
781
|
],
|
|
740
|
-
returns: `${resolveResponseType(target)}<${wrapBody(responseBody, target).toString('force')}>`
|
|
782
|
+
returns: `${resolveResponseType(options.target)}<${wrapBody(responseBody, options.target).toString('force')}>`
|
|
741
783
|
});
|
|
742
784
|
const functionSource = generateArrowFunction({
|
|
743
785
|
name: functionName,
|
|
@@ -746,7 +788,6 @@ const generateGenericEndpoint = (suffix) => ({ target, method, path, endpoint })
|
|
|
746
788
|
returns: `_generic(cfg, ${generateString(method.toUpperCase())}, \`${insertPathPlaceholder(endpoint.path, { id: '${id}' })}\`, query, ${String(responseBody.toString() === 'binary')}, requestOptions)`
|
|
747
789
|
});
|
|
748
790
|
return {
|
|
749
|
-
entity: pascalCase(endpoint.service),
|
|
750
791
|
name: functionName,
|
|
751
792
|
type: { name: functionTypeName, source: functionTypeSource },
|
|
752
793
|
func: { name: functionName, source: functionSource },
|
|
@@ -759,13 +800,13 @@ const generateGenericEndpoint = (suffix) => ({ target, method, path, endpoint })
|
|
|
759
800
|
};
|
|
760
801
|
};
|
|
761
802
|
|
|
762
|
-
const generateRemoveEndpoint = ({
|
|
803
|
+
const generateRemoveEndpoint = ({ endpoint, options }) => {
|
|
763
804
|
const functionName = 'remove';
|
|
764
805
|
const functionTypeName = `${pascalCase(endpoint.service)}Service_${pascalCase(functionName)}`;
|
|
765
806
|
const functionTypeSource = generateArrowFunctionType({
|
|
766
807
|
type: functionTypeName,
|
|
767
808
|
params: ['id: string', 'options?: RemoveQuery', 'requestOptions?: RequestOptions'],
|
|
768
|
-
returns: `${resolveResponseType(target)}<void>`
|
|
809
|
+
returns: `${resolveResponseType(options.target)}<void>`
|
|
769
810
|
});
|
|
770
811
|
const functionSource = generateArrowFunction({
|
|
771
812
|
name: functionName,
|
|
@@ -774,7 +815,6 @@ const generateRemoveEndpoint = ({ target, endpoint }) => {
|
|
|
774
815
|
params: ['id', 'options?: RemoveQuery', 'requestOptions?: RequestOptions']
|
|
775
816
|
});
|
|
776
817
|
return {
|
|
777
|
-
entity: pascalCase(endpoint.service),
|
|
778
818
|
name: functionName,
|
|
779
819
|
type: { name: functionTypeName, source: functionTypeSource },
|
|
780
820
|
func: { name: functionName, source: functionSource }
|
|
@@ -790,8 +830,8 @@ const excludedParameters = [
|
|
|
790
830
|
'includeReferencedEntities',
|
|
791
831
|
'additionalProperties'
|
|
792
832
|
];
|
|
793
|
-
const resolveAdditionalPropertiesSchema = (
|
|
794
|
-
const body =
|
|
833
|
+
const resolveAdditionalPropertiesSchema = ({ responses }) => {
|
|
834
|
+
const body = resolveResponsesObject(responses);
|
|
795
835
|
if (isResponseObject(body)) {
|
|
796
836
|
const schema = body?.content?.['application/json']?.schema;
|
|
797
837
|
if (isObjectSchemaObject(schema)) {
|
|
@@ -827,12 +867,14 @@ const resolveReferencedEntities = (entity, entities) => {
|
|
|
827
867
|
const generatedEntity = entities.get(entity);
|
|
828
868
|
if (generatedEntity) {
|
|
829
869
|
for (const [, propertyMetaData] of generatedEntity.properties) {
|
|
830
|
-
if (propertyMetaData.
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
870
|
+
if (propertyMetaData.service && propertyMetaData.entity) {
|
|
871
|
+
const referencedEntity = entities.get(propertyMetaData.entity);
|
|
872
|
+
if (referencedEntity)
|
|
873
|
+
referencedEntities.push({
|
|
874
|
+
name: propertyMetaData.service,
|
|
875
|
+
type: `${referencedEntity.interfaceName}[]`,
|
|
876
|
+
required: true
|
|
877
|
+
});
|
|
836
878
|
}
|
|
837
879
|
}
|
|
838
880
|
if (generatedEntity.parentName) {
|
|
@@ -841,33 +883,37 @@ const resolveReferencedEntities = (entity, entities) => {
|
|
|
841
883
|
}
|
|
842
884
|
return referencedEntities;
|
|
843
885
|
};
|
|
844
|
-
const generateSomeEndpoint = ({ endpoint,
|
|
886
|
+
const generateSomeEndpoint = ({ endpoint, operationObject, entities, context, options }) => {
|
|
845
887
|
const functionName = 'some';
|
|
846
888
|
const functionTypeName = `${pascalCase(endpoint.service)}Service_${pascalCase(functionName)}`;
|
|
847
|
-
const
|
|
889
|
+
const relatedEntityName = context.aliases.get(endpoint.service);
|
|
890
|
+
const relatedEntity = !!relatedEntityName && entities.get(relatedEntityName);
|
|
891
|
+
if (!relatedEntity) {
|
|
892
|
+
throw Error(`Related entity schema for service ${endpoint.service} not found`);
|
|
893
|
+
}
|
|
848
894
|
const parametersTypeName = `${functionTypeName}_Parameters`;
|
|
849
|
-
const parameters =
|
|
895
|
+
const parameters = operationObject.parameters?.filter((v) => isParameterObject(v) ? !excludedParameters.includes(v.name) : false);
|
|
850
896
|
const parametersType = createObjectType({
|
|
851
|
-
params: convertToTypeScriptType(
|
|
897
|
+
params: parameters && convertToTypeScriptType(resolveParameters(parameters, context.parameters))
|
|
852
898
|
});
|
|
853
899
|
const parametersTypeSource = generateInterfaceFromObject(parametersTypeName, parametersType, 'propagate');
|
|
854
900
|
const filterTypeName = `${functionTypeName}_Filter`;
|
|
855
|
-
const filterTypeSource = generateInterfaceType(filterTypeName, [], [`${
|
|
901
|
+
const filterTypeSource = generateInterfaceType(filterTypeName, [], [`${relatedEntity.filterInterfaceName}`]);
|
|
856
902
|
const referencesTypeName = `${functionTypeName}_References`;
|
|
857
903
|
const referencesTypeSource = generateInterfaceType(referencesTypeName, resolveReferences(endpoint.service, entities));
|
|
858
904
|
const additionalPropertyTypeName = `${functionTypeName}_AdditionalProperty`;
|
|
859
905
|
const additionalPropertyTypeSource = generateType(additionalPropertyTypeName, 'string');
|
|
860
906
|
const queryTypeName = `${functionTypeName}_Query`;
|
|
861
|
-
const queryTypeSource = generateType(queryTypeName, `SomeQuery<${
|
|
907
|
+
const queryTypeSource = generateType(queryTypeName, `SomeQuery<${relatedEntity.interfaceName}, ${filterTypeName}, ${referencesTypeName}, ${additionalPropertyTypeName}> & ${parametersTypeName}`);
|
|
862
908
|
const referencedEntitiesTypeName = `${functionTypeName}_ReferencedEntities`;
|
|
863
909
|
const referencedEntitiesTypeSource = generateInterfaceType(referencedEntitiesTypeName, resolveReferencedEntities(endpoint.service, entities));
|
|
864
910
|
const additionalPropertiesTypeName = `${functionTypeName}_AdditionalProperties`;
|
|
865
|
-
const additionalPropertiesSchema = resolveAdditionalPropertiesSchema(
|
|
911
|
+
const additionalPropertiesSchema = resolveAdditionalPropertiesSchema(operationObject);
|
|
866
912
|
const additionalPropertiesTypeSource = generateType(additionalPropertiesTypeName, additionalPropertiesSchema ? convertToTypeScriptType(additionalPropertiesSchema).toString() : '{}');
|
|
867
913
|
const functionTypeSource = generateArrowFunctionType({
|
|
868
914
|
type: functionTypeName,
|
|
869
915
|
params: [`query${parametersType.isFullyOptional() ? '?' : ''}: ${queryTypeName}, requestOptions?: RequestOptions`],
|
|
870
|
-
returns: `${resolveResponseType(target)}<SomeQueryReturn<${
|
|
916
|
+
returns: `${resolveResponseType(options.target)}<SomeQueryReturn<${relatedEntity.interfaceName}, ${referencedEntitiesTypeName}, ${additionalPropertiesTypeName}>>`
|
|
871
917
|
});
|
|
872
918
|
const functionSource = generateArrowFunction({
|
|
873
919
|
name: functionName,
|
|
@@ -876,7 +922,6 @@ const generateSomeEndpoint = ({ endpoint, target, path, entities, aliases }) =>
|
|
|
876
922
|
params: ['query', 'requestOptions?: RequestOptions']
|
|
877
923
|
});
|
|
878
924
|
return {
|
|
879
|
-
entity,
|
|
880
925
|
name: functionName,
|
|
881
926
|
type: { name: functionTypeName, source: functionTypeSource },
|
|
882
927
|
func: { name: functionName, source: functionSource },
|
|
@@ -892,14 +937,14 @@ const generateSomeEndpoint = ({ endpoint, target, path, entities, aliases }) =>
|
|
|
892
937
|
};
|
|
893
938
|
};
|
|
894
939
|
|
|
895
|
-
const generateUniqueEndpoint = ({
|
|
940
|
+
const generateUniqueEndpoint = ({ operationObject, endpoint, context, options }) => {
|
|
896
941
|
const functionName = 'unique';
|
|
897
942
|
const functionTypeName = `${pascalCase(endpoint.service)}Service_${pascalCase(functionName)}`;
|
|
898
943
|
const functionTypeSource = generateArrowFunctionType({
|
|
899
944
|
type: functionTypeName,
|
|
900
945
|
params: ['id: string', 'query?: Q', 'requestOptions?: RequestOptions'],
|
|
901
946
|
generics: ['Q extends UniqueQuery'],
|
|
902
|
-
returns: `${resolveResponseType(target)}<${
|
|
947
|
+
returns: `${resolveResponseType(options.target)}<${generateResponseType(operationObject, context.responses).toString()}>`
|
|
903
948
|
});
|
|
904
949
|
const functionSource = generateArrowFunction({
|
|
905
950
|
name: functionName,
|
|
@@ -908,25 +953,24 @@ const generateUniqueEndpoint = ({ target, path, endpoint }) => {
|
|
|
908
953
|
returns: `_${functionName}(cfg, \`${insertPathPlaceholder(endpoint.path, { id: '${id}' })}\`, query, requestOptions)`
|
|
909
954
|
});
|
|
910
955
|
return {
|
|
911
|
-
entity: pascalCase(endpoint.service),
|
|
912
956
|
name: functionName,
|
|
913
957
|
type: { name: functionTypeName, source: functionTypeSource },
|
|
914
958
|
func: { name: functionName, source: functionSource }
|
|
915
959
|
};
|
|
916
960
|
};
|
|
917
961
|
|
|
918
|
-
const generateUpdateEndpoint = ({
|
|
962
|
+
const generateUpdateEndpoint = ({ endpoint, operationObject, context, options }) => {
|
|
919
963
|
const functionName = 'update';
|
|
920
964
|
const functionTypeName = `${pascalCase(endpoint.service)}Service_${pascalCase(functionName)}`;
|
|
921
965
|
const functionTypeSource = generateArrowFunctionType({
|
|
922
966
|
type: functionTypeName,
|
|
923
967
|
params: [
|
|
924
968
|
'id: string',
|
|
925
|
-
`data: DeepPartial<${generateRequestBodyType(
|
|
969
|
+
`data: DeepPartial<${generateRequestBodyType(operationObject, context.requestBodies).toString()}>`,
|
|
926
970
|
'options?: UpdateQuery',
|
|
927
971
|
'requestOptions?: RequestOptions'
|
|
928
972
|
],
|
|
929
|
-
returns: `${resolveResponseType(target)}<${
|
|
973
|
+
returns: `${resolveResponseType(options.target)}<${generateResponseType(operationObject, context.responses).toString()}>`
|
|
930
974
|
});
|
|
931
975
|
const functionSource = generateArrowFunction({
|
|
932
976
|
name: functionName,
|
|
@@ -935,102 +979,77 @@ const generateUpdateEndpoint = ({ target, path, endpoint }) => {
|
|
|
935
979
|
params: ['id', 'data', 'options', 'requestOptions?: RequestOptions']
|
|
936
980
|
});
|
|
937
981
|
return {
|
|
938
|
-
entity: pascalCase(endpoint.service),
|
|
939
982
|
name: functionName,
|
|
940
983
|
type: { name: functionTypeName, source: functionTypeSource },
|
|
941
984
|
func: { name: functionName, source: functionSource }
|
|
942
985
|
};
|
|
943
986
|
};
|
|
944
987
|
|
|
945
|
-
const isMultiPartUploadPath = (path) => {
|
|
946
|
-
const [, entity, ...rest] = path.split('/');
|
|
947
|
-
return entity && rest.length === 2 && rest[1] === 'multipartUpload';
|
|
948
|
-
};
|
|
949
|
-
const parseEndpointsAndGroupByEntity = (paths) => {
|
|
950
|
-
const endpoints = new Map();
|
|
951
|
-
for (const [rawPath, path] of Object.entries(paths)) {
|
|
952
|
-
const endpoint = parseEndpointPath(rawPath);
|
|
953
|
-
if (!endpoint || !path) {
|
|
954
|
-
// Todo: Should be removed if sdk supports multi part upload.
|
|
955
|
-
if (isMultiPartUploadPath(rawPath)) {
|
|
956
|
-
continue;
|
|
957
|
-
}
|
|
958
|
-
logger.errorLn(`Failed to parse ${rawPath}`);
|
|
959
|
-
continue;
|
|
960
|
-
}
|
|
961
|
-
if (endpoints.has(endpoint.service)) {
|
|
962
|
-
endpoints.get(endpoint.service)?.push({ endpoint, path });
|
|
963
|
-
}
|
|
964
|
-
else {
|
|
965
|
-
endpoints.set(endpoint.service, [{ endpoint, path }]);
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
return endpoints;
|
|
969
|
-
};
|
|
970
|
-
|
|
971
988
|
const generators = {
|
|
972
989
|
/* /article */
|
|
973
990
|
[WeclappEndpointType.ROOT]: {
|
|
974
|
-
|
|
975
|
-
|
|
991
|
+
[OpenAPIV3.HttpMethods.GET]: generateSomeEndpoint,
|
|
992
|
+
[OpenAPIV3.HttpMethods.POST]: generateCreateEndpoint
|
|
976
993
|
},
|
|
977
994
|
/* /article/count */
|
|
978
995
|
[WeclappEndpointType.COUNT]: {
|
|
979
|
-
|
|
996
|
+
[OpenAPIV3.HttpMethods.GET]: generateCountEndpoint
|
|
980
997
|
},
|
|
981
998
|
/* /article/:id */
|
|
982
999
|
[WeclappEndpointType.ENTITY]: {
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
1000
|
+
[OpenAPIV3.HttpMethods.GET]: generateUniqueEndpoint,
|
|
1001
|
+
[OpenAPIV3.HttpMethods.PUT]: generateUpdateEndpoint,
|
|
1002
|
+
[OpenAPIV3.HttpMethods.DELETE]: generateRemoveEndpoint
|
|
986
1003
|
},
|
|
987
1004
|
/* /article/:id/method */
|
|
988
1005
|
[WeclappEndpointType.GENERIC_ENTITY]: {
|
|
989
|
-
|
|
990
|
-
|
|
1006
|
+
[OpenAPIV3.HttpMethods.GET]: generateGenericEndpoint('ById'),
|
|
1007
|
+
[OpenAPIV3.HttpMethods.POST]: generateGenericEndpoint('ById')
|
|
991
1008
|
},
|
|
992
1009
|
/* /article/method */
|
|
993
1010
|
[WeclappEndpointType.GENERIC_ROOT]: {
|
|
994
|
-
|
|
995
|
-
|
|
1011
|
+
[OpenAPIV3.HttpMethods.GET]: generateGenericEndpoint(),
|
|
1012
|
+
[OpenAPIV3.HttpMethods.POST]: generateGenericEndpoint()
|
|
996
1013
|
}
|
|
997
1014
|
};
|
|
998
|
-
const generateServices = (
|
|
1015
|
+
const generateServices = (entities, context, options) => {
|
|
999
1016
|
const services = new Map();
|
|
1000
|
-
const
|
|
1001
|
-
for (const [serviceName, paths] of endpoints) {
|
|
1017
|
+
for (const [serviceName, serviceEndpoints] of context.endpoints) {
|
|
1002
1018
|
const serviceFnName = camelCase(`${serviceName}Service`);
|
|
1003
1019
|
const serviceTypeName = pascalCase(`${serviceName}Service`);
|
|
1004
1020
|
const functions = [];
|
|
1005
|
-
for (const { path, endpoint } of
|
|
1006
|
-
const
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1021
|
+
for (const { path, endpoint } of serviceEndpoints) {
|
|
1022
|
+
for (const method of [
|
|
1023
|
+
OpenAPIV3.HttpMethods.GET,
|
|
1024
|
+
OpenAPIV3.HttpMethods.POST,
|
|
1025
|
+
OpenAPIV3.HttpMethods.PUT,
|
|
1026
|
+
OpenAPIV3.HttpMethods.DELETE
|
|
1027
|
+
]) {
|
|
1028
|
+
if ((method === OpenAPIV3.HttpMethods.GET &&
|
|
1029
|
+
endpoint.type === WeclappEndpointType.ENTITY &&
|
|
1030
|
+
!options.generateUnique) ||
|
|
1031
|
+
(method === OpenAPIV3.HttpMethods.POST &&
|
|
1032
|
+
(endpoint.type === WeclappEndpointType.COUNT || endpoint.path.endsWith('query')))) {
|
|
1010
1033
|
// Skip unique endpoints if generateUnique option is not set or if POST is used for filter queries
|
|
1011
1034
|
continue;
|
|
1012
1035
|
}
|
|
1013
|
-
const
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
if (!path.deprecated || options.deprecated) {
|
|
1036
|
+
const operationObject = path[method];
|
|
1037
|
+
const generatorFn = generators[endpoint.type][method];
|
|
1038
|
+
if (operationObject && generatorFn) {
|
|
1039
|
+
if (!operationObject.deprecated || options.deprecated) {
|
|
1018
1040
|
functions.push({
|
|
1019
1041
|
...generatorFn({
|
|
1020
|
-
endpoint,
|
|
1021
1042
|
method,
|
|
1022
|
-
|
|
1023
|
-
|
|
1043
|
+
endpoint,
|
|
1044
|
+
operationObject,
|
|
1024
1045
|
entities,
|
|
1025
|
-
|
|
1046
|
+
context,
|
|
1047
|
+
options
|
|
1026
1048
|
}),
|
|
1027
|
-
path
|
|
1049
|
+
path: operationObject
|
|
1028
1050
|
});
|
|
1029
1051
|
}
|
|
1030
1052
|
}
|
|
1031
|
-
else {
|
|
1032
|
-
logger.errorLn(`Failed to generate a function for ${method.toUpperCase()}:${endpoint.type} ${endpoint.path}`);
|
|
1033
|
-
}
|
|
1034
1053
|
}
|
|
1035
1054
|
}
|
|
1036
1055
|
if (!functions.length) {
|
|
@@ -1045,40 +1064,27 @@ const generateServices = (paths, entities, aliases, options) => {
|
|
|
1045
1064
|
}))
|
|
1046
1065
|
])));
|
|
1047
1066
|
const serviceFn = `export const ${serviceFnName} = (cfg?: ServiceConfig): ${serviceTypeName} => ${generateBlockStatements(...functions.map((v) => v.func.source), `return {${concat(functions.map((v) => v.func.name))}};`)};`;
|
|
1067
|
+
const relatedEntityName = context.aliases.get(serviceName);
|
|
1068
|
+
const relatedEntity = relatedEntityName ? entities.get(relatedEntityName) : undefined;
|
|
1048
1069
|
services.set(serviceName, {
|
|
1049
1070
|
name: serviceName,
|
|
1050
1071
|
serviceFnName,
|
|
1051
|
-
serviceTypeName,
|
|
1052
1072
|
functions,
|
|
1053
1073
|
source: generateStatements(serviceTypes, serviceFn),
|
|
1054
|
-
deprecated: functions.every((v) => v.path.deprecated)
|
|
1074
|
+
deprecated: functions.every((v) => v.path.deprecated),
|
|
1075
|
+
relatedEntity
|
|
1055
1076
|
});
|
|
1056
1077
|
}
|
|
1057
1078
|
return services;
|
|
1058
1079
|
};
|
|
1059
1080
|
|
|
1060
|
-
const generateCustomValueServices = (
|
|
1061
|
-
const customValueEntity = entities.get('customValue');
|
|
1081
|
+
const generateCustomValueServices = (services) => {
|
|
1062
1082
|
const customValueEntities = [];
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
serviceLoop: for (const service of services) {
|
|
1068
|
-
const someFunction = service.functions.find((v) => v.name === 'some');
|
|
1069
|
-
if (!someFunction) {
|
|
1070
|
-
continue;
|
|
1071
|
-
}
|
|
1072
|
-
const entity = entities.get(camelCase(someFunction.entity));
|
|
1073
|
-
if (entity?.properties.size !== customValueEntity.properties.size) {
|
|
1074
|
-
continue;
|
|
1075
|
-
}
|
|
1076
|
-
for (const [prop, { type }] of entity.properties) {
|
|
1077
|
-
if (customValueEntity.properties.get(prop)?.type !== type) {
|
|
1078
|
-
continue serviceLoop;
|
|
1079
|
-
}
|
|
1083
|
+
for (const service of services) {
|
|
1084
|
+
const relatedEntity = service.relatedEntity;
|
|
1085
|
+
if (relatedEntity?.name === 'customValue') {
|
|
1086
|
+
customValueEntities.push(service.name);
|
|
1080
1087
|
}
|
|
1081
|
-
customValueEntities.push(service.name);
|
|
1082
1088
|
}
|
|
1083
1089
|
return generateStatements(generateType('WCustomValueService', concat(generateStrings(customValueEntities), ' | ')), `export const wCustomValueServiceNames: WCustomValueService[] = [${concat(generateStrings(customValueEntities))}];`, `export const isWCustomValueService = (service: string | undefined): service is WCustomValueService =>\n${indent('wCustomValueServiceNames.includes(service as WCustomValueService);')}`);
|
|
1084
1090
|
};
|
|
@@ -1123,14 +1129,19 @@ const generatePropertyDescriptors = (entity, entities, services, options) => [..
|
|
|
1123
1129
|
value: value !== undefined ? (typeof value === 'number' ? value : generateString(value)) : undefined
|
|
1124
1130
|
}))
|
|
1125
1131
|
}));
|
|
1126
|
-
const generateEntityProperties = (entities,
|
|
1132
|
+
const generateEntityProperties = (entities, services, options) => {
|
|
1127
1133
|
const typeName = 'WEntityProperties';
|
|
1128
1134
|
const propertyMap = [
|
|
1129
1135
|
...entities.entries(),
|
|
1130
|
-
...
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1136
|
+
...services
|
|
1137
|
+
.filter(({ relatedEntity }) => !!relatedEntity)
|
|
1138
|
+
.filter(({ name }) => !entities.get(name))
|
|
1139
|
+
.map(({ name, relatedEntity }) => {
|
|
1140
|
+
return [name, relatedEntity];
|
|
1141
|
+
})
|
|
1142
|
+
].map(([entityName, entity]) => ({
|
|
1143
|
+
key: entityName,
|
|
1144
|
+
value: generatePropertyDescriptors(entity, entities, services, options)
|
|
1134
1145
|
}));
|
|
1135
1146
|
return generateStatements(`export type ${typeName} = Partial<Record<WEntity, Partial<Record<string, WEntityPropertyMeta>>>>;`, `export const wEntityProperties: ${typeName} = ${generateObject(propertyMap)};`);
|
|
1136
1147
|
};
|
|
@@ -1180,7 +1191,7 @@ const generateGroupedServices = (services) => {
|
|
|
1180
1191
|
}), ...typeGuards);
|
|
1181
1192
|
};
|
|
1182
1193
|
|
|
1183
|
-
const generateMaps = (enums, entities, services,
|
|
1194
|
+
const generateMaps = (enums, entities, services, context, options) => {
|
|
1184
1195
|
const enumInstances = `export const wEnums = ${generateObject([...enums.keys()].map((v) => ({ key: v, value: v })))};`;
|
|
1185
1196
|
const entityNames = `export const wEntityNames: WEntity[] = ${generateArray([...entities.keys()])};`;
|
|
1186
1197
|
const generatedServices = [...services.values()];
|
|
@@ -1194,75 +1205,116 @@ const generateMaps = (enums, entities, services, aliases, options) => {
|
|
|
1194
1205
|
value: v.serviceFnName,
|
|
1195
1206
|
comment: v.deprecated ? '@deprecated' : undefined
|
|
1196
1207
|
})))};`;
|
|
1197
|
-
return
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1208
|
+
return generateStatements(
|
|
1209
|
+
/* Enums */
|
|
1210
|
+
generateInterface('WEnums', [...enums.keys()].map((name) => ({ name, type: name, required: true }))), generateType('WEnum', 'keyof WEnums'), enumInstances,
|
|
1211
|
+
/* Entities */
|
|
1212
|
+
generateInterface('WEntities', [
|
|
1213
|
+
...[...entities.entries()].map(([name, entity]) => ({
|
|
1214
|
+
name,
|
|
1215
|
+
type: entity.interfaceName,
|
|
1216
|
+
required: true
|
|
1217
|
+
})),
|
|
1218
|
+
...generatedServices
|
|
1219
|
+
.filter(({ relatedEntity }) => !!relatedEntity)
|
|
1220
|
+
.filter(({ name }) => !entities.get(name))
|
|
1221
|
+
.map(({ name, relatedEntity }) => ({
|
|
1222
|
+
name,
|
|
1223
|
+
type: relatedEntity.interfaceName,
|
|
1224
|
+
required: true
|
|
1225
|
+
}))
|
|
1226
|
+
].sort((a, b) => (a.name > b.name ? 1 : -1))), generateType('WEntity', 'keyof WEntities'), entityNames,
|
|
1227
|
+
/* Services */
|
|
1228
|
+
serviceInstances, generateType('WServices', 'typeof wServices'), generateType('WService', 'keyof WServices'), serviceFactories, generateType('WServiceFactories', 'typeof wServiceFactories'),
|
|
1229
|
+
/* Service Utils */
|
|
1230
|
+
generateGroupedServices(generatedServices), generateCustomValueServices(generatedServices),
|
|
1231
|
+
/* Entity Properties (Runtime Meta Infos) */
|
|
1232
|
+
generateEntityProperties(entities, generatedServices, options));
|
|
1213
1233
|
};
|
|
1214
1234
|
|
|
1215
|
-
|
|
1216
|
-
const
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1235
|
+
function extractRelatedEntityName(serviceEndpoints, responses) {
|
|
1236
|
+
const rootEndpoint = serviceEndpoints.find((v) => v.endpoint.type === WeclappEndpointType.ROOT);
|
|
1237
|
+
if (!rootEndpoint)
|
|
1238
|
+
return;
|
|
1239
|
+
const response = rootEndpoint?.path.get?.responses['200'];
|
|
1240
|
+
if (!response)
|
|
1241
|
+
return;
|
|
1242
|
+
let responseObject;
|
|
1243
|
+
if (isReferenceObject(response)) {
|
|
1244
|
+
const refName = getRefName(response);
|
|
1245
|
+
responseObject = responses.get(refName);
|
|
1246
|
+
}
|
|
1247
|
+
else {
|
|
1248
|
+
responseObject = response;
|
|
1249
|
+
}
|
|
1250
|
+
const responseSchema = responseObject?.content?.['application/json'].schema;
|
|
1251
|
+
if (responseSchema) {
|
|
1252
|
+
if (isReferenceObject(responseSchema)) {
|
|
1253
|
+
return;
|
|
1222
1254
|
}
|
|
1223
|
-
const
|
|
1224
|
-
if (
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
aliases.set(parsed.service, parseReferencedEntityType(resultSchema));
|
|
1235
|
-
continue;
|
|
1236
|
-
}
|
|
1237
|
-
if (isArraySchemaObject(resultSchema)) {
|
|
1238
|
-
const resultItemSchema = resultSchema.items;
|
|
1239
|
-
if (isReferenceObject(resultItemSchema)) {
|
|
1240
|
-
aliases.set(parsed.service, parseReferencedEntityType(resultItemSchema));
|
|
1241
|
-
}
|
|
1255
|
+
const resultSchema = responseSchema.properties?.result;
|
|
1256
|
+
if (!resultSchema) {
|
|
1257
|
+
return;
|
|
1258
|
+
}
|
|
1259
|
+
if (isReferenceObject(resultSchema)) {
|
|
1260
|
+
return getRefName(resultSchema);
|
|
1261
|
+
}
|
|
1262
|
+
else if (isArraySchemaObject(resultSchema)) {
|
|
1263
|
+
const resultItemSchema = resultSchema.items;
|
|
1264
|
+
if (isReferenceObject(resultItemSchema)) {
|
|
1265
|
+
return getRefName(resultItemSchema);
|
|
1242
1266
|
}
|
|
1243
1267
|
}
|
|
1244
1268
|
}
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
const extractServiceAliases = (endpoints, responses) => {
|
|
1272
|
+
const aliases = new Map();
|
|
1273
|
+
for (const [serviceName, serviceEndpoints] of endpoints) {
|
|
1274
|
+
const relatedEntityName = extractRelatedEntityName(serviceEndpoints, responses);
|
|
1275
|
+
if (relatedEntityName)
|
|
1276
|
+
aliases.set(serviceName, relatedEntityName);
|
|
1277
|
+
}
|
|
1245
1278
|
return aliases;
|
|
1246
1279
|
};
|
|
1247
|
-
const
|
|
1280
|
+
const extractContext = (doc) => {
|
|
1281
|
+
const endpoints = parseEndpointsPaths(doc.paths);
|
|
1248
1282
|
const schemas = new Map();
|
|
1249
1283
|
for (const [name, schema] of Object.entries(doc.components?.schemas ?? {})) {
|
|
1250
1284
|
if (!isReferenceObject(schema)) {
|
|
1251
1285
|
schemas.set(name, schema);
|
|
1252
1286
|
}
|
|
1253
1287
|
}
|
|
1254
|
-
const
|
|
1255
|
-
|
|
1288
|
+
const responses = new Map();
|
|
1289
|
+
for (const [name, response] of Object.entries(doc.components?.responses ?? {})) {
|
|
1290
|
+
if (!isReferenceObject(response)) {
|
|
1291
|
+
responses.set(name, response);
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
const parameters = new Map();
|
|
1295
|
+
for (const [name, parameter] of Object.entries(doc.components?.parameters ?? {})) {
|
|
1296
|
+
if (!isReferenceObject(parameter)) {
|
|
1297
|
+
parameters.set(name, parameter);
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
const requestBodies = new Map();
|
|
1301
|
+
for (const [name, requestBody] of Object.entries(doc.components?.requestBodies ?? {})) {
|
|
1302
|
+
if (!isReferenceObject(requestBody)) {
|
|
1303
|
+
requestBodies.set(name, requestBody);
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
const aliases = extractServiceAliases(endpoints, responses);
|
|
1307
|
+
return { endpoints, schemas, responses, parameters, requestBodies, aliases };
|
|
1256
1308
|
};
|
|
1257
1309
|
|
|
1258
1310
|
const generate = (doc, options) => {
|
|
1259
|
-
const
|
|
1260
|
-
const
|
|
1261
|
-
const
|
|
1262
|
-
const
|
|
1263
|
-
const services = generateServices(
|
|
1264
|
-
const maps = generateMaps(enums, entities, services,
|
|
1265
|
-
return generateStatements(
|
|
1311
|
+
const context = extractContext(doc);
|
|
1312
|
+
const base = generateBase(doc.info.version, options);
|
|
1313
|
+
const enums = generateEnums(context);
|
|
1314
|
+
const entities = generateEntities(context);
|
|
1315
|
+
const services = generateServices(entities, context, options);
|
|
1316
|
+
const maps = generateMaps(enums, entities, services, context, options);
|
|
1317
|
+
return generateStatements(generateBlockComment('BASE', base), generateBlockComment('ENUMS', generateStatements(...[...enums.values()].map((v) => v.source))), generateBlockComment('ENTITIES', generateStatements(...[...entities.values()].map((v) => v.source))), generateBlockComment('FILTERS', generateStatements(...[...entities.values()].map((v) => v.filterSource))), generateBlockComment('SERVICES', generateStatements(...[...services.values()].map((v) => v.source))), generateBlockComment('MAPS', maps));
|
|
1266
1318
|
};
|
|
1267
1319
|
|
|
1268
1320
|
const hash = (content, algorithm = 'sha256') => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weclapp/sdk",
|
|
3
|
-
"version": "2.0.0-dev.
|
|
3
|
+
"version": "2.0.0-dev.51",
|
|
4
4
|
"description": "weclapp SDK Generator",
|
|
5
5
|
"author": "weclapp",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -39,10 +39,14 @@
|
|
|
39
39
|
"scripts": {
|
|
40
40
|
"build": "rollup --config rollup.config.ts --configPlugin typescript={tsconfig:\\'tsconfig.node.json\\'} --configImportAttributesKey with",
|
|
41
41
|
"build:watch": "npm run build -- --watch",
|
|
42
|
-
"cli:browser": "./bin/cli.js test/openapi.json --target browser",
|
|
43
|
-
"cli:browser:
|
|
44
|
-
"cli:browser
|
|
45
|
-
"cli:browser.rx:
|
|
42
|
+
"cli:browser:v1": "./bin/cli.js test/openapi.json --target browser",
|
|
43
|
+
"cli:browser.rx:v1": "./bin/cli.js test/openapi.json --target browser.rx",
|
|
44
|
+
"cli:browser:v2": "./bin/cli.js test/openapi_v2.json --target browser",
|
|
45
|
+
"cli:browser.rx:v2": "./bin/cli.js test/openapi_v2.json --target browser.rx",
|
|
46
|
+
"cli:browser:v3": "./bin/cli.js test/openapi_v3.json --target browser",
|
|
47
|
+
"cli:browser:v3:cache": "./bin/cli.js test/openapi_v3.json --target browser --cache",
|
|
48
|
+
"cli:browser.rx:v3": "./bin/cli.js test/openapi_v3.json --target browser.rx",
|
|
49
|
+
"cli:browser.rx:v3:cache": "./bin/cli.js test/openapi_v3.json --target browser.rx --cache",
|
|
46
50
|
"cli:node": "./bin/cli.js test/openapi.json --target node",
|
|
47
51
|
"cli:node:cache": "./bin/cli.js test/openapi.json --target node --cache",
|
|
48
52
|
"cli:node.rx": "./bin/cli.js test/openapi.json --target node.rx",
|
|
@@ -51,7 +55,7 @@
|
|
|
51
55
|
"prettier:fix": "prettier . --write",
|
|
52
56
|
"lint": "eslint ./src --cache",
|
|
53
57
|
"lint:fix": "npm run lint -- --fix",
|
|
54
|
-
"ci": "npm run prettier && npm run lint && npm run build && npm run cli:browser",
|
|
58
|
+
"ci": "npm run prettier && npm run lint && npm run build && npm run cli:browser:v1 && npm run cli:browser:v2 && npm run cli:browser:v3",
|
|
55
59
|
"release": "standard-version"
|
|
56
60
|
},
|
|
57
61
|
"devDependencies": {
|