@acrool/rtk-query-codegen-openapi 0.0.2 → 0.0.7
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/lib/index.d.mts +8 -4
- package/lib/index.d.ts +8 -4
- package/lib/index.js +460 -124
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +460 -124
- package/lib/index.mjs.map +1 -1
- package/package.json +11 -2
- package/src/generate.ts +365 -142
- package/src/generators/react-hooks.ts +2 -2
- package/src/index.ts +250 -9
- package/src/types.ts +9 -1
package/lib/index.mjs
CHANGED
|
@@ -305,14 +305,14 @@ function removeUndefined(t) {
|
|
|
305
305
|
|
|
306
306
|
// src/generators/react-hooks.ts
|
|
307
307
|
var createBinding = ({
|
|
308
|
-
operationDefinition: { verb, path: path4
|
|
308
|
+
operationDefinition: { verb, path: path4 },
|
|
309
309
|
overrides,
|
|
310
310
|
isLazy = false
|
|
311
311
|
}) => factory.createBindingElement(
|
|
312
312
|
void 0,
|
|
313
313
|
void 0,
|
|
314
314
|
factory.createIdentifier(
|
|
315
|
-
`use${isLazy ? "Lazy" : ""}${capitalize(getOperationName(verb, path4,
|
|
315
|
+
`use${isLazy ? "Lazy" : ""}${capitalize(getOperationName(verb, path4, void 0))}${isQuery(verb, overrides) ? "Query" : "Mutation"}`
|
|
316
316
|
),
|
|
317
317
|
void 0
|
|
318
318
|
);
|
|
@@ -366,8 +366,8 @@ function defaultIsDataResponse(code, includeDefault) {
|
|
|
366
366
|
const parsedCode = Number(code);
|
|
367
367
|
return !Number.isNaN(parsedCode) && parsedCode >= 200 && parsedCode < 300;
|
|
368
368
|
}
|
|
369
|
-
function getOperationName2({ verb, path: path4
|
|
370
|
-
return _getOperationName(verb, path4,
|
|
369
|
+
function getOperationName2({ verb, path: path4 }) {
|
|
370
|
+
return _getOperationName(verb, path4, void 0);
|
|
371
371
|
}
|
|
372
372
|
function getTags({ verb, pathItem }) {
|
|
373
373
|
return verb ? pathItem[verb]?.tags || [] : [];
|
|
@@ -441,41 +441,154 @@ async function generateApi(spec, {
|
|
|
441
441
|
useEnumType,
|
|
442
442
|
mergeReadWriteOnly
|
|
443
443
|
});
|
|
444
|
+
const schemeTypeNames = /* @__PURE__ */ new Set();
|
|
445
|
+
function addSchemeTypeName(name) {
|
|
446
|
+
schemeTypeNames.add(name);
|
|
447
|
+
schemeTypeNames.add(camelCase(name));
|
|
448
|
+
schemeTypeNames.add(capitalize(camelCase(name)));
|
|
449
|
+
}
|
|
444
450
|
if (sharedTypesFile) {
|
|
451
|
+
const resultFile2 = ts4.createSourceFile(
|
|
452
|
+
"sharedTypes.ts",
|
|
453
|
+
"",
|
|
454
|
+
ts4.ScriptTarget.Latest,
|
|
455
|
+
/*setParentNodes*/
|
|
456
|
+
false,
|
|
457
|
+
ts4.ScriptKind.TS
|
|
458
|
+
);
|
|
459
|
+
const printer2 = ts4.createPrinter({ newLine: ts4.NewLineKind.LineFeed });
|
|
460
|
+
const allTypeDefinitions = [];
|
|
461
|
+
const definedTypeNames = /* @__PURE__ */ new Set();
|
|
445
462
|
const components = v3Doc.components;
|
|
446
463
|
if (components) {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
ts4.ScriptKind.TS
|
|
454
|
-
);
|
|
455
|
-
const printer2 = ts4.createPrinter({ newLine: ts4.NewLineKind.LineFeed });
|
|
456
|
-
const typeDefinitions = Object.entries(components).flatMap(([_, componentDefs]) => {
|
|
457
|
-
return Object.entries(componentDefs).map(([name, def]) => {
|
|
458
|
-
const typeNode = apiGen.getTypeFromSchema(def);
|
|
464
|
+
if (components.schemas) {
|
|
465
|
+
const typeEntries = Object.entries(components.schemas).map(([name, def]) => {
|
|
466
|
+
addSchemeTypeName(name);
|
|
467
|
+
const typeName = capitalize(camelCase(name));
|
|
468
|
+
definedTypeNames.add(typeName);
|
|
469
|
+
const typeNode = wrapWithSchemeIfComponent(apiGen.getTypeFromSchema(def));
|
|
459
470
|
return factory.createTypeAliasDeclaration(
|
|
460
471
|
[factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
|
|
461
|
-
factory.createIdentifier(
|
|
472
|
+
factory.createIdentifier(typeName),
|
|
462
473
|
void 0,
|
|
463
474
|
typeNode
|
|
464
475
|
);
|
|
465
476
|
});
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
)
|
|
474
|
-
|
|
477
|
+
allTypeDefinitions.push(
|
|
478
|
+
factory.createModuleDeclaration(
|
|
479
|
+
[factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
|
|
480
|
+
factory.createIdentifier("Scheme"),
|
|
481
|
+
factory.createModuleBlock(typeEntries),
|
|
482
|
+
ts4.NodeFlags.Namespace
|
|
483
|
+
)
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
const enumEntries = [
|
|
488
|
+
...apiGen.enumAliases.filter((e) => ts4.isEnumDeclaration(e)),
|
|
489
|
+
...apiGen.enumAliases.filter((e) => ts4.isTypeAliasDeclaration(e))
|
|
490
|
+
].map((enumDecl) => {
|
|
491
|
+
if (ts4.isEnumDeclaration(enumDecl)) {
|
|
492
|
+
return factory.createEnumDeclaration(
|
|
493
|
+
[factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
|
|
494
|
+
enumDecl.name,
|
|
495
|
+
enumDecl.members
|
|
496
|
+
);
|
|
497
|
+
} else if (ts4.isTypeAliasDeclaration(enumDecl)) {
|
|
498
|
+
return factory.createTypeAliasDeclaration(
|
|
499
|
+
[factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
|
|
500
|
+
enumDecl.name,
|
|
501
|
+
enumDecl.typeParameters,
|
|
502
|
+
enumDecl.type
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
return enumDecl;
|
|
506
|
+
});
|
|
507
|
+
const unionTypeEnums = apiGen.aliases.filter((alias) => {
|
|
508
|
+
if (ts4.isTypeAliasDeclaration(alias) && alias.type) {
|
|
509
|
+
return ts4.isUnionTypeNode(alias.type);
|
|
510
|
+
}
|
|
511
|
+
return false;
|
|
512
|
+
}).map((alias) => {
|
|
513
|
+
if (ts4.isTypeAliasDeclaration(alias)) {
|
|
514
|
+
return factory.createTypeAliasDeclaration(
|
|
515
|
+
[factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
|
|
516
|
+
alias.name,
|
|
517
|
+
alias.typeParameters,
|
|
518
|
+
alias.type
|
|
519
|
+
);
|
|
520
|
+
}
|
|
521
|
+
return alias;
|
|
522
|
+
});
|
|
523
|
+
const allEnumEntries = [...enumEntries, ...unionTypeEnums];
|
|
524
|
+
if (allEnumEntries.length > 0) {
|
|
525
|
+
allTypeDefinitions.push(
|
|
526
|
+
factory.createModuleDeclaration(
|
|
527
|
+
[factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
|
|
528
|
+
factory.createIdentifier("Enum"),
|
|
529
|
+
factory.createModuleBlock(allEnumEntries),
|
|
530
|
+
ts4.NodeFlags.Namespace
|
|
531
|
+
)
|
|
475
532
|
);
|
|
476
|
-
const fs2 = await import("node:fs/promises");
|
|
477
|
-
await fs2.writeFile(sharedTypesFile, output, "utf-8");
|
|
478
533
|
}
|
|
534
|
+
if (apiGen.aliases.length > 0) {
|
|
535
|
+
const aliasEntries = apiGen.aliases.filter((alias) => {
|
|
536
|
+
if (ts4.isTypeAliasDeclaration(alias)) {
|
|
537
|
+
const isDefinedInComponents = definedTypeNames.has(alias.name.text);
|
|
538
|
+
const isUnionTypeEnum = ts4.isUnionTypeNode(alias.type);
|
|
539
|
+
return !isDefinedInComponents && !isUnionTypeEnum;
|
|
540
|
+
}
|
|
541
|
+
return false;
|
|
542
|
+
}).map((alias) => {
|
|
543
|
+
if (ts4.isTypeAliasDeclaration(alias)) {
|
|
544
|
+
return factory.createTypeAliasDeclaration(
|
|
545
|
+
[factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
|
|
546
|
+
alias.name,
|
|
547
|
+
alias.typeParameters,
|
|
548
|
+
alias.type
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
return alias;
|
|
552
|
+
});
|
|
553
|
+
if (aliasEntries.length > 0) {
|
|
554
|
+
const existingSchemeIndex = allTypeDefinitions.findIndex(
|
|
555
|
+
(def) => ts4.isModuleDeclaration(def) && ts4.isIdentifier(def.name) && def.name.text === "Scheme"
|
|
556
|
+
);
|
|
557
|
+
if (existingSchemeIndex >= 0) {
|
|
558
|
+
const existingScheme = allTypeDefinitions[existingSchemeIndex];
|
|
559
|
+
const mergedMembers = [...existingScheme.body.statements, ...aliasEntries];
|
|
560
|
+
allTypeDefinitions[existingSchemeIndex] = factory.createModuleDeclaration(
|
|
561
|
+
[factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
|
|
562
|
+
factory.createIdentifier("Scheme"),
|
|
563
|
+
factory.createModuleBlock(mergedMembers),
|
|
564
|
+
ts4.NodeFlags.Namespace
|
|
565
|
+
);
|
|
566
|
+
} else {
|
|
567
|
+
allTypeDefinitions.push(
|
|
568
|
+
factory.createModuleDeclaration(
|
|
569
|
+
[factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
|
|
570
|
+
factory.createIdentifier("Scheme"),
|
|
571
|
+
factory.createModuleBlock(aliasEntries),
|
|
572
|
+
ts4.NodeFlags.Namespace
|
|
573
|
+
)
|
|
574
|
+
);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
const fs2 = await import("node:fs/promises");
|
|
579
|
+
const path4 = await import("node:path");
|
|
580
|
+
const sharedTypesDir = path4.dirname(sharedTypesFile);
|
|
581
|
+
await fs2.mkdir(sharedTypesDir, { recursive: true });
|
|
582
|
+
const output = printer2.printNode(
|
|
583
|
+
ts4.EmitHint.Unspecified,
|
|
584
|
+
factory.createSourceFile(
|
|
585
|
+
allTypeDefinitions,
|
|
586
|
+
factory.createToken(ts4.SyntaxKind.EndOfFileToken),
|
|
587
|
+
ts4.NodeFlags.None
|
|
588
|
+
),
|
|
589
|
+
resultFile2
|
|
590
|
+
);
|
|
591
|
+
await fs2.writeFile(sharedTypesFile, output, "utf-8");
|
|
479
592
|
}
|
|
480
593
|
if (apiGen.spec.components?.schemas) {
|
|
481
594
|
apiGen.preprocessComponents(apiGen.spec.components.schemas);
|
|
@@ -506,16 +619,13 @@ async function generateApi(spec, {
|
|
|
506
619
|
apiFile = apiFile.replace(/\\/g, "/");
|
|
507
620
|
if (!apiFile.startsWith(".")) apiFile = `./${apiFile}`;
|
|
508
621
|
}
|
|
509
|
-
if (sharedTypesFile && sharedTypesFile.startsWith(".")) {
|
|
510
|
-
sharedTypesFile = path2.relative(path2.dirname(outputFile), sharedTypesFile);
|
|
511
|
-
sharedTypesFile = sharedTypesFile.replace(/\\/g, "/");
|
|
512
|
-
if (!sharedTypesFile.startsWith(".")) sharedTypesFile = `./${sharedTypesFile}`;
|
|
513
|
-
}
|
|
514
622
|
}
|
|
515
623
|
apiFile = apiFile.replace(/\.[jt]sx?$/, "");
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
624
|
+
const sharedTypesImportPath = sharedTypesFile && outputFile ? (() => {
|
|
625
|
+
let rel = path2.relative(path2.dirname(outputFile), sharedTypesFile).replace(/\\/g, "/").replace(/\.[jt]sx?$/, "");
|
|
626
|
+
if (!rel.startsWith(".")) rel = "./" + rel;
|
|
627
|
+
return rel;
|
|
628
|
+
})() : "./shared-types";
|
|
519
629
|
return printer.printNode(
|
|
520
630
|
ts4.EmitHint.Unspecified,
|
|
521
631
|
factory.createSourceFile(
|
|
@@ -523,16 +633,10 @@ async function generateApi(spec, {
|
|
|
523
633
|
generateImportNode(apiFile, { [apiImport]: "api" }),
|
|
524
634
|
generateImportNode("@acrool/react-fetcher", { IRestFulEndpointsQueryReturn: "IRestFulEndpointsQueryReturn" }),
|
|
525
635
|
...sharedTypesFile ? [
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
void 0,
|
|
531
|
-
factory.createNamespaceImport(factory.createIdentifier("SharedTypes"))
|
|
532
|
-
),
|
|
533
|
-
factory.createStringLiteral(sharedTypesFile),
|
|
534
|
-
void 0
|
|
535
|
-
)
|
|
636
|
+
generateImportNode(sharedTypesImportPath, {
|
|
637
|
+
Scheme: "Scheme",
|
|
638
|
+
...useEnumType ? { Enum: "Enum" } : {}
|
|
639
|
+
})
|
|
536
640
|
] : [],
|
|
537
641
|
...tag ? [generateTagTypes({ addTagTypes: extractAllTagTypes({ operationDefinitions }) })] : [],
|
|
538
642
|
generateCreateApiCall({
|
|
@@ -541,17 +645,14 @@ async function generateApi(spec, {
|
|
|
541
645
|
operationDefinitions.map(
|
|
542
646
|
(operationDefinition) => generateEndpoint({
|
|
543
647
|
operationDefinition,
|
|
544
|
-
overrides: getOverrides(operationDefinition, endpointOverrides)
|
|
648
|
+
overrides: getOverrides(operationDefinition, endpointOverrides),
|
|
649
|
+
sharedTypesFile: !!sharedTypesFile
|
|
545
650
|
})
|
|
546
651
|
),
|
|
547
652
|
true
|
|
548
653
|
)
|
|
549
654
|
}),
|
|
550
|
-
factory.createExportAssignment(
|
|
551
|
-
void 0,
|
|
552
|
-
void 0,
|
|
553
|
-
factory.createIdentifier(generatedApiName)
|
|
554
|
-
),
|
|
655
|
+
factory.createExportAssignment(void 0, void 0, factory.createIdentifier(generatedApiName)),
|
|
555
656
|
...Object.values(interfaces),
|
|
556
657
|
...sharedTypesFile ? [] : [...apiGen.aliases, ...apiGen.enumAliases],
|
|
557
658
|
...hooks ? [
|
|
@@ -580,7 +681,8 @@ async function generateApi(spec, {
|
|
|
580
681
|
}
|
|
581
682
|
function generateEndpoint({
|
|
582
683
|
operationDefinition,
|
|
583
|
-
overrides
|
|
684
|
+
overrides,
|
|
685
|
+
sharedTypesFile: sharedTypesFile2
|
|
584
686
|
}) {
|
|
585
687
|
const {
|
|
586
688
|
verb,
|
|
@@ -589,60 +691,30 @@ async function generateApi(spec, {
|
|
|
589
691
|
operation,
|
|
590
692
|
operation: { responses, requestBody }
|
|
591
693
|
} = operationDefinition;
|
|
592
|
-
const operationName = getOperationName2({ verb, path: path4
|
|
694
|
+
const operationName = getOperationName2({ verb, path: path4 });
|
|
593
695
|
const tags = tag ? getTags({ verb, pathItem }) : [];
|
|
594
696
|
const isQuery2 = isQuery(verb, overrides);
|
|
595
697
|
const returnsJson = apiGen.getResponseType(responses) === "json";
|
|
596
698
|
let ResponseType = factory.createKeywordTypeNode(ts4.SyntaxKind.UnknownKeyword);
|
|
597
|
-
function replaceReferences(schema) {
|
|
598
|
-
if (!schema) return factory.createKeywordTypeNode(ts4.SyntaxKind.UnknownKeyword);
|
|
599
|
-
const refName = getReferenceName(schema);
|
|
600
|
-
if (refName && sharedTypesFile) {
|
|
601
|
-
return factory.createTypeReferenceNode(
|
|
602
|
-
factory.createQualifiedName(
|
|
603
|
-
factory.createIdentifier("SharedTypes"),
|
|
604
|
-
factory.createIdentifier(refName)
|
|
605
|
-
),
|
|
606
|
-
void 0
|
|
607
|
-
);
|
|
608
|
-
}
|
|
609
|
-
if (schema.type === "object" && schema.properties) {
|
|
610
|
-
const members = Object.entries(schema.properties).map(([key, value]) => {
|
|
611
|
-
return factory.createPropertySignature(
|
|
612
|
-
void 0,
|
|
613
|
-
factory.createIdentifier(key),
|
|
614
|
-
schema.required?.includes(key) ? void 0 : factory.createToken(ts4.SyntaxKind.QuestionToken),
|
|
615
|
-
replaceReferences(value)
|
|
616
|
-
);
|
|
617
|
-
});
|
|
618
|
-
return factory.createTypeLiteralNode(members);
|
|
619
|
-
}
|
|
620
|
-
if (schema.type === "array" && schema.items) {
|
|
621
|
-
return factory.createArrayTypeNode(replaceReferences(schema.items));
|
|
622
|
-
}
|
|
623
|
-
return apiGen.getTypeFromSchema(schema);
|
|
624
|
-
}
|
|
625
699
|
if (returnsJson) {
|
|
626
700
|
const returnTypes = Object.entries(responses || {}).map(
|
|
627
|
-
([code, response]) =>
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
return [code, resolvedResponse, type];
|
|
635
|
-
}
|
|
701
|
+
([code, response]) => [
|
|
702
|
+
code,
|
|
703
|
+
apiGen.resolve(response),
|
|
704
|
+
wrapWithSchemeIfComponent(
|
|
705
|
+
apiGen.getTypeFromResponse(response, "readOnly") || factory.createKeywordTypeNode(ts4.SyntaxKind.UndefinedKeyword)
|
|
706
|
+
)
|
|
707
|
+
]
|
|
636
708
|
).filter(
|
|
637
709
|
([status, response]) => isDataResponse(status, includeDefault, apiGen.resolve(response), responses || {})
|
|
638
|
-
).filter(([_1, _2, type]) => type !== keywordType.void).map(
|
|
639
|
-
|
|
640
|
-
|
|
710
|
+
).filter(([_1, _2, type]) => type !== keywordType.void).map(([code, response, type]) => {
|
|
711
|
+
return ts4.addSyntheticLeadingComment(
|
|
712
|
+
type,
|
|
641
713
|
ts4.SyntaxKind.MultiLineCommentTrivia,
|
|
642
714
|
`* status ${code} ${response.description} `,
|
|
643
715
|
false
|
|
644
|
-
)
|
|
645
|
-
);
|
|
716
|
+
);
|
|
717
|
+
});
|
|
646
718
|
if (returnTypes.length > 0) {
|
|
647
719
|
ResponseType = factory.createUnionTypeNode(returnTypes);
|
|
648
720
|
}
|
|
@@ -677,10 +749,23 @@ async function generateApi(spec, {
|
|
|
677
749
|
}
|
|
678
750
|
return name;
|
|
679
751
|
}
|
|
752
|
+
for (const param of parameters) {
|
|
753
|
+
const name = generateName(param.name, param.in);
|
|
754
|
+
queryArg[name] = {
|
|
755
|
+
origin: "param",
|
|
756
|
+
name,
|
|
757
|
+
originalName: param.name,
|
|
758
|
+
type: wrapWithSchemeIfComponent(
|
|
759
|
+
apiGen.getTypeFromSchema(isReference(param) ? param : param.schema, void 0, "writeOnly")
|
|
760
|
+
),
|
|
761
|
+
required: param.required,
|
|
762
|
+
param
|
|
763
|
+
};
|
|
764
|
+
}
|
|
680
765
|
if (requestBody) {
|
|
681
766
|
const body = apiGen.resolve(requestBody);
|
|
682
767
|
const schema = apiGen.getSchemaFromContent(body.content);
|
|
683
|
-
const type =
|
|
768
|
+
const type = wrapWithSchemeIfComponent(apiGen.getTypeFromSchema(schema));
|
|
684
769
|
const schemaName = camelCase(
|
|
685
770
|
type.name || getReferenceName(schema) || typeof schema === "object" && "title" in schema && schema.title || "body"
|
|
686
771
|
);
|
|
@@ -689,24 +774,11 @@ async function generateApi(spec, {
|
|
|
689
774
|
origin: "body",
|
|
690
775
|
name,
|
|
691
776
|
originalName: schemaName,
|
|
692
|
-
type,
|
|
777
|
+
type: wrapWithSchemeIfComponent(apiGen.getTypeFromSchema(schema, void 0, "writeOnly")),
|
|
693
778
|
required: true,
|
|
694
779
|
body
|
|
695
780
|
};
|
|
696
781
|
}
|
|
697
|
-
for (const param of parameters) {
|
|
698
|
-
const name = generateName(param.name, param.in);
|
|
699
|
-
const paramSchema = isReference(param) ? param : param.schema;
|
|
700
|
-
const type = replaceReferences(paramSchema);
|
|
701
|
-
queryArg[name] = {
|
|
702
|
-
origin: "param",
|
|
703
|
-
name,
|
|
704
|
-
originalName: param.name,
|
|
705
|
-
type,
|
|
706
|
-
required: param.required,
|
|
707
|
-
param
|
|
708
|
-
};
|
|
709
|
-
}
|
|
710
782
|
const propertyName = (name) => {
|
|
711
783
|
if (typeof name === "string") {
|
|
712
784
|
return isValidIdentifier(name) ? factory.createIdentifier(name) : factory.createStringLiteral(name);
|
|
@@ -749,10 +821,7 @@ async function generateApi(spec, {
|
|
|
749
821
|
operationName: operationNameSuffix ? capitalize(operationName + operationNameSuffix) : operationName,
|
|
750
822
|
type: isQuery2 ? "query" : "mutation",
|
|
751
823
|
Response: ResponseTypeName,
|
|
752
|
-
QueryArg: factory.createTypeReferenceNode(
|
|
753
|
-
factory.createIdentifier("IRestFulEndpointsQueryReturn"),
|
|
754
|
-
[QueryArg]
|
|
755
|
-
),
|
|
824
|
+
QueryArg: factory.createTypeReferenceNode(factory.createIdentifier("IRestFulEndpointsQueryReturn"), [QueryArg]),
|
|
756
825
|
queryFn: generateQueryFn({
|
|
757
826
|
operationDefinition,
|
|
758
827
|
queryArg,
|
|
@@ -773,10 +842,18 @@ async function generateApi(spec, {
|
|
|
773
842
|
encodePathParams: encodePathParams2,
|
|
774
843
|
encodeQueryParams: encodeQueryParams2
|
|
775
844
|
}) {
|
|
776
|
-
const { path: path4, verb } = operationDefinition;
|
|
845
|
+
const { path: path4, verb, operation } = operationDefinition;
|
|
777
846
|
const bodyParameter = Object.values(queryArg).find((def) => def.origin === "body");
|
|
778
847
|
const rootObject = factory.createIdentifier("queryArg");
|
|
779
848
|
const variablesObject = factory.createPropertyAccessExpression(rootObject, factory.createIdentifier("variables"));
|
|
849
|
+
function getContentType() {
|
|
850
|
+
if (operation.requestBody) {
|
|
851
|
+
const requestBody = apiGen.resolve(operation.requestBody);
|
|
852
|
+
const contentTypes = Object.keys(requestBody.content || {});
|
|
853
|
+
return contentTypes[0];
|
|
854
|
+
}
|
|
855
|
+
return void 0;
|
|
856
|
+
}
|
|
780
857
|
function pickParams(paramIn) {
|
|
781
858
|
return Object.values(queryArg).filter((def) => def.origin === "param" && def.param.in === paramIn);
|
|
782
859
|
}
|
|
@@ -800,6 +877,7 @@ async function generateApi(spec, {
|
|
|
800
877
|
factory.createObjectLiteralExpression(properties, true)
|
|
801
878
|
);
|
|
802
879
|
}
|
|
880
|
+
const contentType = getContentType();
|
|
803
881
|
return factory.createArrowFunction(
|
|
804
882
|
void 0,
|
|
805
883
|
void 0,
|
|
@@ -817,9 +895,16 @@ async function generateApi(spec, {
|
|
|
817
895
|
factory.createIdentifier("method"),
|
|
818
896
|
factory.createStringLiteral(verb.toUpperCase())
|
|
819
897
|
),
|
|
898
|
+
contentType ? factory.createPropertyAssignment(
|
|
899
|
+
factory.createIdentifier("contentType"),
|
|
900
|
+
factory.createStringLiteral(contentType)
|
|
901
|
+
) : void 0,
|
|
820
902
|
bodyParameter === void 0 ? void 0 : factory.createPropertyAssignment(
|
|
821
903
|
factory.createIdentifier("body"),
|
|
822
|
-
isFlatArg ? variablesObject : factory.createPropertyAccessExpression(
|
|
904
|
+
isFlatArg ? variablesObject : factory.createPropertyAccessExpression(
|
|
905
|
+
variablesObject,
|
|
906
|
+
factory.createIdentifier(bodyParameter.name)
|
|
907
|
+
)
|
|
823
908
|
),
|
|
824
909
|
createObjectLiteralProperty(pickParams("cookie"), "cookies"),
|
|
825
910
|
createObjectLiteralProperty(pickParams("query"), "params"),
|
|
@@ -843,6 +928,99 @@ async function generateApi(spec, {
|
|
|
843
928
|
function generateMutationEndpointProps({}) {
|
|
844
929
|
return {};
|
|
845
930
|
}
|
|
931
|
+
function wrapWithSchemeIfComponent(typeNode) {
|
|
932
|
+
if (ts4.isTypeReferenceNode(typeNode) && ts4.isIdentifier(typeNode.typeName)) {
|
|
933
|
+
const typeName = typeNode.typeName.text;
|
|
934
|
+
const isEnumType = useEnumType && (apiGen.enumAliases.some((enumDecl) => {
|
|
935
|
+
if (ts4.isEnumDeclaration(enumDecl) || ts4.isTypeAliasDeclaration(enumDecl)) {
|
|
936
|
+
return enumDecl.name.text === typeName;
|
|
937
|
+
}
|
|
938
|
+
return false;
|
|
939
|
+
}) || apiGen.aliases.some((alias) => {
|
|
940
|
+
if (ts4.isTypeAliasDeclaration(alias) && alias.type) {
|
|
941
|
+
if (ts4.isUnionTypeNode(alias.type)) {
|
|
942
|
+
return alias.name.text === typeName;
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
return false;
|
|
946
|
+
}));
|
|
947
|
+
if (isEnumType) {
|
|
948
|
+
return factory.createTypeReferenceNode(
|
|
949
|
+
factory.createQualifiedName(factory.createIdentifier("Enum"), typeNode.typeName),
|
|
950
|
+
typeNode.typeArguments?.map(wrapWithSchemeIfComponent)
|
|
951
|
+
);
|
|
952
|
+
}
|
|
953
|
+
if (schemeTypeNames.has(typeName)) {
|
|
954
|
+
return factory.createTypeReferenceNode(
|
|
955
|
+
factory.createQualifiedName(factory.createIdentifier("Scheme"), typeNode.typeName),
|
|
956
|
+
typeNode.typeArguments?.map(wrapWithSchemeIfComponent)
|
|
957
|
+
);
|
|
958
|
+
}
|
|
959
|
+
if (typeNode.typeArguments) {
|
|
960
|
+
return factory.createTypeReferenceNode(
|
|
961
|
+
typeNode.typeName,
|
|
962
|
+
typeNode.typeArguments.map(wrapWithSchemeIfComponent)
|
|
963
|
+
);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
if (ts4.isArrayTypeNode(typeNode)) {
|
|
967
|
+
return factory.createArrayTypeNode(wrapWithSchemeIfComponent(typeNode.elementType));
|
|
968
|
+
}
|
|
969
|
+
if (ts4.isUnionTypeNode(typeNode)) {
|
|
970
|
+
const unionTypes = typeNode.types;
|
|
971
|
+
if (unionTypes.length > 0 && unionTypes.every(
|
|
972
|
+
(type) => ts4.isLiteralTypeNode(type) && (ts4.isStringLiteral(type.literal) || ts4.isNumericLiteral(type.literal))
|
|
973
|
+
)) {
|
|
974
|
+
const enumValues = unionTypes.map((type) => {
|
|
975
|
+
if (ts4.isLiteralTypeNode(type)) {
|
|
976
|
+
if (ts4.isStringLiteral(type.literal)) {
|
|
977
|
+
return type.literal.text;
|
|
978
|
+
} else if (ts4.isNumericLiteral(type.literal)) {
|
|
979
|
+
return type.literal.text;
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
return null;
|
|
983
|
+
}).filter(Boolean);
|
|
984
|
+
const matchingEnum = apiGen.aliases.find((alias) => {
|
|
985
|
+
if (ts4.isTypeAliasDeclaration(alias) && ts4.isUnionTypeNode(alias.type)) {
|
|
986
|
+
const aliasValues = alias.type.types.map((type) => {
|
|
987
|
+
if (ts4.isLiteralTypeNode(type)) {
|
|
988
|
+
if (ts4.isStringLiteral(type.literal)) {
|
|
989
|
+
return type.literal.text;
|
|
990
|
+
} else if (ts4.isNumericLiteral(type.literal)) {
|
|
991
|
+
return type.literal.text;
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
return null;
|
|
995
|
+
}).filter(Boolean);
|
|
996
|
+
return aliasValues.length === enumValues.length && aliasValues.every((val) => enumValues.includes(val));
|
|
997
|
+
}
|
|
998
|
+
return false;
|
|
999
|
+
});
|
|
1000
|
+
if (matchingEnum && ts4.isTypeAliasDeclaration(matchingEnum)) {
|
|
1001
|
+
return typeNode;
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
return factory.createUnionTypeNode(typeNode.types.map(wrapWithSchemeIfComponent));
|
|
1005
|
+
}
|
|
1006
|
+
if (ts4.isTypeLiteralNode(typeNode)) {
|
|
1007
|
+
return factory.createTypeLiteralNode(
|
|
1008
|
+
typeNode.members.map((member) => {
|
|
1009
|
+
if (ts4.isPropertySignature(member) && member.type) {
|
|
1010
|
+
return factory.updatePropertySignature(
|
|
1011
|
+
member,
|
|
1012
|
+
member.modifiers,
|
|
1013
|
+
member.name,
|
|
1014
|
+
member.questionToken,
|
|
1015
|
+
wrapWithSchemeIfComponent(member.type)
|
|
1016
|
+
);
|
|
1017
|
+
}
|
|
1018
|
+
return member;
|
|
1019
|
+
})
|
|
1020
|
+
);
|
|
1021
|
+
}
|
|
1022
|
+
return typeNode;
|
|
1023
|
+
}
|
|
846
1024
|
}
|
|
847
1025
|
function generatePathExpression(path4, pathParameters, rootObject, isFlatArg, encodePathParams) {
|
|
848
1026
|
const expressions = [];
|
|
@@ -870,8 +1048,115 @@ function generatePathExpression(path4, pathParameters, rootObject, isFlatArg, en
|
|
|
870
1048
|
}
|
|
871
1049
|
|
|
872
1050
|
// src/index.ts
|
|
1051
|
+
import camelCase2 from "lodash.camelcase";
|
|
873
1052
|
var require2 = createRequire(__filename);
|
|
1053
|
+
async function ensureDirectoryExists(filePath) {
|
|
1054
|
+
const dirname = path3.dirname(filePath);
|
|
1055
|
+
if (!fs.existsSync(dirname)) {
|
|
1056
|
+
await fs.promises.mkdir(dirname, { recursive: true });
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
function fileExists(filePath) {
|
|
1060
|
+
try {
|
|
1061
|
+
return fs.statSync(filePath).isFile();
|
|
1062
|
+
} catch {
|
|
1063
|
+
return false;
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
function getApiNameFromDir(dirPath) {
|
|
1067
|
+
const dirName = path3.basename(dirPath);
|
|
1068
|
+
return `${dirName}Api`;
|
|
1069
|
+
}
|
|
1070
|
+
async function ensureBaseFilesExist(outputDir) {
|
|
1071
|
+
const enhanceEndpointsPath = path3.join(outputDir, "enhanceEndpoints.ts");
|
|
1072
|
+
const indexPath = path3.join(outputDir, "index.ts");
|
|
1073
|
+
const apiName = getApiNameFromDir(outputDir);
|
|
1074
|
+
if (!fileExists(enhanceEndpointsPath)) {
|
|
1075
|
+
const enhanceEndpointsContent = `import api from './query.generated';
|
|
1076
|
+
|
|
1077
|
+
const enhancedApi = api.enhanceEndpoints({
|
|
1078
|
+
endpoints: {
|
|
1079
|
+
},
|
|
1080
|
+
});
|
|
1081
|
+
|
|
1082
|
+
export default enhancedApi;
|
|
1083
|
+
`;
|
|
1084
|
+
await fs.promises.writeFile(enhanceEndpointsPath, enhanceEndpointsContent, "utf-8");
|
|
1085
|
+
}
|
|
1086
|
+
if (!fileExists(indexPath)) {
|
|
1087
|
+
const indexContent = `export * from './query.generated';
|
|
1088
|
+
export {default as ${apiName}} from './enhanceEndpoints';
|
|
1089
|
+
`;
|
|
1090
|
+
await fs.promises.writeFile(indexPath, indexContent, "utf-8");
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
function getGroupNameFromPath(path4, pattern) {
|
|
1094
|
+
const match = path4.match(pattern);
|
|
1095
|
+
if (match && match[1]) {
|
|
1096
|
+
return camelCase2(match[1]);
|
|
1097
|
+
}
|
|
1098
|
+
return "common";
|
|
1099
|
+
}
|
|
874
1100
|
async function generateEndpoints(options) {
|
|
1101
|
+
const schemaLocation = options.schemaFile;
|
|
1102
|
+
const schemaAbsPath = isValidUrl(options.schemaFile) ? options.schemaFile : path3.resolve(process.cwd(), schemaLocation);
|
|
1103
|
+
if (isValidUrl(options.schemaFile) && "outputFiles" in options) {
|
|
1104
|
+
const { outputFiles, ...commonConfig } = options;
|
|
1105
|
+
const openApiDoc = await getV3Doc(options.schemaFile, options.httpResolverOptions);
|
|
1106
|
+
const paths = Object.keys(openApiDoc.paths);
|
|
1107
|
+
const outputFilesEntries = Object.entries(outputFiles);
|
|
1108
|
+
const [outputPath, config] = outputFilesEntries[0];
|
|
1109
|
+
const patterns = config.groupMatch;
|
|
1110
|
+
const filterEndpoint = config.filterEndpoint;
|
|
1111
|
+
const pattern = patterns;
|
|
1112
|
+
const groupedPaths = paths.reduce((acc, path4) => {
|
|
1113
|
+
const groupName = getGroupNameFromPath(path4, pattern);
|
|
1114
|
+
if (!acc[groupName]) {
|
|
1115
|
+
acc[groupName] = [];
|
|
1116
|
+
}
|
|
1117
|
+
acc[groupName].push(path4);
|
|
1118
|
+
return acc;
|
|
1119
|
+
}, {});
|
|
1120
|
+
for (const [groupName, paths2] of Object.entries(groupedPaths)) {
|
|
1121
|
+
const finalOutputPath = outputPath.replace("$1", groupName);
|
|
1122
|
+
if (filterEndpoint) {
|
|
1123
|
+
const pathBasedFilter = (operationName, operationDefinition) => {
|
|
1124
|
+
const path4 = operationDefinition.path;
|
|
1125
|
+
const pathGroupName = getGroupNameFromPath(path4, pattern);
|
|
1126
|
+
if (pathGroupName !== groupName) {
|
|
1127
|
+
return false;
|
|
1128
|
+
}
|
|
1129
|
+
const endpointFilter = filterEndpoint(groupName);
|
|
1130
|
+
if (endpointFilter instanceof RegExp) {
|
|
1131
|
+
return endpointFilter.test(operationName);
|
|
1132
|
+
}
|
|
1133
|
+
return true;
|
|
1134
|
+
};
|
|
1135
|
+
const groupOptions = {
|
|
1136
|
+
...commonConfig,
|
|
1137
|
+
outputFile: finalOutputPath,
|
|
1138
|
+
filterEndpoints: pathBasedFilter
|
|
1139
|
+
};
|
|
1140
|
+
await generateSingleEndpoint(groupOptions);
|
|
1141
|
+
} else {
|
|
1142
|
+
const pathBasedFilter = (operationName, operationDefinition) => {
|
|
1143
|
+
const path4 = operationDefinition.path;
|
|
1144
|
+
const pathGroupName = getGroupNameFromPath(path4, pattern);
|
|
1145
|
+
return pathGroupName === groupName;
|
|
1146
|
+
};
|
|
1147
|
+
const groupOptions = {
|
|
1148
|
+
...commonConfig,
|
|
1149
|
+
outputFile: finalOutputPath,
|
|
1150
|
+
filterEndpoints: pathBasedFilter
|
|
1151
|
+
};
|
|
1152
|
+
await generateSingleEndpoint(groupOptions);
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
return;
|
|
1156
|
+
}
|
|
1157
|
+
await generateSingleEndpoint(options);
|
|
1158
|
+
}
|
|
1159
|
+
async function generateSingleEndpoint(options) {
|
|
875
1160
|
const schemaLocation = options.schemaFile;
|
|
876
1161
|
const schemaAbsPath = isValidUrl(options.schemaFile) ? options.schemaFile : path3.resolve(process.cwd(), schemaLocation);
|
|
877
1162
|
const sourceCode = await enforceOazapftsTsVersion(async () => {
|
|
@@ -879,8 +1164,12 @@ async function generateEndpoints(options) {
|
|
|
879
1164
|
});
|
|
880
1165
|
const { outputFile, prettierConfigFile } = options;
|
|
881
1166
|
if (outputFile) {
|
|
1167
|
+
const outputPath = path3.resolve(process.cwd(), outputFile);
|
|
1168
|
+
await ensureDirectoryExists(outputPath);
|
|
1169
|
+
const outputDir = path3.dirname(outputPath);
|
|
1170
|
+
await ensureBaseFilesExist(outputDir);
|
|
882
1171
|
fs.writeFileSync(
|
|
883
|
-
|
|
1172
|
+
outputPath,
|
|
884
1173
|
await prettify(outputFile, sourceCode, prettierConfigFile)
|
|
885
1174
|
);
|
|
886
1175
|
} else {
|
|
@@ -891,13 +1180,60 @@ function parseConfig(fullConfig) {
|
|
|
891
1180
|
const outFiles = [];
|
|
892
1181
|
if ("outputFiles" in fullConfig) {
|
|
893
1182
|
const { outputFiles, ...commonConfig } = fullConfig;
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
1183
|
+
let openApiDoc;
|
|
1184
|
+
if (isValidUrl(fullConfig.schemaFile)) {
|
|
1185
|
+
outFiles.push(fullConfig);
|
|
1186
|
+
return outFiles;
|
|
1187
|
+
} else {
|
|
1188
|
+
openApiDoc = JSON.parse(fs.readFileSync(fullConfig.schemaFile, "utf-8"));
|
|
900
1189
|
}
|
|
1190
|
+
const paths = Object.keys(openApiDoc.paths);
|
|
1191
|
+
const outputFilesEntries = Object.entries(outputFiles);
|
|
1192
|
+
const [outputPath, config] = outputFilesEntries[0];
|
|
1193
|
+
const patterns = config.groupMatch;
|
|
1194
|
+
const filterEndpoint = config.filterEndpoint;
|
|
1195
|
+
const pattern = patterns;
|
|
1196
|
+
const groupedPaths = paths.reduce((acc, path4) => {
|
|
1197
|
+
const groupName = getGroupNameFromPath(path4, pattern);
|
|
1198
|
+
if (!acc[groupName]) {
|
|
1199
|
+
acc[groupName] = [];
|
|
1200
|
+
}
|
|
1201
|
+
acc[groupName].push(path4);
|
|
1202
|
+
return acc;
|
|
1203
|
+
}, {});
|
|
1204
|
+
Object.entries(groupedPaths).forEach(([groupName, paths2]) => {
|
|
1205
|
+
const finalOutputPath = outputPath.replace("$1", groupName);
|
|
1206
|
+
if (filterEndpoint) {
|
|
1207
|
+
const pathBasedFilter = (operationName, operationDefinition) => {
|
|
1208
|
+
const path4 = operationDefinition.path;
|
|
1209
|
+
const pathGroupName = getGroupNameFromPath(path4, pattern);
|
|
1210
|
+
if (pathGroupName !== groupName) {
|
|
1211
|
+
return false;
|
|
1212
|
+
}
|
|
1213
|
+
const endpointFilter = filterEndpoint(groupName);
|
|
1214
|
+
if (endpointFilter instanceof RegExp) {
|
|
1215
|
+
return endpointFilter.test(operationName);
|
|
1216
|
+
}
|
|
1217
|
+
return true;
|
|
1218
|
+
};
|
|
1219
|
+
outFiles.push({
|
|
1220
|
+
...commonConfig,
|
|
1221
|
+
outputFile: finalOutputPath,
|
|
1222
|
+
filterEndpoints: pathBasedFilter
|
|
1223
|
+
});
|
|
1224
|
+
} else {
|
|
1225
|
+
const pathBasedFilter = (operationName, operationDefinition) => {
|
|
1226
|
+
const path4 = operationDefinition.path;
|
|
1227
|
+
const pathGroupName = getGroupNameFromPath(path4, pattern);
|
|
1228
|
+
return pathGroupName === groupName;
|
|
1229
|
+
};
|
|
1230
|
+
outFiles.push({
|
|
1231
|
+
...commonConfig,
|
|
1232
|
+
outputFile: finalOutputPath,
|
|
1233
|
+
filterEndpoints: pathBasedFilter
|
|
1234
|
+
});
|
|
1235
|
+
}
|
|
1236
|
+
});
|
|
901
1237
|
} else {
|
|
902
1238
|
outFiles.push(fullConfig);
|
|
903
1239
|
}
|