@acrool/rtk-query-codegen-openapi 0.0.2-test.1 → 0.0.2-test.2

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.mjs CHANGED
@@ -9,11 +9,17 @@ import { createRequire } from "node:module";
9
9
  import path3 from "node:path";
10
10
 
11
11
  // src/generate.ts
12
+ import camelCase from "lodash.camelcase";
12
13
  import path2 from "node:path";
13
14
  import ApiGenerator, {
14
15
  getOperationName as _getOperationName,
16
+ getReferenceName,
15
17
  isReference,
16
- isValidIdentifier
18
+ supportDeepObjects,
19
+ createPropertyAssignment,
20
+ createQuestionToken,
21
+ isValidIdentifier,
22
+ keywordType
17
23
  } from "oazapfts/generate";
18
24
  import ts4 from "typescript";
19
25
 
@@ -151,10 +157,7 @@ function generateEndpointDefinition({
151
157
  objectProperties.push(
152
158
  factory.createPropertyAssignment(
153
159
  factory.createIdentifier(type === "query" ? "providesTags" : "invalidatesTags"),
154
- factory.createArrayLiteralExpression(
155
- tags.map((tag) => factory.createStringLiteral(tag)),
156
- false
157
- )
160
+ factory.createArrayLiteralExpression(tags.map((tag) => factory.createStringLiteral(tag), false))
158
161
  )
159
162
  );
160
163
  }
@@ -356,10 +359,7 @@ var generateReactHooks = ({
356
359
  // src/generate.ts
357
360
  var generatedApiName = "injectedRtkApi";
358
361
  var v3DocCache = {};
359
- var useFetcherImport = generateImportNode("@acrool/react-fetcher", {
360
- IUseFetcherArgs: "IUseFetcherArgs"
361
- });
362
- function defaultIsDataResponse(code, includeDefault, response, allResponses) {
362
+ function defaultIsDataResponse(code, includeDefault) {
363
363
  if (includeDefault && code === "default") {
364
364
  return true;
365
365
  }
@@ -370,8 +370,7 @@ function getOperationName2({ verb, path: path4, operation }) {
370
370
  return _getOperationName(verb, path4, operation.operationId);
371
371
  }
372
372
  function getTags({ verb, pathItem }) {
373
- const tags = verb && pathItem[verb]?.tags ? pathItem[verb].tags : [];
374
- return tags.map((tag) => tag.toString());
373
+ return verb ? pathItem[verb]?.tags || [] : [];
375
374
  }
376
375
  function patternMatches(pattern) {
377
376
  const filters = Array.isArray(pattern) ? pattern : [pattern];
@@ -390,6 +389,26 @@ function operationMatches(pattern) {
390
389
  return checkMatch(operationName, operationDefinition);
391
390
  };
392
391
  }
392
+ function argumentMatches(pattern) {
393
+ const checkMatch = typeof pattern === "function" ? pattern : patternMatches(pattern);
394
+ return function matcher(argumentDefinition) {
395
+ if (!pattern || argumentDefinition.in === "path") return true;
396
+ const argumentName = argumentDefinition.name;
397
+ return checkMatch(argumentName, argumentDefinition);
398
+ };
399
+ }
400
+ function withQueryComment(node, def, hasTrailingNewLine) {
401
+ const comment = def.origin === "param" ? def.param.description : def.body.description;
402
+ if (comment) {
403
+ return ts4.addSyntheticLeadingComment(
404
+ node,
405
+ ts4.SyntaxKind.MultiLineCommentTrivia,
406
+ `* ${comment} `,
407
+ hasTrailingNewLine
408
+ );
409
+ }
410
+ return node;
411
+ }
393
412
  function getOverrides(operation, endpointOverrides) {
394
413
  return endpointOverrides?.find((override) => operationMatches(override.pattern)(operation));
395
414
  }
@@ -508,109 +527,6 @@ async function generateApi(spec, {
508
527
  }
509
528
  return [...allTagTypes];
510
529
  }
511
- function generateQueryArgType(operationDefinition) {
512
- const {
513
- operation: { parameters = [], requestBody }
514
- } = operationDefinition;
515
- const properties = [];
516
- if (requestBody && !isReference(requestBody)) {
517
- const bodySchema = requestBody.content?.["application/json"]?.schema;
518
- if (bodySchema) {
519
- properties.push(
520
- factory.createPropertySignature(
521
- void 0,
522
- factory.createIdentifier("body"),
523
- void 0,
524
- apiGen.getTypeFromSchema(bodySchema)
525
- )
526
- );
527
- }
528
- }
529
- const queryParams = parameters.filter((p) => !isReference(p) && p.in === "query");
530
- if (queryParams.length > 0) {
531
- properties.push(
532
- factory.createPropertySignature(
533
- void 0,
534
- factory.createIdentifier("params"),
535
- void 0,
536
- factory.createTypeLiteralNode(
537
- queryParams.map(
538
- (param) => factory.createPropertySignature(
539
- void 0,
540
- factory.createIdentifier(param.name),
541
- param.required ? void 0 : factory.createToken(ts4.SyntaxKind.QuestionToken),
542
- apiGen.getTypeFromSchema(param.schema)
543
- )
544
- )
545
- )
546
- )
547
- );
548
- }
549
- const headerParams = parameters.filter((p) => !isReference(p) && p.in === "header");
550
- if (headerParams.length > 0) {
551
- properties.push(
552
- factory.createPropertySignature(
553
- void 0,
554
- factory.createIdentifier("headers"),
555
- void 0,
556
- factory.createTypeLiteralNode(
557
- headerParams.map(
558
- (param) => factory.createPropertySignature(
559
- void 0,
560
- factory.createIdentifier(param.name.includes("-") ? `'${param.name}'` : param.name),
561
- param.required ? void 0 : factory.createToken(ts4.SyntaxKind.QuestionToken),
562
- apiGen.getTypeFromSchema(param.schema)
563
- )
564
- )
565
- )
566
- )
567
- );
568
- }
569
- return factory.createTypeLiteralNode([
570
- factory.createPropertySignature(
571
- void 0,
572
- factory.createIdentifier("variables"),
573
- void 0,
574
- factory.createTypeLiteralNode(properties)
575
- ),
576
- factory.createPropertySignature(
577
- void 0,
578
- factory.createIdentifier("fetchOptions"),
579
- factory.createToken(ts4.SyntaxKind.QuestionToken),
580
- factory.createTypeReferenceNode(factory.createIdentifier("any"), void 0)
581
- )
582
- ]);
583
- }
584
- function generateQueryArgDefinitions(operationDefinition) {
585
- const {
586
- operation: { parameters = [], requestBody }
587
- } = operationDefinition;
588
- const queryArg = {};
589
- if (requestBody && !isReference(requestBody)) {
590
- const bodySchema = requestBody.content?.["application/json"]?.schema;
591
- if (bodySchema) {
592
- queryArg["body"] = {
593
- name: "body",
594
- originalName: "body",
595
- type: factory.createKeywordTypeNode(ts4.SyntaxKind.AnyKeyword),
596
- required: true,
597
- origin: "body",
598
- body: requestBody
599
- };
600
- }
601
- }
602
- parameters.filter((p) => !isReference(p)).forEach((param) => {
603
- queryArg[param.name] = {
604
- name: param.name,
605
- originalName: param.name,
606
- type: factory.createKeywordTypeNode(ts4.SyntaxKind.StringKeyword),
607
- required: param.required || false,
608
- origin: "param",
609
- param
610
- };
611
- });
612
- return queryArg;
613
- }
614
530
  function generateEndpoint({
615
531
  operationDefinition,
616
532
  overrides
@@ -629,42 +545,138 @@ async function generateApi(spec, {
629
545
  let ResponseType = factory.createKeywordTypeNode(ts4.SyntaxKind.UnknownKeyword);
630
546
  if (returnsJson) {
631
547
  const returnTypes = Object.entries(responses || {}).map(
632
- ([code, response]) => isDataResponse(code, includeDefault, response, responses) && response ? apiGen.getTypeFromResponse(response) : void 0
633
- ).filter(removeUndefined);
634
- if (returnTypes.length === 1) {
635
- ResponseType = returnTypes[0];
636
- } else if (returnTypes.length > 1) {
548
+ ([code, response]) => [
549
+ code,
550
+ apiGen.resolve(response),
551
+ apiGen.getTypeFromResponse(response, "readOnly") || factory.createKeywordTypeNode(ts4.SyntaxKind.UndefinedKeyword)
552
+ ]
553
+ ).filter(
554
+ ([status, response]) => isDataResponse(status, includeDefault, apiGen.resolve(response), responses || {})
555
+ ).filter(([_1, _2, type]) => type !== keywordType.void).map(
556
+ ([code, response, type]) => ts4.addSyntheticLeadingComment(
557
+ { ...type },
558
+ ts4.SyntaxKind.MultiLineCommentTrivia,
559
+ `* status ${code} ${response.description} `,
560
+ false
561
+ )
562
+ );
563
+ if (returnTypes.length > 0) {
637
564
  ResponseType = factory.createUnionTypeNode(returnTypes);
638
565
  }
639
566
  }
640
- const QueryArg = generateQueryArgType(operationDefinition);
641
- const wrappedQueryArg = factory.createTypeReferenceNode(
642
- factory.createIdentifier("IUseFetcherArgs"),
643
- [QueryArg]
567
+ const ResponseTypeName = factory.createTypeReferenceNode(
568
+ registerInterface(
569
+ factory.createTypeAliasDeclaration(
570
+ [factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
571
+ capitalize(operationName + operationNameSuffix + responseSuffix),
572
+ void 0,
573
+ ResponseType
574
+ )
575
+ ).name
644
576
  );
645
- const endpointBuilder = factory.createIdentifier("build");
646
- const Response = factory.createTypeReferenceNode(
647
- factory.createIdentifier(`${capitalize(operationName)}${responseSuffix}`),
648
- void 0
577
+ const operationParameters = apiGen.resolveArray(operation.parameters);
578
+ const pathItemParameters = apiGen.resolveArray(pathItem.parameters).filter((pp) => !operationParameters.some((op) => op.name === pp.name && op.in === pp.in));
579
+ const parameters = supportDeepObjects([...pathItemParameters, ...operationParameters]).filter(
580
+ argumentMatches(overrides?.parameterFilter)
581
+ );
582
+ const allNames = parameters.map((p) => p.name);
583
+ const queryArg = {};
584
+ function generateName(name, potentialPrefix) {
585
+ const isPureSnakeCase = /^[a-zA-Z][a-zA-Z0-9_]*$/.test(name);
586
+ const hasNamingConflict = allNames.filter((n) => n === name).length > 1;
587
+ if (hasNamingConflict) {
588
+ name = `${potentialPrefix}_${name}`;
589
+ }
590
+ const camelCaseName = camelCase(name);
591
+ if (isPureSnakeCase && !allNames.includes(camelCaseName)) {
592
+ name = camelCaseName;
593
+ }
594
+ while (name in queryArg) {
595
+ name = `_${name}`;
596
+ }
597
+ return name;
598
+ }
599
+ for (const param of parameters) {
600
+ const name = generateName(param.name, param.in);
601
+ queryArg[name] = {
602
+ origin: "param",
603
+ name,
604
+ originalName: param.name,
605
+ type: apiGen.getTypeFromSchema(isReference(param) ? param : param.schema, void 0, "writeOnly"),
606
+ required: param.required,
607
+ param
608
+ };
609
+ }
610
+ if (requestBody) {
611
+ const body = apiGen.resolve(requestBody);
612
+ const schema = apiGen.getSchemaFromContent(body.content);
613
+ const type = apiGen.getTypeFromSchema(schema);
614
+ const schemaName = camelCase(
615
+ type.name || getReferenceName(schema) || typeof schema === "object" && "title" in schema && schema.title || "body"
616
+ );
617
+ const name = generateName(schemaName in queryArg ? "body" : schemaName, "body");
618
+ queryArg[name] = {
619
+ origin: "body",
620
+ name,
621
+ originalName: schemaName,
622
+ type: apiGen.getTypeFromSchema(schema, void 0, "writeOnly"),
623
+ required: true,
624
+ body
625
+ };
626
+ }
627
+ const propertyName = (name) => {
628
+ if (typeof name === "string") {
629
+ return isValidIdentifier(name) ? factory.createIdentifier(name) : factory.createStringLiteral(name);
630
+ }
631
+ return name;
632
+ };
633
+ const queryArgValues = Object.values(queryArg);
634
+ const isFlatArg = flattenArg && queryArgValues.length === 1;
635
+ const QueryArg = factory.createTypeReferenceNode(
636
+ registerInterface(
637
+ factory.createTypeAliasDeclaration(
638
+ [factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
639
+ capitalize(operationName + operationNameSuffix + argSuffix),
640
+ void 0,
641
+ queryArgValues.length > 0 ? isFlatArg ? withQueryComment(
642
+ factory.createUnionTypeNode([
643
+ queryArgValues[0].type,
644
+ ...!queryArgValues[0].required ? [factory.createKeywordTypeNode(ts4.SyntaxKind.UndefinedKeyword)] : []
645
+ ]),
646
+ queryArgValues[0],
647
+ false
648
+ ) : factory.createTypeLiteralNode(
649
+ queryArgValues.map(
650
+ (def) => withQueryComment(
651
+ factory.createPropertySignature(
652
+ void 0,
653
+ propertyName(def.name),
654
+ createQuestionToken(!def.required),
655
+ def.type
656
+ ),
657
+ def,
658
+ true
659
+ )
660
+ )
661
+ ) : factory.createKeywordTypeNode(ts4.SyntaxKind.VoidKeyword)
662
+ )
663
+ ).name
649
664
  );
650
- const queryArgDefinitions = generateQueryArgDefinitions(operationDefinition);
651
- const extraEndpointsProps = isQuery2 ? generateQueryEndpointProps({ operationDefinition }) : generateMutationEndpointProps({ operationDefinition });
652
665
  return generateEndpointDefinition({
653
- operationName,
666
+ operationName: operationNameSuffix ? capitalize(operationName + operationNameSuffix) : operationName,
654
667
  type: isQuery2 ? "query" : "mutation",
655
- Response,
656
- QueryArg: wrappedQueryArg,
668
+ Response: ResponseTypeName,
669
+ QueryArg,
657
670
  queryFn: generateQueryFn({
658
671
  operationDefinition,
659
- queryArg: queryArgDefinitions,
660
- isFlatArg: flattenArg,
672
+ queryArg,
661
673
  isQuery: isQuery2,
674
+ isFlatArg,
662
675
  encodePathParams,
663
676
  encodeQueryParams
664
677
  }),
665
- extraEndpointsProps,
666
- tags,
667
- endpointBuilder
678
+ extraEndpointsProps: isQuery2 ? generateQueryEndpointProps({ operationDefinition }) : generateMutationEndpointProps({ operationDefinition }),
679
+ tags
668
680
  });
669
681
  }
670
682
  function generateQueryFn({
@@ -675,91 +687,60 @@ async function generateApi(spec, {
675
687
  encodePathParams: encodePathParams2,
676
688
  encodeQueryParams: encodeQueryParams2
677
689
  }) {
678
- const {
679
- operation: { parameters = [], requestBody },
680
- path: path4,
681
- verb
682
- } = operationDefinition;
683
- const bodyParameter = requestBody && !isReference(requestBody) ? requestBody.content?.["application/json"]?.schema : void 0;
684
- const bodyArg = bodyParameter ? queryArg["body"] : void 0;
685
- const pathParameters = parameters.filter((p) => !isReference(p) && p.in === "path").map((param) => ({
686
- name: param.name,
687
- originalName: param.name,
688
- type: factory.createKeywordTypeNode(ts4.SyntaxKind.StringKeyword),
689
- required: param.required,
690
- param,
691
- origin: "param"
692
- }));
693
- const queryParameters = parameters.filter((p) => !isReference(p) && p.in === "query").map((param) => ({
694
- name: param.name,
695
- originalName: param.name,
696
- type: factory.createKeywordTypeNode(ts4.SyntaxKind.StringKeyword),
697
- required: param.required,
698
- param,
699
- origin: "param"
700
- }));
701
- const headerParameters = parameters.filter((p) => !isReference(p) && p.in === "header").map((param) => ({
702
- name: param.name.includes("-") ? `'${param.name}'` : param.name,
703
- originalName: param.name,
704
- type: factory.createKeywordTypeNode(ts4.SyntaxKind.StringKeyword),
705
- required: param.required,
706
- param,
707
- origin: "param"
708
- }));
690
+ const { path: path4, verb } = operationDefinition;
691
+ const bodyParameter = Object.values(queryArg).find((def) => def.origin === "body");
709
692
  const rootObject = factory.createIdentifier("queryArg");
710
- const objectProperties = [
711
- factory.createPropertyAssignment(
712
- "url",
713
- generatePathExpression(path4, pathParameters, rootObject, isFlatArg, encodePathParams2)
714
- ),
715
- factory.createPropertyAssignment("method", factory.createStringLiteral(verb.toUpperCase()))
716
- ];
717
- if (bodyArg) {
718
- objectProperties.push(
719
- factory.createPropertyAssignment(
720
- "body",
721
- factory.createPropertyAccessExpression(
722
- factory.createPropertyAccessExpression(rootObject, factory.createIdentifier("variables")),
723
- factory.createIdentifier("body")
724
- )
725
- )
726
- );
693
+ function pickParams(paramIn) {
694
+ return Object.values(queryArg).filter((def) => def.origin === "param" && def.param.in === paramIn);
727
695
  }
728
- if (queryParameters.length) {
729
- objectProperties.push(
730
- factory.createPropertyAssignment(
731
- "params",
732
- factory.createPropertyAccessExpression(
733
- factory.createPropertyAccessExpression(rootObject, factory.createIdentifier("variables")),
734
- factory.createIdentifier("params")
735
- )
736
- )
737
- );
738
- }
739
- if (headerParameters.length) {
740
- objectProperties.push(
741
- factory.createPropertyAssignment(
742
- "headers",
743
- factory.createPropertyAccessExpression(
744
- factory.createPropertyAccessExpression(rootObject, factory.createIdentifier("variables")),
745
- factory.createIdentifier("headers")
746
- )
747
- )
696
+ function createObjectLiteralProperty(parameters, propertyName) {
697
+ if (parameters.length === 0) return void 0;
698
+ const properties = parameters.map((param) => {
699
+ const value = isFlatArg ? rootObject : accessProperty(rootObject, param.name);
700
+ const encodedValue = encodeQueryParams2 && param.param?.in === "query" ? factory.createConditionalExpression(
701
+ value,
702
+ void 0,
703
+ factory.createCallExpression(factory.createIdentifier("encodeURIComponent"), void 0, [
704
+ factory.createCallExpression(factory.createIdentifier("String"), void 0, [value])
705
+ ]),
706
+ void 0,
707
+ factory.createIdentifier("undefined")
708
+ ) : value;
709
+ return createPropertyAssignment(param.originalName, encodedValue);
710
+ });
711
+ return factory.createPropertyAssignment(
712
+ factory.createIdentifier(propertyName),
713
+ factory.createObjectLiteralExpression(properties, true)
748
714
  );
749
715
  }
750
- objectProperties.push(
751
- factory.createPropertyAssignment(
752
- "fetchOptions",
753
- factory.createPropertyAccessExpression(rootObject, factory.createIdentifier("fetchOptions"))
754
- )
755
- );
756
716
  return factory.createArrowFunction(
757
717
  void 0,
758
718
  void 0,
759
- [factory.createParameterDeclaration(void 0, void 0, rootObject)],
719
+ Object.keys(queryArg).length ? [factory.createParameterDeclaration(void 0, void 0, rootObject, void 0, void 0, void 0)] : [],
760
720
  void 0,
761
721
  factory.createToken(ts4.SyntaxKind.EqualsGreaterThanToken),
762
- factory.createParenthesizedExpression(factory.createObjectLiteralExpression(objectProperties, true))
722
+ factory.createParenthesizedExpression(
723
+ factory.createObjectLiteralExpression(
724
+ [
725
+ factory.createPropertyAssignment(
726
+ factory.createIdentifier("url"),
727
+ generatePathExpression(path4, pickParams("path"), rootObject, isFlatArg, encodePathParams2)
728
+ ),
729
+ isQuery2 && verb.toUpperCase() === "GET" ? void 0 : factory.createPropertyAssignment(
730
+ factory.createIdentifier("method"),
731
+ factory.createStringLiteral(verb.toUpperCase())
732
+ ),
733
+ bodyParameter === void 0 ? void 0 : factory.createPropertyAssignment(
734
+ factory.createIdentifier("body"),
735
+ isFlatArg ? rootObject : factory.createPropertyAccessExpression(rootObject, factory.createIdentifier(bodyParameter.name))
736
+ ),
737
+ createObjectLiteralProperty(pickParams("cookie"), "cookies"),
738
+ createObjectLiteralProperty(pickParams("header"), "headers"),
739
+ createObjectLiteralProperty(pickParams("query"), "params")
740
+ ].filter(removeUndefined),
741
+ false
742
+ )
743
+ )
763
744
  );
764
745
  }
765
746
  function generateQueryEndpointProps({}) {
@@ -769,6 +750,9 @@ async function generateApi(spec, {
769
750
  return {};
770
751
  }
771
752
  }
753
+ function accessProperty(rootObject, propertyName) {
754
+ return isValidIdentifier(propertyName) ? factory.createPropertyAccessExpression(rootObject, factory.createIdentifier(propertyName)) : factory.createElementAccessExpression(rootObject, factory.createStringLiteral(propertyName));
755
+ }
772
756
  function generatePathExpression(path4, pathParameters, rootObject, isFlatArg, encodePathParams) {
773
757
  const expressions = [];
774
758
  const head = path4.replace(/\{(.*?)}(.*?)(?=\{|$)/g, (_, expression, literal) => {
@@ -780,21 +764,18 @@ function generatePathExpression(path4, pathParameters, rootObject, isFlatArg, en
780
764
  return "";
781
765
  });
782
766
  return expressions.length ? factory.createTemplateExpression(
783
- factory.createTemplateHead(head, head),
767
+ factory.createTemplateHead(head),
784
768
  expressions.map(([prop, literal], index) => {
785
- const value = factory.createPropertyAccessExpression(
786
- factory.createPropertyAccessExpression(rootObject, factory.createIdentifier("variables")),
787
- factory.createIdentifier(prop)
788
- );
769
+ const value = isFlatArg ? rootObject : accessProperty(rootObject, prop);
789
770
  const encodedValue = encodePathParams ? factory.createCallExpression(factory.createIdentifier("encodeURIComponent"), void 0, [
790
771
  factory.createCallExpression(factory.createIdentifier("String"), void 0, [value])
791
772
  ]) : value;
792
773
  return factory.createTemplateSpan(
793
774
  encodedValue,
794
- index === expressions.length - 1 ? factory.createTemplateTail(literal, literal) : factory.createTemplateMiddle(literal, literal)
775
+ index === expressions.length - 1 ? factory.createTemplateTail(literal) : factory.createTemplateMiddle(literal)
795
776
  );
796
777
  })
797
- ) : factory.createStringLiteral(head);
778
+ ) : factory.createNoSubstitutionTemplateLiteral(head);
798
779
  }
799
780
 
800
781
  // src/index.ts