@bitstack/ng-query-codegen-openapi 0.0.31-alpha.0 → 0.0.31-alpha.3

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 CHANGED
@@ -127,6 +127,11 @@ interface CommonOptions {
127
127
  * File path for importing IRestFulEndpointsQueryReturn type
128
128
  */
129
129
  endpointsQueryReturnTypeFile?: string;
130
+ /**
131
+ * defaults to 60 (seconds)
132
+ * Number of seconds to wait before refetching data when component mounts or args change
133
+ */
134
+ refetchOnMountOrArgChange?: number;
130
135
  }
131
136
  type TextMatcher = string | RegExp | (string | RegExp)[];
132
137
  type EndpointMatcherFunction = (operationName: string, operationDefinition: OperationDefinition) => boolean;
package/lib/index.d.ts CHANGED
@@ -127,6 +127,11 @@ interface CommonOptions {
127
127
  * File path for importing IRestFulEndpointsQueryReturn type
128
128
  */
129
129
  endpointsQueryReturnTypeFile?: string;
130
+ /**
131
+ * defaults to 60 (seconds)
132
+ * Number of seconds to wait before refetching data when component mounts or args change
133
+ */
134
+ refetchOnMountOrArgChange?: number;
130
135
  }
131
136
  type TextMatcher = string | RegExp | (string | RegExp)[];
132
137
  type EndpointMatcherFunction = (operationName: string, operationDefinition: OperationDefinition) => boolean;
package/lib/index.js CHANGED
@@ -390,6 +390,9 @@ var FileWriterService = class {
390
390
  if (sharedFiles.commonTypes) {
391
391
  filesToWrite[import_node_path3.default.join(outputDir, "common-types.ts")] = sharedFiles.commonTypes;
392
392
  }
393
+ if (sharedFiles.tagTypes) {
394
+ filesToWrite[import_node_path3.default.join(outputDir, "tagTypes.ts")] = sharedFiles.tagTypes;
395
+ }
393
396
  if (sharedFiles.doNotModify) {
394
397
  filesToWrite[import_node_path3.default.join(outputDir, "DO_NOT_MODIFY.md")] = sharedFiles.doNotModify;
395
398
  }
@@ -491,12 +494,12 @@ export interface QueryConfig {
491
494
  keepUnusedDataFor?: number,
492
495
  }
493
496
 
494
- export interface IRequestConfig extends RequestOptions { {
497
+ export interface IRequestConfig extends RequestOptions {
495
498
  timeout?: number;
496
499
  }
497
500
 
498
501
  export type IRestFulEndpointsQueryReturn<TVariables> = TVariables extends void ?
499
- void | {fetchOptions?: IRequestConfig;}:
502
+ (void | {fetchOptions?: IRequestConfig;}):
500
503
  {
501
504
  variables: TVariables;
502
505
  fetchOptions?: IRequestConfig;
@@ -926,7 +929,7 @@ function generateRtkQueryFile(endpointInfos, options) {
926
929
  */
927
930
  ${info.operationName}Query(${info.argTypeName !== "VoidApiArg" ? `args: IRestFulEndpointsQueryReturn<${info.argTypeName}>` : ""}): Observable<QueryState<${info.responseTypeName}>> {
928
931
  return this.ntkQuery.query<${info.responseTypeName}, ${info.argTypeName !== "VoidApiArg" ? `IRestFulEndpointsQueryReturn<${info.argTypeName}>` : "void"}>({
929
- queryKey: [ECacheKeys.${info.queryKeyName}${info.argTypeName !== "VoidApiArg" ? ", args.variables" : ""}],
932
+ queryKey: [ECacheTagTypes.${info.queryKeyName}${info.argTypeName !== "VoidApiArg" ? ", args.variables" : ""}],
930
933
  queryFn: () => {
931
934
  return this.apiService.${info.operationName}(${info.argTypeName !== "VoidApiArg" ? "args" : ""});
932
935
  },
@@ -964,7 +967,7 @@ function generateRtkQueryFile(endpointInfos, options) {
964
967
  trigger: (${info.argTypeName !== "VoidApiArg" ? "args, " : ""}options = {}) => {
965
968
  const { skipCache = true } = options;
966
969
  if (!skipCache) {
967
- const cachedResult = this.ntkQuery.getQueryCache<${info.responseTypeName}>([ECacheKeys.${info.queryKeyName}${info.argTypeName !== "VoidApiArg" ? ", args.variables" : ""}]);
970
+ const cachedResult = this.ntkQuery.getQueryCache<${info.responseTypeName}>([ECacheTagTypes.${info.queryKeyName}${info.argTypeName !== "VoidApiArg" ? ", args.variables" : ""}]);
968
971
  if (cachedResult) {
969
972
  return cachedResult;
970
973
  }
@@ -981,8 +984,8 @@ import {Injectable, inject} from '@angular/core';
981
984
  import {Observable} from 'rxjs';
982
985
  import {HttpErrorResponse} from '@angular/common/http';
983
986
  import {NtkQueryService, MutationState, QueryState, MutationResponse} from '@core/ntk-query';
984
- import {ECacheKeys} from '../cache-keys';
985
- import {${apiServiceName}} from './api.service';
987
+ import {ECacheTagTypes} from '../tagTypes';
988
+ import {${apiServiceName}} from './enhanceEndpoints';
986
989
  import {IRestFulEndpointsQueryReturn, RequestOptions} from '../common-types';
987
990
  import {${endpointInfos.map((info) => ` ${info.argTypeName}, ${info.responseTypeName}`).join(",")}} from './types';
988
991
 
@@ -1005,7 +1008,7 @@ function generateRtkEnhanceEndpointsFile(endpointInfos, options) {
1005
1008
  return `/* eslint-disable */
1006
1009
  // [Warning] Generated automatically - do not edit manually
1007
1010
 
1008
- import { ${httpClient.importName} } from '${httpClient.file}';
1011
+ import { ${httpClient.importReturnTypeName} } from '${httpClient.file}';
1009
1012
  import { Injectable, inject } from '@angular/core';
1010
1013
  import { Observable } from 'rxjs';
1011
1014
  import { ${apiConfiguration.importName} } from '${apiConfiguration.file}';
@@ -1018,7 +1021,7 @@ import {${endpointInfos.map((info) => ` ${info.argTypeName}, ${info.responseType
1018
1021
  })
1019
1022
  export class ${apiServiceClassName} {
1020
1023
  private config = inject(${apiConfiguration.importName});
1021
- private http = inject(${httpClient.importName});
1024
+ private http = inject(${httpClient.importReturnTypeName});
1022
1025
 
1023
1026
  ${endpointInfos.map((info) => {
1024
1027
  const isGet = info.verb.toUpperCase() === "GET";
@@ -1036,17 +1039,16 @@ ${endpointInfos.map((info) => {
1036
1039
  const hasQueryParams = info.queryParams.length > 0;
1037
1040
  const hasBody = !isGet && hasArgs;
1038
1041
  const generateRequestOptions = () => {
1039
- const options2 = ["...args.fetchOptions"];
1040
- if (hasRequestBody || !isGet) {
1041
- options2.push(`headers: { 'Content-Type': 'application/json', ...args.fetchOptions?.headers }`);
1042
- }
1043
- if (hasQueryParams && hasArgs) {
1044
- options2.push(generateQueryParams(info.queryParams));
1042
+ let paramsSection = "";
1043
+ if (info.queryParams && info.queryParams.length > 0) {
1044
+ const paramsLines = info.queryParams.map((param) => `${param.name}: args.variables.${param.name},`).join("\n");
1045
+ paramsSection = `params: {${paramsLines}},`;
1045
1046
  }
1046
- if (hasRequestBody) {
1047
- options2.push("body: args.variables.body");
1048
- }
1049
- return options2.length > 0 ? `{ ${options2.join(", ")} }` : "{}";
1047
+ return `{
1048
+ ...args.fetchOptions,
1049
+ headers: { 'Content-Type': '${info.contentType}', ...args.fetchOptions?.headers },
1050
+ ${paramsSection}${info.hasRequestBody ? `body: args.variables.body,` : ""}
1051
+ }`;
1050
1052
  };
1051
1053
  return `
1052
1054
  /**
@@ -1062,12 +1064,6 @@ ${endpointInfos.map((info) => {
1062
1064
  }
1063
1065
  `;
1064
1066
  }
1065
- function generateQueryParams(queryParams) {
1066
- const paramEntries = queryParams.map(
1067
- (param) => `${param.name}: args.variables.${param.name}`
1068
- ).join(", ");
1069
- return `params: withoutUndefined({ ${paramEntries} })`;
1070
- }
1071
1067
 
1072
1068
  // src/services/api-code-generator.ts
1073
1069
  var ApiCodeGenerator = class {
@@ -1093,6 +1089,11 @@ var ApiCodeGenerator = class {
1093
1089
  const rtkQueryContent = generateRtkQueryFile(endpointInfos, this.options);
1094
1090
  const enhanceEndpointsContent = generateRtkEnhanceEndpointsFile(endpointInfos, this.options);
1095
1091
  const indexContent = this.generateIndex();
1092
+ const allEndpointCacheKeys = endpointInfos.filter((info) => info.isQuery).map((info) => ({
1093
+ operationName: info.operationName,
1094
+ queryKeyName: info.queryKeyName,
1095
+ groupKey: this.options.groupKey || "_common"
1096
+ }));
1096
1097
  const operationNames = endpointInfos.map((info) => info.operationName);
1097
1098
  const allTags = /* @__PURE__ */ new Set();
1098
1099
  endpointInfos.forEach((info) => {
@@ -1108,8 +1109,9 @@ var ApiCodeGenerator = class {
1108
1109
  queryService: rtkQueryContent,
1109
1110
  // RTK Query 檔案
1110
1111
  index: indexContent,
1111
- enhanceEndpoints: enhanceEndpointsContent
1112
+ enhanceEndpoints: enhanceEndpointsContent,
1112
1113
  // 新增的 enhance endpoints 檔案
1114
+ allEndpointCacheKeys
1113
1115
  }
1114
1116
  };
1115
1117
  }
@@ -1188,25 +1190,42 @@ export function withoutUndefined(obj?: Record<string, any>) {
1188
1190
 
1189
1191
  `;
1190
1192
  }
1193
+ function toCamelCase(str) {
1194
+ return str.toLowerCase().replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
1195
+ }
1191
1196
 
1192
1197
  // src/generators/tag-types-generator.ts
1193
1198
  init_cjs_shims();
1194
- function generateTagTypesFile(tags) {
1195
- if (tags.length === 0) {
1196
- return `/* eslint-disable */
1197
- // [Warning] Generated automatically - do not edit manually
1198
-
1199
- export enum ECacheTagTypes {
1200
- }
1201
- `;
1202
- }
1203
- const enumEntries = tags.sort().map((tag) => ` ${tag} = '${tag}',`).join("\n");
1204
- return `/* eslint-disable */
1205
- // [Warning] Generated automatically - do not edit manually
1206
-
1199
+ function generateTagTypesFile(allEndpointInfos) {
1200
+ const groupedKeys = allEndpointInfos.reduce(
1201
+ (acc, info) => {
1202
+ if (!acc[info.groupKey]) {
1203
+ acc[info.groupKey] = [];
1204
+ }
1205
+ acc[info.groupKey].push({
1206
+ operationName: info.operationName,
1207
+ queryKeyName: info.queryKeyName
1208
+ });
1209
+ return acc;
1210
+ },
1211
+ {}
1212
+ );
1213
+ const enumEntries = Object.entries(groupedKeys).map(([groupKey, keys]) => {
1214
+ const groupComment = ` // ${groupKey.charAt(0).toUpperCase() + groupKey.slice(1)} related cache keys`;
1215
+ const keyEntries = keys.map((key) => ` ${key.queryKeyName} = '${toCamelCase(key.queryKeyName)}',`).join("\n");
1216
+ return `${groupComment}
1217
+ ${keyEntries}`;
1218
+ }).join("\n\n");
1219
+ return `// [Warning] Generated automatically - do not edit manually
1220
+
1221
+ /**
1222
+ * Cache keys enum for all API queries
1223
+ */
1207
1224
  export enum ECacheTagTypes {
1208
1225
  ${enumEntries}
1209
1226
  }
1227
+
1228
+ export default ECacheTagTypes;
1210
1229
  `;
1211
1230
  }
1212
1231
 
@@ -1216,6 +1235,7 @@ var UnifiedCodeGenerator = class {
1216
1235
  openApiService = new OpenApiService();
1217
1236
  groupService = new GroupService();
1218
1237
  fileWriterService = new FileWriterService();
1238
+ allEndpointCacheKeys = [];
1219
1239
  // 內部狀態存儲
1220
1240
  openApiDoc = null;
1221
1241
  parserService = null;
@@ -1245,7 +1265,7 @@ var UnifiedCodeGenerator = class {
1245
1265
  this.generateSchemaContent();
1246
1266
  this.generateUtilsContent();
1247
1267
  this.generateDoNotModifyContent();
1248
- this.generateTagTypesContent();
1268
+ this.generatECacheTagTypesContent();
1249
1269
  return await this.release();
1250
1270
  }
1251
1271
  /**
@@ -1259,23 +1279,23 @@ var UnifiedCodeGenerator = class {
1259
1279
  this._options.schemaFile
1260
1280
  );
1261
1281
  }
1262
- this.openApiDoc = await this.openApiService.getDocument(
1263
- this.actualSchemaFile,
1264
- this._options.httpResolverOptions
1265
- );
1282
+ this.openApiDoc = await this.openApiService.getDocument(this.actualSchemaFile, this._options.httpResolverOptions);
1266
1283
  this.parserService = new OpenApiParserService(this.openApiDoc, this._options);
1267
1284
  this.parserService.initialize();
1268
1285
  const apiGen = this.parserService.getApiGenerator();
1269
- this.schemaInterfaces = apiGen.aliases.reduce((curr, alias) => {
1270
- if (import_typescript3.default.isInterfaceDeclaration(alias) || import_typescript3.default.isTypeAliasDeclaration(alias)) {
1271
- const name = alias.name.text;
1272
- return {
1273
- ...curr,
1274
- [name]: alias
1275
- };
1276
- }
1277
- return curr;
1278
- }, {});
1286
+ this.schemaInterfaces = apiGen.aliases.reduce(
1287
+ (curr, alias) => {
1288
+ if (import_typescript3.default.isInterfaceDeclaration(alias) || import_typescript3.default.isTypeAliasDeclaration(alias)) {
1289
+ const name = alias.name.text;
1290
+ return {
1291
+ ...curr,
1292
+ [name]: alias
1293
+ };
1294
+ }
1295
+ return curr;
1296
+ },
1297
+ {}
1298
+ );
1279
1299
  }
1280
1300
  /**
1281
1301
  * 生成階段:產生所有內容但不寫檔
@@ -1288,10 +1308,7 @@ var UnifiedCodeGenerator = class {
1288
1308
  const groupInfos = this.groupService.groupPaths(paths, this._options.outputFiles);
1289
1309
  for (const groupInfo of Object.values(groupInfos)) {
1290
1310
  try {
1291
- const groupContent = await this.generateApiGroupContent(
1292
- this._options,
1293
- groupInfo
1294
- );
1311
+ const groupContent = await this.generateApiGroupContent(this._options, groupInfo);
1295
1312
  if (groupContent.operationNames.length > 0) {
1296
1313
  this.generatedContent.groups.push({
1297
1314
  groupKey: groupInfo.groupKey,
@@ -1307,6 +1324,12 @@ var UnifiedCodeGenerator = class {
1307
1324
  }
1308
1325
  }
1309
1326
  }
1327
+ /**
1328
+ * 生成 cache keys
1329
+ */
1330
+ async generatECacheTagTypesContent() {
1331
+ this.generatedContent.tagTypes = generateTagTypesFile(this.allEndpointCacheKeys);
1332
+ }
1310
1333
  /**
1311
1334
  * 生成 common types
1312
1335
  */
@@ -1334,10 +1357,10 @@ var UnifiedCodeGenerator = class {
1334
1357
  /**
1335
1358
  * 生成 Tag Types
1336
1359
  */
1337
- async generateTagTypesContent() {
1338
- const tagsArray = Array.from(this.allTags);
1339
- this.generatedContent.tagTypes = generateTagTypesFile(tagsArray);
1340
- }
1360
+ // private async generateTagTypesContent(): Promise<void> {
1361
+ // const tagsArray = Array.from(this.allTags);
1362
+ // this.generatedContent.tagTypes = generateTagTypesFile(tagsArray);
1363
+ // }
1341
1364
  /**
1342
1365
  * 發佈階段:統一寫入所有檔案
1343
1366
  */
@@ -1350,15 +1373,12 @@ var UnifiedCodeGenerator = class {
1350
1373
  try {
1351
1374
  if (group.content?.files) {
1352
1375
  const groupOutputDir = import_node_path4.default.dirname(group.outputPath);
1353
- const groupResults = await this.fileWriterService.writeGroupFiles(
1354
- groupOutputDir,
1355
- {
1356
- types: group.content.files.types,
1357
- queryService: group.content.files.queryService,
1358
- enhanceEndpoints: group.content.files.enhanceEndpoints,
1359
- index: group.content.files.index
1360
- }
1361
- );
1376
+ const groupResults = await this.fileWriterService.writeGroupFiles(groupOutputDir, {
1377
+ types: group.content.files.types,
1378
+ queryService: group.content.files.queryService,
1379
+ enhanceEndpoints: group.content.files.enhanceEndpoints,
1380
+ index: group.content.files.index
1381
+ });
1362
1382
  results.push(...groupResults);
1363
1383
  generatedGroups.push(group.groupKey);
1364
1384
  }
@@ -1367,24 +1387,15 @@ var UnifiedCodeGenerator = class {
1367
1387
  }
1368
1388
  }
1369
1389
  const outputDir = this.generatedContent.groups[0] ? import_node_path4.default.dirname(import_node_path4.default.dirname(this.generatedContent.groups[0].outputPath)) : "./generated";
1370
- if (this.generatedContent.commonTypes || this.generatedContent.doNotModify || this.generatedContent.utils) {
1371
- const sharedResults = await this.fileWriterService.writeSharedFiles(
1372
- outputDir,
1373
- {
1374
- commonTypes: this.generatedContent.commonTypes || void 0,
1375
- doNotModify: this.generatedContent.doNotModify || void 0,
1376
- utils: this.generatedContent.utils || void 0
1377
- }
1378
- );
1390
+ if (this.generatedContent.tagTypes || this.generatedContent.commonTypes || this.generatedContent.doNotModify || this.generatedContent.utils) {
1391
+ const sharedResults = await this.fileWriterService.writeSharedFiles(outputDir, {
1392
+ tagTypes: this.generatedContent.tagTypes || void 0,
1393
+ commonTypes: this.generatedContent.commonTypes || void 0,
1394
+ doNotModify: this.generatedContent.doNotModify || void 0,
1395
+ utils: this.generatedContent.utils || void 0
1396
+ });
1379
1397
  results.push(...sharedResults);
1380
1398
  }
1381
- if (this.generatedContent.tagTypes) {
1382
- const tagTypesResult = await this.fileWriterService.writeFile(
1383
- import_node_path4.default.join(outputDir, "tagTypes.ts"),
1384
- this.generatedContent.tagTypes
1385
- );
1386
- results.push(tagTypesResult);
1387
- }
1388
1399
  if (this.generatedContent.componentSchema) {
1389
1400
  const schemaResults = await this.fileWriterService.writeSchemaFile(
1390
1401
  outputDir,
@@ -1427,6 +1438,10 @@ var UnifiedCodeGenerator = class {
1427
1438
  }
1428
1439
  const apiGenerator = new ApiCodeGenerator(this.parserService, groupOptions);
1429
1440
  const result = await apiGenerator.generate();
1441
+ if (result.files && "allEndpointCacheKeys" in result.files) {
1442
+ const cacheKeys = result.files.allEndpointCacheKeys;
1443
+ this.allEndpointCacheKeys.push(...cacheKeys);
1444
+ }
1430
1445
  return result;
1431
1446
  }
1432
1447
  /**