beer-swagger 1.0.3 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/generate-apis.js +51 -48
  2. package/package.json +1 -1
package/generate-apis.js CHANGED
@@ -5,7 +5,6 @@ import path from 'path';
5
5
  import { createInterface } from 'readline';
6
6
 
7
7
  const ENV_PATH = path.join(process.cwd(), '.env');
8
- const CLIENT_TYPES = new Set(['WEB', 'WeChatMiniProgram']);
9
8
  const SKIPPED_SERVICES = new Set([
10
9
  'billbear-common-web-gateway',
11
10
  'billbear-common-data-panel'
@@ -116,8 +115,8 @@ function appendParamSuffix(baseName, paramSuffix) {
116
115
  return `${baseName}${paramSuffix}`;
117
116
  }
118
117
 
119
- // Add a verb for single-segment paths when needed.
120
- function addVerbForSingleSegment(name, method) {
118
+ // Add a verb when the HTTP method should be reflected in the name.
119
+ function addVerbForSingleSegment(name, method, hasPathParams = false) {
121
120
  const lower = name.toLowerCase();
122
121
  if (KEEP_METHOD_NAMES.has(lower)) {
123
122
  return name;
@@ -126,6 +125,9 @@ function addVerbForSingleSegment(name, method) {
126
125
  const suffix = name[0].toUpperCase() + name.slice(1);
127
126
  return `removeBy${suffix}`;
128
127
  }
128
+ if ((method === 'post' || method === 'put') && !hasPathParams) {
129
+ return name;
130
+ }
129
131
  const verbMap = {
130
132
  get: 'get',
131
133
  post: 'save',
@@ -238,9 +240,9 @@ function mapSchemaToType(schema, schemas, useTypes) {
238
240
  return `${itemType}[]`;
239
241
  }
240
242
  if (type === 'object') {
241
- return '{}';
243
+ return 'object';
242
244
  }
243
- return '{}';
245
+ return 'object';
244
246
  }
245
247
 
246
248
  // Map parameter schema to a type for method signatures.
@@ -281,9 +283,9 @@ function mapParamSchemaToType(schema, schemas, useTypes) {
281
283
  return '[]';
282
284
  }
283
285
  if (type === 'object') {
284
- return '{}';
286
+ return 'object';
285
287
  }
286
- return '{}';
288
+ return 'object';
287
289
  }
288
290
 
289
291
  // Resolve default response type from Swagger responses.
@@ -400,7 +402,7 @@ function toPascal(value) {
400
402
  }
401
403
 
402
404
  // Generate API file content for a service.
403
- function generateForSpec(spec, serviceName, fileBase, clientType) {
405
+ function generateForSpec(spec, serviceName, fileBase, isDefaultFetch) {
404
406
  const {
405
407
  components = {},
406
408
  tags: specTags = [],
@@ -453,7 +455,8 @@ function generateForSpec(spec, serviceName, fileBase, clientType) {
453
455
  const pathSegments = p.split('/')
454
456
  .filter(Boolean)
455
457
  .filter((part) => !part.startsWith('{'));
456
- name = pathSegments.length === 1 ? addVerbForSingleSegment(inferred, method) : inferred;
458
+ const shouldAddVerb = pathSegments.length === 1 || ((method === 'post' || method === 'put') && pathParams.length > 0);
459
+ name = shouldAddVerb ? addVerbForSingleSegment(inferred, method, pathParams.length > 0) : inferred;
457
460
  }
458
461
  if (!KEEP_METHOD_NAMES.has(name.toLowerCase())) {
459
462
  name = fixVerbCase(name);
@@ -615,7 +618,7 @@ function generateForSpec(spec, serviceName, fileBase, clientType) {
615
618
 
616
619
  if (entryMethod === 'get') {
617
620
  methods.push(` public async ${name}<T = ${defaultType}>(${sigParts}): Promise<JsonResponse<T>> {`);
618
- methods.push(` return this.get<T>(${pathLiteral}, ${paramsObject});`);
621
+ methods.push(` return await this.get<T>(${pathLiteral}, ${paramsObject});`);
619
622
  methods.push(' }');
620
623
  methods.push('');
621
624
  continue;
@@ -624,12 +627,12 @@ function generateForSpec(spec, serviceName, fileBase, clientType) {
624
627
  if (entryMethod === 'delete') {
625
628
  if (entryHasBody) {
626
629
  methods.push(` public async ${name}<T = ${defaultType}>(${sigParts}): Promise<JsonResponse<T>> {`);
627
- methods.push(` return this.deleteBody<T>(${pathLiteral}, ${paramsObject}, body);`);
630
+ methods.push(` return await this.deleteBody<T>(${pathLiteral}, ${paramsObject}, body);`);
628
631
  methods.push(' }');
629
632
  methods.push('');
630
633
  } else {
631
634
  methods.push(` public async ${name}<T = ${defaultType}>(${sigParts}): Promise<JsonResponse<T>> {`);
632
- methods.push(` return this.delete<T>(${pathLiteral}, ${paramsObject});`);
635
+ methods.push(` return await this.delete<T>(${pathLiteral}, ${paramsObject});`);
633
636
  methods.push(' }');
634
637
  methods.push('');
635
638
  }
@@ -639,12 +642,12 @@ function generateForSpec(spec, serviceName, fileBase, clientType) {
639
642
  if (entryMethod === 'post') {
640
643
  if (entryHasBody) {
641
644
  methods.push(` public async ${name}<T = ${defaultType}>(${sigParts}): Promise<JsonResponse<T>> {`);
642
- methods.push(` return this.postBody<T>(${pathLiteral}, ${paramsObject}, body);`);
645
+ methods.push(` return await this.postBody<T>(${pathLiteral}, ${paramsObject}, body);`);
643
646
  methods.push(' }');
644
647
  methods.push('');
645
648
  } else {
646
649
  methods.push(` public async ${name}<T = ${defaultType}>(${sigParts}): Promise<JsonResponse<T>> {`);
647
- methods.push(` return this.post<T>(${pathLiteral}, ${paramsObject});`);
650
+ methods.push(` return await this.post<T>(${pathLiteral}, ${paramsObject});`);
648
651
  methods.push(' }');
649
652
  methods.push('');
650
653
  }
@@ -654,12 +657,12 @@ function generateForSpec(spec, serviceName, fileBase, clientType) {
654
657
  if (entryMethod === 'put') {
655
658
  if (entryHasBody) {
656
659
  methods.push(` public async ${name}<T = ${defaultType}>(${sigParts}): Promise<JsonResponse<T>> {`);
657
- methods.push(` return this.putBody<T>(${pathLiteral}, ${paramsObject}, body);`);
660
+ methods.push(` return await this.putBody<T>(${pathLiteral}, ${paramsObject}, body);`);
658
661
  methods.push(' }');
659
662
  methods.push('');
660
663
  } else {
661
664
  methods.push(` public async ${name}<T = ${defaultType}>(${sigParts}): Promise<JsonResponse<T>> {`);
662
- methods.push(` return this.put<T>(${pathLiteral}, ${paramsObject});`);
665
+ methods.push(` return await this.put<T>(${pathLiteral}, ${paramsObject});`);
663
666
  methods.push(' }');
664
667
  methods.push('');
665
668
  }
@@ -667,7 +670,7 @@ function generateForSpec(spec, serviceName, fileBase, clientType) {
667
670
  }
668
671
 
669
672
  methods.push(` public async ${name}<T = ${defaultType}>(${sigParts}): Promise<JsonResponse<T>> {`);
670
- methods.push(` return this.postBody<T>(${pathLiteral}, ${paramsObject}, body);`);
673
+ methods.push(` return await this.postBody<T>(${pathLiteral}, ${paramsObject}, body);`);
671
674
  methods.push(' }');
672
675
  methods.push('');
673
676
  }
@@ -698,8 +701,9 @@ function generateForSpec(spec, serviceName, fileBase, clientType) {
698
701
  lines.push(' * This file is auto-generated. Do not edit manually.');
699
702
  lines.push(' * To update, run the generate-apis.js script.');
700
703
  lines.push(' */');
701
- const fetchImport = clientType === 'WeChatMiniProgram' ? './fetch' : 'beer-network/api';
702
- lines.push(`import Fetch, { JsonResponse } from '${fetchImport}';`);
704
+ const fetchImport = isDefaultFetch ? 'beer-network/api' : './fetch';
705
+ lines.push(`import type { JsonResponse } from '${fetchImport}';`);
706
+ lines.push(`import Fetch from '${fetchImport}';`);
703
707
  if (fileBase) {
704
708
  lines.push(`import type * as Types from './types/${fileBase}-type';`);
705
709
  }
@@ -709,7 +713,7 @@ function generateForSpec(spec, serviceName, fileBase, clientType) {
709
713
  lines.push(' public readonly pathPrefix: string;');
710
714
  lines.push(...apiProps);
711
715
  lines.push(' constructor(pathPrefix = \'\') {');
712
- lines.push(` this.pathPrefix = (pathPrefix ?? '') + '${defaultPathPrefix}';`);
716
+ lines.push(` this.pathPrefix = \`\${pathPrefix ?? ''}${defaultPathPrefix}\`;`);
713
717
  lines.push(...apiInit);
714
718
  lines.push(' }');
715
719
  lines.push('}');
@@ -719,7 +723,7 @@ function generateForSpec(spec, serviceName, fileBase, clientType) {
719
723
  lines.push(` if (!${cacheName}.has(pathPrefix)) {`);
720
724
  lines.push(` ${cacheName}.set(pathPrefix, new ${apiClassName}(pathPrefix));`);
721
725
  lines.push(' }');
722
- lines.push(` return ${cacheName}.get(pathPrefix)!;`);
726
+ lines.push(` return ${cacheName}.get(pathPrefix) ?? (() => { throw new Error('API instance not found'); })();`);
723
727
  lines.push('}');
724
728
  lines.push('');
725
729
 
@@ -913,22 +917,23 @@ function writeEnvFile(nextEnv) {
913
917
  fs.writeFileSync(ENV_PATH, `${lines.join('\n')}\n`, 'utf8');
914
918
  }
915
919
 
916
- function normalizeClientType(value) {
917
- if (!value) {
918
- return '';
920
+ function normalizeBoolean(value) {
921
+ if (value === undefined || value === null || value === '') {
922
+ return undefined;
919
923
  }
920
- if (CLIENT_TYPES.has(value)) {
924
+ if (typeof value === 'boolean') {
921
925
  return value;
922
926
  }
923
- if (value.toUpperCase() === 'WEB') {
924
- return 'WEB';
925
- }
926
- const normalized = value.replace(/[-_\s]/g, '')
927
+ const normalized = String(value)
928
+ .trim()
927
929
  .toLowerCase();
928
- if (normalized === 'wechatminiprogram') {
929
- return 'WeChatMiniProgram';
930
+ if (['true', '1', 'yes', 'y'].includes(normalized)) {
931
+ return true;
930
932
  }
931
- return '';
933
+ if (['false', '0', 'no', 'n'].includes(normalized)) {
934
+ return false;
935
+ }
936
+ return undefined;
932
937
  }
933
938
 
934
939
  // Ask user for missing values via CLI.
@@ -948,13 +953,12 @@ async function promptForMissing(env) {
948
953
  if (!result.SWAGGER_OUT_DIRECTORY) {
949
954
  result.SWAGGER_OUT_DIRECTORY = (await ask('DIRECTORY: ')).trim();
950
955
  }
951
- if (!result.CLIENT_TYPE || !CLIENT_TYPES.has(result.CLIENT_TYPE)) {
952
- let selected = '';
953
- while (!CLIENT_TYPES.has(selected)) {
954
- selected = normalizeClientType((await ask('CLIENT_TYPE (WEB/WeChatMiniProgram): ')).trim());
955
- }
956
- result.CLIENT_TYPE = selected;
956
+ let isDefaultFetch = normalizeBoolean(result.IS_DEFAULT_FETCH);
957
+ while (isDefaultFetch === undefined) {
958
+ const selected = (await ask('IS_DEFAULT_FETCH (true/false): ')).trim();
959
+ isDefaultFetch = normalizeBoolean(selected);
957
960
  }
961
+ result.IS_DEFAULT_FETCH = String(isDefaultFetch);
958
962
  rl.close();
959
963
  return result;
960
964
  }
@@ -965,23 +969,23 @@ async function main() {
965
969
  let {
966
970
  SWAGGER_BASE_URL: baseUrl,
967
971
  SWAGGER_OUT_DIRECTORY: directory,
968
- CLIENT_TYPE: clientType
972
+ IS_DEFAULT_FETCH: isDefaultFetch
969
973
  } = { ...process.env, ...envFile };
970
- clientType = normalizeClientType(clientType);
974
+ isDefaultFetch = normalizeBoolean(isDefaultFetch);
971
975
 
972
- if (!baseUrl || !directory || !clientType) {
976
+ if (!baseUrl || !directory || isDefaultFetch === undefined) {
973
977
  const filled = await promptForMissing({
974
978
  SWAGGER_BASE_URL: baseUrl || '',
975
979
  SWAGGER_OUT_DIRECTORY: directory || '',
976
- CLIENT_TYPE: clientType || ''
980
+ IS_DEFAULT_FETCH: isDefaultFetch === undefined ? '' : String(isDefaultFetch)
977
981
  });
978
982
  baseUrl = filled.SWAGGER_BASE_URL;
979
983
  directory = filled.SWAGGER_OUT_DIRECTORY;
980
- clientType = normalizeClientType(filled.CLIENT_TYPE);
984
+ isDefaultFetch = normalizeBoolean(filled.IS_DEFAULT_FETCH);
981
985
  writeEnvFile({
982
986
  SWAGGER_BASE_URL: baseUrl,
983
987
  SWAGGER_OUT_DIRECTORY: directory,
984
- CLIENT_TYPE: clientType
988
+ IS_DEFAULT_FETCH: String(isDefaultFetch)
985
989
  });
986
990
  }
987
991
 
@@ -991,10 +995,9 @@ async function main() {
991
995
  if (!directory) {
992
996
  throw new Error('SWAGGER_OUT_DIRECTORY is required.');
993
997
  }
994
- if (!clientType) {
995
- throw new Error('CLIENT_TYPE is required.');
998
+ if (isDefaultFetch === undefined) {
999
+ throw new Error('IS_DEFAULT_FETCH is required.');
996
1000
  }
997
-
998
1001
  const configUrl = `${baseUrl}/v3/api-docs/swagger-config`;
999
1002
  const outputDirectory = path.isAbsolute(directory) ? directory : path.join(process.cwd(), directory);
1000
1003
  const typesDirectory = path.join(outputDirectory, 'types');
@@ -1032,7 +1035,7 @@ async function main() {
1032
1035
  const specUrl = `${baseUrl}${url}`;
1033
1036
  const spec = await fetchJson(specUrl);
1034
1037
  const fileBase = toFileBase(serviceName);
1035
- const content = generateForSpec(spec, serviceName, fileBase, clientType);
1038
+ const content = generateForSpec(spec, serviceName, fileBase, isDefaultFetch);
1036
1039
  const typesContent = generateTypes(spec);
1037
1040
 
1038
1041
  const outPath = path.join(outputDirectory, `${fileBase}.ts`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beer-swagger",
3
- "version": "1.0.3",
3
+ "version": "1.1.1",
4
4
  "bin": {
5
5
  "beer-swagger": "./generate-apis.js"
6
6
  },