@keq-request/cli 5.0.0-alpha.10 → 5.0.0-alpha.12

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 (83) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/cli.cjs +673 -222
  3. package/dist/cli.cjs.map +1 -1
  4. package/dist/cli.js +673 -222
  5. package/dist/cli.js.map +1 -1
  6. package/dist/compiler/compiler.d.ts +29 -0
  7. package/dist/compiler/compiler.d.ts.map +1 -0
  8. package/dist/compiler/index.d.ts +2 -0
  9. package/dist/compiler/index.d.ts.map +1 -0
  10. package/dist/compiler/intercepter/perfect-error-message.d.ts +3 -0
  11. package/dist/compiler/intercepter/perfect-error-message.d.ts.map +1 -0
  12. package/dist/compiler/intercepter/print-information.d.ts +5 -0
  13. package/dist/compiler/intercepter/print-information.d.ts.map +1 -0
  14. package/dist/index.cjs +620 -154
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.ts +9 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +609 -150
  19. package/dist/index.js.map +1 -1
  20. package/dist/plugins/body-fallback/index.d.ts +6 -0
  21. package/dist/plugins/body-fallback/index.d.ts.map +1 -0
  22. package/dist/plugins/eslint/index.d.ts +15 -0
  23. package/dist/plugins/eslint/index.d.ts.map +1 -0
  24. package/dist/plugins/index.d.ts +4 -0
  25. package/dist/plugins/index.d.ts.map +1 -0
  26. package/dist/plugins/prettier/index.d.ts +6 -0
  27. package/dist/plugins/prettier/index.d.ts.map +1 -0
  28. package/dist/plugins.cjs +159 -0
  29. package/dist/plugins.cjs.map +1 -0
  30. package/dist/plugins.js +120 -0
  31. package/dist/plugins.js.map +1 -0
  32. package/dist/renderer/json-schema/index.d.ts.map +1 -1
  33. package/dist/renderer/operation-request/index.d.ts.map +1 -1
  34. package/dist/renderer/operation-type/index.d.ts +2 -1
  35. package/dist/renderer/operation-type/index.d.ts.map +1 -1
  36. package/dist/renderer/request/index.d.ts.map +1 -1
  37. package/dist/tasks/compile/index.d.ts +3 -5
  38. package/dist/tasks/compile/index.d.ts.map +1 -1
  39. package/dist/tasks/compile/utils/compile-operation-definition.d.ts +5 -2
  40. package/dist/tasks/compile/utils/compile-operation-definition.d.ts.map +1 -1
  41. package/dist/tasks/compile/utils/compile-schema-definition.d.ts +5 -2
  42. package/dist/tasks/compile/utils/compile-schema-definition.d.ts.map +1 -1
  43. package/dist/tasks/download/index.d.ts +3 -3
  44. package/dist/tasks/download/index.d.ts.map +1 -1
  45. package/dist/tasks/index.d.ts +9 -11
  46. package/dist/tasks/index.d.ts.map +1 -1
  47. package/dist/tasks/interactive/index.d.ts +9 -6
  48. package/dist/tasks/interactive/index.d.ts.map +1 -1
  49. package/dist/tasks/persist/index.d.ts +3 -8
  50. package/dist/tasks/persist/index.d.ts.map +1 -1
  51. package/dist/tasks/setup/index.d.ts +7 -1
  52. package/dist/tasks/setup/index.d.ts.map +1 -1
  53. package/dist/tasks/shaking/index.d.ts +4 -5
  54. package/dist/tasks/shaking/index.d.ts.map +1 -1
  55. package/dist/tasks/types/base-task-options.d.ts +6 -0
  56. package/dist/tasks/types/base-task-options.d.ts.map +1 -0
  57. package/dist/tasks/types/file.d.ts +4 -0
  58. package/dist/tasks/types/file.d.ts.map +1 -0
  59. package/dist/tasks/types/index.d.ts +6 -0
  60. package/dist/tasks/types/index.d.ts.map +1 -0
  61. package/dist/tasks/types/task-context.d.ts +4 -0
  62. package/dist/tasks/types/task-context.d.ts.map +1 -1
  63. package/dist/tasks/types/task-wrapper.d.ts +4 -0
  64. package/dist/tasks/types/task-wrapper.d.ts.map +1 -0
  65. package/dist/tasks/utils/anchor.d.ts +20 -0
  66. package/dist/tasks/utils/anchor.d.ts.map +1 -0
  67. package/dist/tasks/utils/artifact.d.ts +2 -0
  68. package/dist/tasks/utils/artifact.d.ts.map +1 -1
  69. package/dist/tasks/utils/index.d.ts +11 -0
  70. package/dist/tasks/utils/index.d.ts.map +1 -0
  71. package/dist/tasks/utils/proxy-task-wrapper.d.ts +3 -0
  72. package/dist/tasks/utils/proxy-task-wrapper.d.ts.map +1 -0
  73. package/dist/tasks/validate/index.d.ts +3 -6
  74. package/dist/tasks/validate/index.d.ts.map +1 -1
  75. package/dist/types/index.d.ts +7 -0
  76. package/dist/types/index.d.ts.map +1 -0
  77. package/dist/types/plugin.d.ts +5 -0
  78. package/dist/types/plugin.d.ts.map +1 -0
  79. package/dist/types/runtime-config.d.ts +4 -1
  80. package/dist/types/runtime-config.d.ts.map +1 -1
  81. package/package.json +20 -4
  82. package/dist/tasks/append-ignore-rule/index.d.ts +0 -10
  83. package/dist/tasks/append-ignore-rule/index.d.ts.map +0 -1
package/dist/cli.js CHANGED
@@ -4,7 +4,27 @@
4
4
  import semver from "semver";
5
5
  import { Argument, Command, Option } from "commander";
6
6
 
7
- // src/tasks/index.ts
7
+ // src/constants/supported-methods.ts
8
+ var SupportedMethods = [
9
+ "get",
10
+ "post",
11
+ "put",
12
+ "delete",
13
+ "patch",
14
+ "head",
15
+ "options"
16
+ ];
17
+
18
+ // src/utils/logger.ts
19
+ import chalk from "chalk";
20
+ var logger = {
21
+ log: (str) => console.log(chalk.green(str)),
22
+ warn: (str) => console.warn(chalk.yellow(str)),
23
+ error: (str) => console.error(chalk.red(str))
24
+ };
25
+
26
+ // src/compiler/compiler.ts
27
+ import { AsyncSeriesHook, AsyncSeriesWaterfallHook, SyncHook } from "tapable";
8
28
  import { Listr } from "listr2";
9
29
 
10
30
  // src/tasks/setup/index.ts
@@ -81,7 +101,8 @@ var RuntimeConfig = Type2.Object({
81
101
  /**
82
102
  * Whether to tolerate wrong swagger structure
83
103
  */
84
- tolerant: Type2.Optional(Type2.Boolean({ default: false }))
104
+ tolerant: Type2.Optional(Type2.Boolean({ default: false })),
105
+ plugins: Type2.Optional(Type2.Array(Type2.Any(), { default: [] }))
85
106
  });
86
107
 
87
108
  // src/utils/ignore-matcher.ts
@@ -232,9 +253,8 @@ function getProjectModuleSystem(pkgInfo) {
232
253
 
233
254
  // src/tasks/setup/index.ts
234
255
  var explore = cosmiconfig("keq");
235
- function createSetupTask(options) {
256
+ function main(compiler, options) {
236
257
  return {
237
- title: "Setup",
238
258
  task: async (context, task) => {
239
259
  const result = options?.config ? await explore.load(options.config) : await explore.search();
240
260
  if (!result || "isEmpty" in result && result.isEmpty) {
@@ -259,13 +279,23 @@ function createSetupTask(options) {
259
279
  const moduleSystem = getProjectModuleSystem(packageJsonInfo);
260
280
  rc.esm = moduleSystem === "esm";
261
281
  }
262
- let filter2 = new IgnoreMatcher([]);
282
+ let matcher = new IgnoreMatcher([]);
263
283
  if (result.filepath) {
264
284
  const ignoreFilepath = path2.resolve(path2.dirname(result.filepath), ".keqignore");
265
285
  if (await fs3.exists(ignoreFilepath)) {
266
- filter2 = await IgnoreMatcher.read(ignoreFilepath);
286
+ matcher = await IgnoreMatcher.read(ignoreFilepath);
267
287
  }
268
288
  }
289
+ const ignoreRules = options.ignore === false ? [] : options.ignore?.rules || [];
290
+ for (const rule of ignoreRules) {
291
+ matcher.append({
292
+ persist: !!rule.persist,
293
+ ignore: rule.ignore,
294
+ moduleName: rule.moduleName,
295
+ operationMethod: rule.operationMethod,
296
+ operationPathname: rule.operationPathname
297
+ });
298
+ }
269
299
  if (options?.modules && options.modules.length) {
270
300
  const notExistModules = options.modules.filter((moduleName) => !(moduleName in rc.modules));
271
301
  if (notExistModules.length) {
@@ -273,7 +303,7 @@ function createSetupTask(options) {
273
303
  }
274
304
  const ignoredModules = R3.difference(R3.keys(rc.modules), options.modules);
275
305
  for (const moduleName of ignoredModules) {
276
- filter2.append({
306
+ matcher.append({
277
307
  persist: false,
278
308
  ignore: true,
279
309
  moduleName,
@@ -282,10 +312,33 @@ function createSetupTask(options) {
282
312
  });
283
313
  }
284
314
  }
285
- context.setup = { rc, matcher: filter2 };
315
+ context.setup = { rc, matcher };
316
+ if (rc.plugins && rc.plugins.length) {
317
+ for (const plugin of rc.plugins) {
318
+ plugin.apply(compiler);
319
+ }
320
+ }
286
321
  }
287
322
  };
288
323
  }
324
+ function createSetupTask(compiler, options) {
325
+ return {
326
+ title: "Setup",
327
+ enabled: options?.enabled,
328
+ skip: options?.skip,
329
+ task: (context, task) => task.newListr(
330
+ [
331
+ main(compiler, options),
332
+ {
333
+ task: (context2, task2) => compiler.hooks.afterSetup.promise(task2)
334
+ }
335
+ ],
336
+ {
337
+ concurrent: false
338
+ }
339
+ )
340
+ };
341
+ }
289
342
 
290
343
  // src/tasks/download/index.ts
291
344
  import { PRESET_TIMER } from "listr2";
@@ -311,17 +364,6 @@ import { upgrade, validate } from "@scalar/openapi-parser";
311
364
  // src/tasks/utils/api-document_v3_1.ts
312
365
  import * as R6 from "ramda";
313
366
 
314
- // src/constants/supported-methods.ts
315
- var SupportedMethods = [
316
- "get",
317
- "post",
318
- "put",
319
- "delete",
320
- "patch",
321
- "head",
322
- "options"
323
- ];
324
-
325
367
  // src/tasks/utils/operation-definition.ts
326
368
  import * as R5 from "ramda";
327
369
 
@@ -489,16 +531,8 @@ var OperationDefinition = class {
489
531
  }
490
532
  };
491
533
 
492
- // src/utils/logger.ts
493
- import chalk from "chalk";
494
- var logger = {
495
- log: (str) => console.log(chalk.green(str)),
496
- warn: (str) => console.warn(chalk.yellow(str)),
497
- error: (str) => console.error(chalk.red(str))
498
- };
499
-
500
534
  // src/tasks/utils/api-document_v3_1.ts
501
- import OpenapiShaking from "@opendoc/openapi-shaking";
535
+ import { openapiShakingSync } from "@opendoc/openapi-shaking";
502
536
  var ApiDocumentV3_1 = class _ApiDocumentV3_1 {
503
537
  module;
504
538
  swagger;
@@ -554,7 +588,7 @@ var ApiDocumentV3_1 = class _ApiDocumentV3_1 {
554
588
  });
555
589
  return filter2(operationDefinition);
556
590
  };
557
- const sharkedSwagger = OpenapiShaking.openapiShakingSync(
591
+ const sharkedSwagger = openapiShakingSync(
558
592
  this.swagger,
559
593
  isAccepted,
560
594
  { tolerant: true }
@@ -748,8 +782,8 @@ function dereferenceDeep($ref, swagger) {
748
782
  const stack = [$ref];
749
783
  let value;
750
784
  while (true) {
751
- const last = stack[stack.length - 1];
752
- value = dereference(last, swagger);
785
+ const last2 = stack[stack.length - 1];
786
+ value = dereference(last2, swagger);
753
787
  if (JsonSchemaUtils.isRef(value)) {
754
788
  if (!stack.includes(value.$ref)) {
755
789
  stack.push(value.$ref);
@@ -860,11 +894,8 @@ var ApiDocument = class _ApiDocument {
860
894
  };
861
895
 
862
896
  // src/tasks/download/index.ts
863
- function createDownloadTask(options) {
897
+ function main2(compiler, options) {
864
898
  return {
865
- title: "Download",
866
- enabled: options?.enabled,
867
- skip: options?.skip,
868
899
  task: (context, task) => {
869
900
  if (!context.setup) {
870
901
  throw new Error("Please run setup task first.");
@@ -902,13 +933,28 @@ function createDownloadTask(options) {
902
933
  }
903
934
  };
904
935
  }
905
-
906
- // src/tasks/validate/index.ts
907
- function createValidateTask(options) {
936
+ function createDownloadTask(compiler, options) {
908
937
  return {
909
- title: "Validate",
938
+ title: "Download",
910
939
  enabled: options?.enabled,
911
940
  skip: options?.skip,
941
+ task: (_, task) => task.newListr(
942
+ [
943
+ main2(compiler, options),
944
+ {
945
+ task: (context, task2) => compiler.hooks.afterDownload.promise(task2)
946
+ }
947
+ ],
948
+ {
949
+ concurrent: false
950
+ }
951
+ )
952
+ };
953
+ }
954
+
955
+ // src/tasks/validate/index.ts
956
+ function main3() {
957
+ return {
912
958
  task: (context, task) => {
913
959
  if (!context.setup) throw new Error("Please run setup task first.");
914
960
  if (!context.downloaded) throw new Error("Please run download task first.");
@@ -945,13 +991,28 @@ ${errors?.map((e) => ` - ${e.message}`).join("\n")}`;
945
991
  }
946
992
  };
947
993
  }
948
-
949
- // src/tasks/shaking/index.ts
950
- function createShakingTask(options) {
994
+ function createValidateTask(compiler, options) {
951
995
  return {
952
- title: "Shaking",
996
+ title: "Validate",
953
997
  enabled: options?.enabled,
954
998
  skip: options?.skip,
999
+ task: (context, task) => task.newListr(
1000
+ [
1001
+ main3(),
1002
+ {
1003
+ task: (context2, task2) => compiler.hooks.afterValidate.promise(task2)
1004
+ }
1005
+ ],
1006
+ {
1007
+ concurrent: false
1008
+ }
1009
+ )
1010
+ };
1011
+ }
1012
+
1013
+ // src/tasks/shaking/index.ts
1014
+ function main4(compiler, options) {
1015
+ return {
955
1016
  task: (context, task) => {
956
1017
  if (!context.setup) throw new Error("Please run setup task first.");
957
1018
  if (!context.validated) throw new Error("Please run validate task first.");
@@ -989,15 +1050,31 @@ function createShakingTask(options) {
989
1050
  }
990
1051
  };
991
1052
  }
1053
+ function createShakingTask(compiler, options) {
1054
+ return {
1055
+ title: "Shaking",
1056
+ enabled: options?.enabled,
1057
+ skip: options?.skip,
1058
+ task: (context, task) => task.newListr(
1059
+ [
1060
+ main4(compiler, options),
1061
+ {
1062
+ task: (context2, task2) => compiler.hooks.afterShaking.promise(task2)
1063
+ }
1064
+ ],
1065
+ {
1066
+ concurrent: false
1067
+ }
1068
+ )
1069
+ };
1070
+ }
992
1071
 
993
1072
  // src/tasks/persist/index.ts
994
1073
  import * as path6 from "path";
995
1074
  import fs6 from "fs-extra";
996
- function createPersistArtifactTask(options) {
1075
+ function createPersistArtifactTask() {
997
1076
  return {
998
1077
  title: "Write files",
999
- enabled: options?.persistArtifacts,
1000
- skip: options?.skip,
1001
1078
  task: async (context, task) => {
1002
1079
  if (!context.setup) throw new Error("Please run setup task first.");
1003
1080
  if (!context.compiled) throw new Error("Please run compile task first.");
@@ -1008,21 +1085,21 @@ function createPersistArtifactTask(options) {
1008
1085
  }
1009
1086
  const total = artifacts.length;
1010
1087
  let completed = 0;
1011
- await Promise.all(artifacts.map(async (artifact) => {
1088
+ const files = await Promise.all(artifacts.map(async (artifact) => {
1012
1089
  const realpath = `./${path6.join(rc.outdir, artifact.filepath)}`;
1013
1090
  await fs6.ensureFile(realpath);
1014
1091
  await fs6.writeFile(realpath, artifact.toCode({ esm: !!rc.esm }));
1015
1092
  completed += 1;
1016
1093
  task.output = `Persisted ${completed}/${total} files`;
1094
+ return { path: path6.resolve(realpath) };
1017
1095
  }));
1096
+ context.persisted = { files };
1018
1097
  }
1019
1098
  };
1020
1099
  }
1021
- function createPersistIgnoreTask(options) {
1100
+ function createPersistIgnoreTask() {
1022
1101
  return {
1023
1102
  title: "Update .keqignore",
1024
- enabled: options?.persistIgnore,
1025
- skip: options?.skip,
1026
1103
  task: async (context, task) => {
1027
1104
  if (!context.setup) throw new Error("Please run setup task first.");
1028
1105
  const matcher = context.setup.matcher;
@@ -1030,15 +1107,12 @@ function createPersistIgnoreTask(options) {
1030
1107
  }
1031
1108
  };
1032
1109
  }
1033
- function createPersistTask(options) {
1110
+ function main5() {
1034
1111
  return {
1035
- title: "Persist",
1036
- enabled: options?.enabled,
1037
- skip: options?.skip,
1038
1112
  task: (context, task) => task.newListr(
1039
1113
  [
1040
- createPersistArtifactTask(options),
1041
- createPersistIgnoreTask(options)
1114
+ createPersistArtifactTask(),
1115
+ createPersistIgnoreTask()
1042
1116
  ],
1043
1117
  {
1044
1118
  concurrent: true,
@@ -1049,8 +1123,29 @@ function createPersistTask(options) {
1049
1123
  )
1050
1124
  };
1051
1125
  }
1126
+ function createPersistTask(compiler, options) {
1127
+ return {
1128
+ title: "Persist",
1129
+ enabled: options?.enabled,
1130
+ skip: options?.skip,
1131
+ task: (context, task) => task.newListr(
1132
+ [
1133
+ main5(),
1134
+ {
1135
+ task: (context2, task2) => compiler.hooks.afterPersist.promise(task2)
1136
+ }
1137
+ ],
1138
+ {
1139
+ concurrent: false
1140
+ }
1141
+ )
1142
+ };
1143
+ }
1052
1144
 
1053
1145
  // src/tasks/compile/utils/compile-schema-definition.ts
1146
+ import * as R14 from "ramda";
1147
+
1148
+ // src/renderer/json-schema/index.ts
1054
1149
  import * as R12 from "ramda";
1055
1150
 
1056
1151
  // src/renderer/utils/generate-schema.ts
@@ -1176,14 +1271,102 @@ async function jsonSchemaRenderer(schemaDefinition) {
1176
1271
  let $comment = generateComment(schemaDefinition.schema);
1177
1272
  if ($comment) $comment += "\n";
1178
1273
  if (typeof schemaDefinition.schema === "boolean") {
1179
- return `${$comment}type ${schemaDefinition.name} = unknown`;
1274
+ return [
1275
+ "/* @anchor:file:start */",
1276
+ "",
1277
+ $comment || void 0,
1278
+ `type ${schemaDefinition.name} = unknown`,
1279
+ "",
1280
+ "/* @anchor:file:end */"
1281
+ ].filter(R12.isNotNil).join("\n");
1180
1282
  }
1181
1283
  if (JsonSchemaUtils.isNonArray(schemaDefinition.schema) && schemaDefinition.schema.type === "object") {
1182
- return `${$comment}export interface ${schemaDefinition.name} ${generateSchema(schemaDefinition.schema)}`;
1284
+ return [
1285
+ "/* @anchor:file:start */",
1286
+ "",
1287
+ $comment || void 0,
1288
+ `export interface ${schemaDefinition.name} ${generateSchema(schemaDefinition.schema)}`,
1289
+ "",
1290
+ "/* @anchor:file:end */"
1291
+ ].filter(R12.isNotNil).join("\n");
1183
1292
  }
1184
- return `${$comment}export type ${schemaDefinition.name} = ${generateSchema(schemaDefinition.schema)}`;
1293
+ return [
1294
+ "/* @anchor:file:start */",
1295
+ "",
1296
+ $comment || void 0,
1297
+ `export type ${schemaDefinition.name} = ${generateSchema(schemaDefinition.schema)}`,
1298
+ "",
1299
+ "/* @anchor:file:end */"
1300
+ ].filter(R12.isNotNil).join("\n");
1185
1301
  }
1186
1302
 
1303
+ // src/tasks/utils/anchor.ts
1304
+ var AnchorBlock = class {
1305
+ constructor(artifact) {
1306
+ this.artifact = artifact;
1307
+ }
1308
+ /**
1309
+ * Append content to the end of the anchor block.
1310
+ */
1311
+ append(anchorName, content) {
1312
+ const lines = this.artifact.content.split("\n");
1313
+ const anchor = `@anchor:${anchorName}:end`;
1314
+ const anchorIndex = lines.findIndex((line) => line.includes(`/* ${anchor} */`));
1315
+ if (anchorIndex === -1) {
1316
+ throw new Error(`"${anchor}" not found in artifact "${this.artifact.filepath}".`);
1317
+ }
1318
+ lines.splice(anchorIndex, 0, content);
1319
+ this.artifact.content = lines.join("\n");
1320
+ }
1321
+ prepend(anchorName, content) {
1322
+ const lines = this.artifact.content.split("\n");
1323
+ const anchor = `@anchor:${anchorName}:start`;
1324
+ const anchorIndex = lines.findIndex((line) => line.includes(`/* ${anchor} */`));
1325
+ if (anchorIndex === -1) {
1326
+ throw new Error(`"${anchor}" not found in artifact "${this.artifact.filepath}".`);
1327
+ }
1328
+ lines.splice(anchorIndex + 1, 0, content);
1329
+ this.artifact.content = lines.join("\n");
1330
+ }
1331
+ replace(anchorName, content) {
1332
+ const lines = this.artifact.content.split("\n");
1333
+ const startIndex = lines.findIndex((line) => line.includes(`/* @anchor:${anchorName}:start */`));
1334
+ const endIndex = lines.findIndex((line) => line.includes(`/* @anchor:${anchorName}:end */`));
1335
+ if (startIndex === -1 || endIndex === -1 || endIndex <= startIndex) {
1336
+ throw new Error(`"@anchor:${anchorName}:start" or "@anchor:${anchorName}:end" not found in artifact "${this.artifact.filepath}".`);
1337
+ }
1338
+ lines.splice(startIndex + 1, endIndex - startIndex - 1, content);
1339
+ this.artifact.content = lines.join("\n");
1340
+ }
1341
+ };
1342
+ var Anchor = class {
1343
+ constructor(artifact) {
1344
+ this.artifact = artifact;
1345
+ this.block = new AnchorBlock(artifact);
1346
+ }
1347
+ block;
1348
+ append(anchorName, content) {
1349
+ const lines = this.artifact.content.split("\n");
1350
+ const anchor = `@anchor:${anchorName}`;
1351
+ const anchorIndex = lines.findIndex((line) => line.includes(`/* ${anchor} */`));
1352
+ if (anchorIndex === -1) {
1353
+ throw new Error(`"${anchor}" not found in artifact "${this.artifact.filepath}".`);
1354
+ }
1355
+ lines.splice(anchorIndex + 1, 0, content);
1356
+ this.artifact.content = lines.join("\n");
1357
+ }
1358
+ prepend(anchorName, content) {
1359
+ const lines = this.artifact.content.split("\n");
1360
+ const anchor = `@anchor:${anchorName}`;
1361
+ const anchorIndex = lines.findIndex((line) => line.includes(`/* ${anchor} */`));
1362
+ if (anchorIndex === -1) {
1363
+ throw new Error(`"${anchor}" not found in artifact "${this.artifact.filepath}".`);
1364
+ }
1365
+ lines.splice(anchorIndex, 0, content);
1366
+ this.artifact.content = lines.join("\n");
1367
+ }
1368
+ };
1369
+
1187
1370
  // src/tasks/utils/artifact.ts
1188
1371
  import * as path8 from "path";
1189
1372
  import * as changeCase from "change-case";
@@ -1268,6 +1451,7 @@ var Artifact = class {
1268
1451
  warns = [];
1269
1452
  content;
1270
1453
  extensionName;
1454
+ anchor = new Anchor(this);
1271
1455
  constructor(options) {
1272
1456
  this.id = options.id;
1273
1457
  this.filepath = options.filepath;
@@ -1324,6 +1508,10 @@ var Artifact = class {
1324
1508
  }
1325
1509
  };
1326
1510
 
1511
+ // src/tasks/utils/json-schema.ts
1512
+ import * as R13 from "ramda";
1513
+ import { JSONPath as JSONPath5 } from "jsonpath-plus";
1514
+
1327
1515
  // src/tasks/compile/utils/compile-schema-definition.ts
1328
1516
  function genSchemaDefinitionFilepath(schemaDefinition) {
1329
1517
  const filename = `${schemaDefinition.name}.schema.ts`;
@@ -1348,17 +1536,18 @@ var isArtifactCompiledBy = function(schemaDefinition) {
1348
1536
  return (artifact) => artifact.id === genSchemaDefinitionFilepath(schemaDefinition);
1349
1537
  };
1350
1538
  async function compileSchemaDefinition(options) {
1351
- const { schemaDefinitions } = options;
1539
+ const { task, compiler, schemaDefinitions } = options;
1352
1540
  const artifacts = await Promise.all(
1353
1541
  schemaDefinitions.map(async (schemaDefinition) => {
1354
1542
  const content = await jsonSchemaRenderer(schemaDefinition);
1355
1543
  const filepath = genSchemaDefinitionFilepath(schemaDefinition);
1356
- return new Artifact({
1544
+ const artifact = new Artifact({
1357
1545
  id: filepath,
1358
1546
  filepath,
1359
1547
  content,
1360
1548
  extensionName: ".schema.ts"
1361
1549
  });
1550
+ return await compiler.hooks.afterCompileSchema.promise(artifact, schemaDefinition, task);
1362
1551
  })
1363
1552
  );
1364
1553
  for (const schemaDefinition of schemaDefinitions) {
@@ -1374,7 +1563,7 @@ async function compileSchemaDefinition(options) {
1374
1563
  artifact.addDependence(dependentArtifact, [dependentSchemaDefinition.name]);
1375
1564
  }
1376
1565
  }
1377
- const schemaDefinitionsGroupByModuleName = R12.groupBy(
1566
+ const schemaDefinitionsGroupByModuleName = R14.groupBy(
1378
1567
  (schemaDefinition) => schemaDefinition.module.name,
1379
1568
  schemaDefinitions
1380
1569
  );
@@ -1399,41 +1588,93 @@ async function compileSchemaDefinition(options) {
1399
1588
  }
1400
1589
 
1401
1590
  // src/tasks/compile/utils/compile-operation-definition.ts
1402
- import * as R15 from "ramda";
1591
+ import * as R17 from "ramda";
1403
1592
 
1404
1593
  // src/renderer/operation-type/index.ts
1405
- import * as R13 from "ramda";
1594
+ import * as R15 from "ramda";
1406
1595
  import * as changeCase2 from "change-case";
1407
1596
  function typeNameFactory(operationDefinition) {
1408
1597
  const pascalCaseOperationId = changeCase2.pascalCase(operationDefinition.operationId);
1409
1598
  return (name) => `${pascalCaseOperationId}${name}`;
1410
1599
  }
1411
- async function operationTypeRenderer(operationDefinition, alias = R13.identity) {
1412
- const { operation } = operationDefinition;
1413
- if (!operation.responses) return "";
1414
- const typeName = typeNameFactory(operationDefinition);
1600
+ function responseBodies(operation, alias = R15.identity, typeName) {
1601
+ if (!operation.responses || R15.isEmpty(operation.responses)) {
1602
+ return `export interface ${typeName("ResponseBodies")} {}`;
1603
+ }
1415
1604
  const $responses = Object.entries(operation.responses).map(([statusCode, response]) => {
1416
1605
  if (!JsonSchemaUtils.isRef(response)) {
1417
1606
  const $value = Object.values(response.content || {}).map((mediaTypeObject) => mediaTypeObject.schema).filter((schema) => !!schema).map((schema) => generateSchema(schema, alias)).join(" | ");
1418
1607
  return indent(2, `${statusCode}: ${$value || "void"}`);
1419
1608
  }
1420
1609
  }).join("\n");
1421
- let $requestBody = `export type ${typeName("RequestBody")} = {}`;
1422
- if (operation.requestBody && !JsonSchemaUtils.isRef(operation.requestBody)) {
1423
- const $value = Object.entries(operation.requestBody.content || {}).map(([mediaType, mediaTypeObject]) => [mediaType, mediaTypeObject.schema]).filter(([, schema]) => !!schema).map(([mediaType, schema]) => {
1424
- if (mediaType === "multipart/form-data") {
1425
- return `FormData | ${generateSchema(schema, alias)}`;
1426
- } else if (mediaType === "application/x-www-form-urlencoded") {
1427
- return `URLSearchParams | ${generateSchema(schema, alias)}`;
1428
- }
1429
- return generateSchema(schema, alias);
1430
- }).join(" | ");
1431
- $requestBody = `export type ${typeName("RequestBody")} = ${$value || "unknown"}`;
1432
- }
1433
1610
  return [
1434
1611
  `export interface ${typeName("ResponseBodies")} {`,
1435
1612
  $responses,
1436
- "}",
1613
+ "}"
1614
+ ].join("\n");
1615
+ }
1616
+ function requestBodies(operation, alias = R15.identity, typeName) {
1617
+ let $requestBodies = `export interface ${typeName("RequestBodies")} {}`;
1618
+ if (operation.requestBody && !JsonSchemaUtils.isRef(operation.requestBody)) {
1619
+ const $mediaTypes = Object.entries(operation.requestBody.content || {}).map(([mediaType, mediaTypeObject]) => [mediaType, mediaTypeObject.schema]).map(([mediaType, schema]) => {
1620
+ if (!schema) return `${JSON.stringify(mediaType)}: unknown`;
1621
+ return `${JSON.stringify(mediaType)}: ${generateSchema(schema, alias)}`;
1622
+ }).map((pair) => indent(2, pair));
1623
+ $requestBodies = [
1624
+ `export interface ${typeName("RequestBodies")} {`,
1625
+ ...$mediaTypes,
1626
+ "}"
1627
+ ].join("\n");
1628
+ }
1629
+ return $requestBodies;
1630
+ }
1631
+ function parameterBodies(operationDefinition, alias = R15.identity, typeName) {
1632
+ const { operation } = operationDefinition;
1633
+ let parameterBodies2 = "";
1634
+ if (operation.requestBody && !JsonSchemaUtils.isRef(operation.requestBody)) {
1635
+ const $mediaTypes = Object.entries(operation.requestBody.content || {}).map(([mediaType, mediaTypeObject]) => [mediaType, mediaTypeObject.schema]).map(([mediaType, schemaOrRef]) => {
1636
+ if (!schemaOrRef) return `${JSON.stringify(mediaType)}: unknown`;
1637
+ const schema = JsonSchemaUtils.isRef(schemaOrRef) ? SwaggerUtils.dereferenceDeep(schemaOrRef.$ref, operationDefinition.document.swagger) : schemaOrRef;
1638
+ if (schema.type === "object" || schema.properties) {
1639
+ return `${JSON.stringify(mediaType)}: ${generateSchema(schemaOrRef, alias)} & { [key: string]: any }`;
1640
+ }
1641
+ return `${JSON.stringify(mediaType)}: { [key: string]: any }`;
1642
+ }).map((pair) => indent(2, pair));
1643
+ parameterBodies2 = [
1644
+ `interface ${typeName("ParameterBodies")} {`,
1645
+ ...$mediaTypes,
1646
+ "}",
1647
+ ""
1648
+ ].join("\n");
1649
+ }
1650
+ return parameterBodies2;
1651
+ }
1652
+ function requestParameters(operation, alias = R15.identity, typeName) {
1653
+ const mediaTypes = operation.requestBody && !JsonSchemaUtils.isRef(operation.requestBody) ? Object.keys(operation.requestBody.content || {}) : [];
1654
+ const base = `${typeName("RequestQuery")} & ${typeName("RouteParameters")} & ${typeName("RequestHeaders")}`;
1655
+ if (mediaTypes.length === 1) {
1656
+ return `export type ${typeName("RequestParameters")} = ${base} & ${typeName("RequestBodies")}[${JSON.stringify(mediaTypes[0])}]`;
1657
+ }
1658
+ if (mediaTypes.length > 1) {
1659
+ const unions = mediaTypes.map((mediaType) => `(${base} & ${typeName("RequestBodies")}[${JSON.stringify(mediaType)}] & { "content-type": ${JSON.stringify(mediaType)} })`).join("\n| ");
1660
+ return `export type ${typeName("RequestParameters")} = ${unions}`;
1661
+ }
1662
+ return `export type ${typeName("RequestParameters")} = ${base}`;
1663
+ }
1664
+ async function operationTypeRenderer(operationDefinition, alias = R15.identity) {
1665
+ const { operation } = operationDefinition;
1666
+ if (!operation.responses) return "";
1667
+ const typeName = typeNameFactory(operationDefinition);
1668
+ const $responseBodies = responseBodies(operation, alias, typeName);
1669
+ const $requestBodies = requestBodies(operation, alias, typeName);
1670
+ const $parameterBodies = parameterBodies(operationDefinition, alias, typeName);
1671
+ const $requestParameters = requestParameters(operation, alias, typeName);
1672
+ return [
1673
+ "/* @anchor:file:start */",
1674
+ "",
1675
+ $responseBodies,
1676
+ "",
1677
+ $requestBodies,
1437
1678
  "",
1438
1679
  generateParameters(`${typeName("RequestQuery")}`, operation.parameters?.filter((p) => !JsonSchemaUtils.isRef(p) && p.in === "query") || [], alias),
1439
1680
  "",
@@ -1441,18 +1682,19 @@ async function operationTypeRenderer(operationDefinition, alias = R13.identity)
1441
1682
  "",
1442
1683
  generateParameters(`${typeName("RequestHeaders")}`, operation.parameters?.filter((p) => !JsonSchemaUtils.isRef(p) && p.in === "header") || [], alias),
1443
1684
  "",
1444
- $requestBody,
1685
+ $parameterBodies || void 0,
1686
+ $requestParameters,
1445
1687
  "",
1446
- `export type ${typeName("RequestParameters")} = ${typeName("RequestQuery")} & ${typeName("RouteParameters")} & ${typeName("RequestHeaders")} & ${typeName("RequestBody")}`,
1447
- "",
1448
- `export interface Operation<STATUS extends keyof ${typeName("ResponseBodies")}> extends KeqOperation {`,
1449
- ` requestParams: ${typeName("RouteParameters")} & { [key: string]: KeqParamValue }`,
1450
- ` requestQuery: ${typeName("RequestQuery")} & { [key: string]: KeqQueryValue }`,
1688
+ `export interface Operation<STATUS extends keyof ${typeName("ResponseBodies")}, CONTENT_TYPE extends keyof ${typeName("ParameterBodies")}> extends KeqOperation {`,
1689
+ ` requestParams: ${typeName("RouteParameters")} & { [key: string]: KeqPathParameterInit }`,
1690
+ ` requestQuery: ${typeName("RequestQuery")} & { [key: string]: KeqQueryInit }`,
1451
1691
  ` requestHeaders: ${typeName("RequestHeaders")} & { [key: string]: string | number }`,
1452
- ` requestBody: ${typeName("RequestBody")}`,
1692
+ ` requestBody: ${$parameterBodies ? `${typeName("ParameterBodies")}[CONTENT_TYPE] | ` : "object | "}BodyInit`,
1453
1693
  ` responseBody: ${typeName("ResponseBodies")}[STATUS]`,
1454
- "}"
1455
- ].join("\n");
1694
+ "}",
1695
+ "",
1696
+ "/* @anchor:file:end */"
1697
+ ].filter(R15.isNotNil).join("\n");
1456
1698
  }
1457
1699
  function generateParameters(name, parameters, alias) {
1458
1700
  if (parameters.length === 0) {
@@ -1472,7 +1714,7 @@ function generateParameters(name, parameters, alias) {
1472
1714
  }
1473
1715
 
1474
1716
  // src/renderer/operation-request/index.ts
1475
- import * as R14 from "ramda";
1717
+ import * as R16 from "ramda";
1476
1718
  function errorToComment(err, mediaType) {
1477
1719
  const $err = String(err).split("\n").map(((line) => ` * ${line}`)).join("\n");
1478
1720
  return [
@@ -1482,23 +1724,8 @@ function errorToComment(err, mediaType) {
1482
1724
  " */"
1483
1725
  ].join("\n");
1484
1726
  }
1485
- async function operationRequestRenderer(operationDefinition, options) {
1486
- const { operation, operationId, method, pathname } = operationDefinition;
1487
- const { qs } = options;
1488
- if (!operation.responses) return "";
1489
- const typeName = typeNameFactory(operationDefinition);
1490
- const moduleName = operationDefinition.module.name;
1491
- const parameters = operation.parameters?.filter((p) => !JsonSchemaUtils.isRef(p)) || [];
1492
- const queryParameters = parameters.filter((p) => p.in === "query");
1493
- const headersParameters = parameters.filter((p) => p.in === "header");
1494
- const pathParameters = parameters.filter((p) => p.in === "path");
1495
- const $queryParameters = queryParameters.map((p) => {
1496
- const option = qs(p);
1497
- const $option = !option || R14.isEmpty(option) ? "" : `, ${JSON.stringify(option)}`;
1498
- return ` if (args && ${JSON.stringify(p.name)} in args) req.query(${JSON.stringify(p.name)}, args[${JSON.stringify(p.name)}]${$option})`;
1499
- }).concat("").join("\n");
1500
- const $headerParameters = headersParameters.map((p) => ` if (args && ${JSON.stringify(p.name)} in args) req.header(${JSON.stringify(p.name)}, args[${JSON.stringify(p.name)}])`).concat("").join("\n");
1501
- const $pathParameters = pathParameters.map((p) => ` if (args && ${JSON.stringify(p.name)} in args) req.params(${JSON.stringify(p.name)}, args[${JSON.stringify(p.name)}])`).concat("").join("\n");
1727
+ function requestBodyRenderer(operationDefinition, typeName) {
1728
+ const { operation } = operationDefinition;
1502
1729
  const requestBodyContent = operation.requestBody?.content || {};
1503
1730
  const $requestBody = Object.entries(requestBodyContent).map(([mediaType, mediaTypeObject]) => {
1504
1731
  if (!mediaTypeObject.schema) return;
@@ -1527,27 +1754,107 @@ async function operationRequestRenderer(operationDefinition, options) {
1527
1754
  } catch (err) {
1528
1755
  return indent(2, errorToComment(err, mediaType));
1529
1756
  }
1530
- }).filter(R14.isNotNil).join("\n");
1757
+ }).filter(R16.isNotNil).join("\n");
1758
+ return $requestBody;
1759
+ }
1760
+ function requestHeadersRenderer(operationDefinition, typeName) {
1761
+ const { operation } = operationDefinition;
1762
+ const $headers = (operation.parameters || []).filter((p) => !JsonSchemaUtils.isRef(p)).filter((p) => p.in === "header").map((p) => ` if (args && ${JSON.stringify(p.name)} in args) req.header(${JSON.stringify(p.name)}, args[${JSON.stringify(p.name)}])`).concat("").join("\n");
1763
+ return $headers;
1764
+ }
1765
+ function requestQueryRenderer(operationDefinition, qs, typeName) {
1766
+ const { operation } = operationDefinition;
1767
+ const $query = (operation.parameters || []).filter((p) => !JsonSchemaUtils.isRef(p)).filter((p) => p.in === "query").map((p) => {
1768
+ const option = qs(p);
1769
+ const $option = !option || R16.isEmpty(option) ? "" : `, ${JSON.stringify(option)}`;
1770
+ return ` if (args && ${JSON.stringify(p.name)} in args) req.query(${JSON.stringify(p.name)}, args[${JSON.stringify(p.name)}]${$option})`;
1771
+ }).concat("").join("\n");
1772
+ return $query;
1773
+ }
1774
+ function requestPathParametersRenderer(operationDefinition, typeName) {
1775
+ const { operation } = operationDefinition;
1776
+ const $pathParameters = (operation.parameters || []).filter((p) => !JsonSchemaUtils.isRef(p)).filter((p) => p.in === "path").map((p) => ` if (args && ${JSON.stringify(p.name)} in args) req.params(${JSON.stringify(p.name)}, args[${JSON.stringify(p.name)}])`).concat("").join("\n");
1777
+ return $pathParameters;
1778
+ }
1779
+ function getRequestMediaTypes(operationDefinition) {
1780
+ const { operation } = operationDefinition;
1781
+ const requestBodyContent = operation.requestBody?.content || {};
1782
+ return Object.keys(requestBodyContent);
1783
+ }
1784
+ function mediaTypeRenderer(operationDefinition) {
1785
+ const mediaTypes = getRequestMediaTypes(operationDefinition);
1786
+ if (mediaTypes.length === 1 && !mediaTypes[0].endsWith("/*")) {
1787
+ return ` req.type("${mediaTypes[0]}")
1788
+ `;
1789
+ } else if (mediaTypes.some((mediaType) => mediaType === "*/*")) {
1790
+ } else if (mediaTypes.some((mediaType) => mediaType.endsWith("/*"))) {
1791
+ return ' if(args?.["content-type"]) req.type(args["content-type"])\n';
1792
+ } else if (mediaTypes.length > 1) {
1793
+ return ' if(args?.["content-type"]) req.type(args["content-type"])\n';
1794
+ }
1795
+ return "";
1796
+ }
1797
+ function operationDeclarationRenderer(operationDefinition, typeName) {
1798
+ const { operationId } = operationDefinition;
1799
+ const mediaTypes = getRequestMediaTypes(operationDefinition);
1800
+ if (mediaTypes.length === 0) {
1801
+ return `function ${operationId}<STATUS extends keyof ${typeName("ResponseBodies")}>(args?: ${typeName("RequestParameters")}): Keq<Operation<STATUS, never>>`;
1802
+ } else if (mediaTypes.length === 1) {
1803
+ return `function ${operationId}<STATUS extends keyof ${typeName("ResponseBodies")}>(args?: ${typeName("RequestParameters")}): Keq<Operation<STATUS, ${JSON.stringify(mediaTypes[0])}>>`;
1804
+ } else if (mediaTypes.length > 1) {
1805
+ return `function ${operationId}<STATUS extends keyof ${typeName("ResponseBodies")}, CONTENT_TYPE extends ${typeName("RequestParameters")}["content-type"]>(args?: Extract<${typeName("RequestParameters")}, { "content-type": CONTENT_TYPE }>): Keq<Operation<STATUS, CONTENT_TYPE>>`;
1806
+ }
1807
+ throw new Error("[operationDeclarationRenderer] Unreachable");
1808
+ }
1809
+ async function operationRequestRenderer(operationDefinition, options) {
1810
+ const { operation, operationId, method, pathname } = operationDefinition;
1811
+ const { qs } = options;
1812
+ if (!operation.responses) return "";
1813
+ const typeName = typeNameFactory(operationDefinition);
1814
+ const moduleName = operationDefinition.module.name;
1815
+ const $queryParameters = requestQueryRenderer(operationDefinition, qs, typeName);
1816
+ const $headerParameters = requestHeadersRenderer(operationDefinition, typeName);
1817
+ const $pathParameters = requestPathParametersRenderer(operationDefinition, typeName);
1818
+ const $mediaType = mediaTypeRenderer(operationDefinition);
1819
+ const $requestBody = requestBodyRenderer(operationDefinition, typeName);
1820
+ const $operationDeclaration = operationDeclarationRenderer(operationDefinition, typeName);
1531
1821
  return [
1822
+ "/* @anchor:file:start */",
1823
+ "",
1532
1824
  `const moduleName = "${moduleName}"`,
1533
1825
  `const method = "${method}"`,
1534
1826
  `const pathname = "${pathname}"`,
1535
1827
  "",
1536
- `export function ${operationId}<STATUS extends keyof ${typeName("ResponseBodies")}>(args?: ${typeName("RequestParameters")}): Keq<Operation<STATUS>> {`,
1828
+ "/* @anchor:operation-declaration */",
1829
+ `export ${$operationDeclaration} {`,
1537
1830
  ` const req = request.post<${typeName("ResponseBodies")}[STATUS]>("${pathname}")`,
1538
1831
  " .option('module', { name: moduleName, pathname, method })",
1539
1832
  "",
1833
+ $mediaType || void 0,
1834
+ " /* @anchor:query:start */",
1540
1835
  $queryParameters || void 0,
1836
+ " /* @anchor:query:end */",
1837
+ "",
1838
+ " /* @anchor:headers:start */",
1541
1839
  $headerParameters || void 0,
1840
+ " /* @anchor:headers:end */",
1841
+ "",
1842
+ " /* @anchor:path-parameters:start */",
1542
1843
  $pathParameters || void 0,
1543
- $requestBody ? `${$requestBody}
1544
- ` : void 0,
1545
- " return req",
1844
+ " /* @anchor:path-parameters:end */",
1845
+ "",
1846
+ " /* @anchor:body:start */",
1847
+ $requestBody || void 0,
1848
+ " /* @anchor:body:end */",
1849
+ "",
1850
+ " /* @anchor:operation-return */",
1851
+ ` return req as ReturnType<typeof ${operationId}>`,
1546
1852
  "}",
1547
1853
  "",
1548
1854
  `${operationId}.pathname = pathname`,
1549
- `${operationId}.method = method`
1550
- ].filter(R14.isNotNil).join("\n");
1855
+ `${operationId}.method = method`,
1856
+ "/* @anchor:file:end */"
1857
+ ].filter(R16.isNotNil).join("\n");
1551
1858
  }
1552
1859
 
1553
1860
  // src/tasks/compile/utils/compile-operation-definition.ts
@@ -1578,7 +1885,7 @@ function genEntrypointFilepath2(moduleName) {
1578
1885
  ].join("/");
1579
1886
  }
1580
1887
  async function compileOperationDefinition(options) {
1581
- const { rc, requestArtifact, schemaArtifacts, operationDefinitions } = options;
1888
+ const { compiler, task, rc, requestArtifact, schemaArtifacts, operationDefinitions } = options;
1582
1889
  const alias = (name) => `${name}Schema`;
1583
1890
  const qs = (parameter) => {
1584
1891
  if (typeof rc.qs === "function") {
@@ -1612,7 +1919,7 @@ async function compileOperationDefinition(options) {
1612
1919
  content,
1613
1920
  extensionName: ".type.ts"
1614
1921
  });
1615
- typeArtifact.addDependence("keq", ["KeqOperation", "KeqQueryValue", "KeqParamValue"]);
1922
+ typeArtifact.addDependence("keq", ["KeqOperation", "KeqQueryInit", "KeqPathParameterInit"]);
1616
1923
  const dependentSchemaDefinitions = operationDefinition.getDependencies();
1617
1924
  for (const dependentSchemaDefinition of dependentSchemaDefinitions) {
1618
1925
  const dependentArtifact = schemaArtifacts.find(isArtifactCompiledBy(dependentSchemaDefinition));
@@ -1624,7 +1931,7 @@ async function compileOperationDefinition(options) {
1624
1931
  new DependencyIdentifier(dependentSchemaDefinition.name, alias(dependentSchemaDefinition.name))
1625
1932
  ]);
1626
1933
  }
1627
- return typeArtifact;
1934
+ return await compiler.hooks.afterCompileOperationType.promise(typeArtifact, operationDefinition, task);
1628
1935
  }
1629
1936
  async function createRequestArtifact(operationDefinition, typeArtifact) {
1630
1937
  const typeName = typeNameFactory(operationDefinition);
@@ -1651,13 +1958,13 @@ async function compileOperationDefinition(options) {
1651
1958
  [
1652
1959
  `${typeName("RequestQuery")}`,
1653
1960
  `${typeName("RequestHeaders")}`,
1654
- `${typeName("RequestBody")}`
1961
+ `${typeName("RequestBodies")}`
1655
1962
  ],
1656
1963
  { export: true }
1657
1964
  );
1658
- return artifact;
1965
+ return await compiler.hooks.afterCompileOperationRequest.promise(artifact, operationDefinition, task);
1659
1966
  }
1660
- const artifacts = R15.unnest(
1967
+ const artifacts = R17.unnest(
1661
1968
  await Promise.all(
1662
1969
  operationDefinitions.map(async (operationDefinition) => {
1663
1970
  const typeArtifact = await createTypeArtifact(operationDefinition);
@@ -1666,7 +1973,7 @@ async function compileOperationDefinition(options) {
1666
1973
  })
1667
1974
  )
1668
1975
  );
1669
- const operationDefinitionsGroupByModuleName = R15.groupBy(
1976
+ const operationDefinitionsGroupByModuleName = R17.groupBy(
1670
1977
  (operationDefinition) => operationDefinition.module.name,
1671
1978
  operationDefinitions
1672
1979
  );
@@ -1694,32 +2001,38 @@ async function compileOperationDefinition(options) {
1694
2001
  async function requestRenderer() {
1695
2002
  return [
1696
2003
  "import { KeqRequest } from 'keq'",
1697
- "export const request = new KeqRequest()"
2004
+ "",
2005
+ "/* @anchor:file:start */",
2006
+ "",
2007
+ "/* @anchor:request-declaration */",
2008
+ "export const request = new KeqRequest()",
2009
+ "",
2010
+ "/* @anchor:file:end"
1698
2011
  ].join("\n");
1699
2012
  }
1700
2013
 
1701
2014
  // src/tasks/compile/index.ts
1702
- function createCompileTask(options) {
2015
+ function main6(compiler) {
1703
2016
  return {
1704
- title: "Compile",
1705
- enabled: options?.enabled,
1706
- skip: options?.skip,
1707
2017
  task: async (context, task) => {
1708
2018
  if (!context.setup) throw new Error("Please run setup task first.");
1709
2019
  if (!context.shaken) throw new Error("Please run shaking task first.");
1710
2020
  const rc = context.setup.rc;
1711
2021
  const matcher = context.setup.matcher;
1712
2022
  const documents = context.shaken.documents.filter((document) => !matcher.isModuleIgnored(document.module));
1713
- const requestArtifact = new Artifact({
1714
- id: "request",
1715
- filepath: "request",
1716
- content: await requestRenderer(),
1717
- extensionName: ".ts"
1718
- });
2023
+ const requestArtifact = await compiler.hooks.afterCompileKeqRequest.promise(
2024
+ new Artifact({
2025
+ id: "request",
2026
+ filepath: "request",
2027
+ content: await requestRenderer(),
2028
+ extensionName: ".ts"
2029
+ }),
2030
+ task
2031
+ );
1719
2032
  const schemaDefinitions = documents.flatMap((document) => document.schemas);
1720
2033
  const operationDefinitions = documents.flatMap((document) => document.operations);
1721
- const schemaArtifacts = await compileSchemaDefinition({ schemaDefinitions });
1722
- const operationArtifacts = await compileOperationDefinition({ rc, operationDefinitions, schemaArtifacts, requestArtifact });
2034
+ const schemaArtifacts = await compileSchemaDefinition({ compiler, task, schemaDefinitions });
2035
+ const operationArtifacts = await compileOperationDefinition({ compiler, task, rc, operationDefinitions, schemaArtifacts, requestArtifact });
1723
2036
  const artifacts = [requestArtifact, ...schemaArtifacts, ...operationArtifacts];
1724
2037
  context.compiled = {
1725
2038
  artifacts
@@ -1727,24 +2040,22 @@ function createCompileTask(options) {
1727
2040
  }
1728
2041
  };
1729
2042
  }
1730
-
1731
- // src/tasks/append-ignore-rule/index.ts
1732
- function createAppendIgnoreRulesTask(options) {
2043
+ function createCompileTask(compiler, options) {
1733
2044
  return {
1734
- title: "Update .keqignore file",
1735
- task: (context, task) => {
1736
- if (!context.setup) throw new Error("Setup task has not been executed.");
1737
- const matcher = context.setup.matcher;
1738
- for (const rule of options.rules) {
1739
- matcher.append({
1740
- persist: true,
1741
- ignore: options.mode === "add",
1742
- moduleName: rule.moduleName,
1743
- operationMethod: rule.operationMethod,
1744
- operationPathname: rule.operationPathname
1745
- });
2045
+ title: "Compile",
2046
+ enabled: options?.enabled,
2047
+ skip: options?.skip,
2048
+ task: (context, task) => task.newListr(
2049
+ [
2050
+ main6(compiler),
2051
+ {
2052
+ task: (context2, task2) => compiler.hooks.afterCompile.promise(task2)
2053
+ }
2054
+ ],
2055
+ {
2056
+ concurrent: false
1746
2057
  }
1747
- }
2058
+ )
1748
2059
  };
1749
2060
  }
1750
2061
 
@@ -1783,7 +2094,7 @@ function createInteractiveTask(options) {
1783
2094
  const documents = context.validated.documents;
1784
2095
  const operationDefinitions = documents.flatMap((document) => document.operations);
1785
2096
  const selectedOperationDefinitions = await selectOperationDefinitions(task, operationDefinitions);
1786
- if (options.override) {
2097
+ if (options.clear) {
1787
2098
  matcher.append({
1788
2099
  persist: false,
1789
2100
  ignore: true,
@@ -1794,7 +2105,7 @@ function createInteractiveTask(options) {
1794
2105
  }
1795
2106
  for (const op of selectedOperationDefinitions) {
1796
2107
  matcher.append({
1797
- persist: true,
2108
+ persist: !!options.persist,
1798
2109
  ignore: options.mode === "add",
1799
2110
  moduleName: op.module.name,
1800
2111
  operationMethod: op.method,
@@ -1805,110 +2116,250 @@ function createInteractiveTask(options) {
1805
2116
  };
1806
2117
  }
1807
2118
 
1808
- // src/tasks/index.ts
1809
- async function build(options) {
1810
- const tasks = new Listr(
1811
- [
1812
- createSetupTask(options),
1813
- createDownloadTask({ skipIgnoredModules: !options.interactive }),
1814
- createValidateTask(),
1815
- createInteractiveTask({ mode: "except", override: true, enabled: !!options.interactive }),
1816
- createShakingTask({ skipIgnoredModules: true, skipEmptyDocuments: true }),
1817
- createCompileTask(),
1818
- createPersistTask({ persistIgnore: false })
1819
- ],
1820
- {
1821
- concurrent: false,
1822
- renderer: "default",
1823
- rendererOptions: {
1824
- suffixSkips: true,
1825
- collapseSubtasks: false,
1826
- collapseErrors: false
2119
+ // src/compiler/intercepter/perfect-error-message.ts
2120
+ import * as R18 from "ramda";
2121
+ function perfectErrorMessage() {
2122
+ return {
2123
+ register: (tap) => {
2124
+ const fn = tap.fn;
2125
+ function prefix(err) {
2126
+ if (err instanceof Error) {
2127
+ err.message = `[Plugin: ${tap.name}] ${err.message}`;
2128
+ }
2129
+ }
2130
+ if (tap.type === "promise") {
2131
+ tap.fn = async (...args) => {
2132
+ try {
2133
+ return await fn(...args);
2134
+ } catch (err) {
2135
+ prefix(err);
2136
+ throw err;
2137
+ }
2138
+ };
1827
2139
  }
2140
+ if (tap.type === "sync") {
2141
+ tap.fn = (...args) => {
2142
+ try {
2143
+ return fn(...args);
2144
+ } catch (err) {
2145
+ prefix(err);
2146
+ throw err;
2147
+ }
2148
+ };
2149
+ }
2150
+ if (tap.type === "async") {
2151
+ tap.fn = (...args) => {
2152
+ const callback = R18.last(args);
2153
+ return fn(...R18.init(args), (err, result) => {
2154
+ prefix(err);
2155
+ return callback(err, result);
2156
+ });
2157
+ };
2158
+ }
2159
+ return tap;
1828
2160
  }
1829
- );
1830
- await tasks.run({});
1831
- }
1832
- async function ignore(options) {
1833
- const tasks = new Listr(
1834
- [
1835
- createSetupTask(options),
1836
- createAppendIgnoreRulesTask(options),
1837
- createDownloadTask({ enabled: !!options.interactive }),
1838
- createValidateTask({ enabled: !!options.interactive }),
1839
- createInteractiveTask({ mode: options.mode, override: false, enabled: !!options.interactive }),
1840
- createShakingTask({ enabled: !!options.build, skipIgnoredModules: true, skipEmptyDocuments: true }),
1841
- createCompileTask({ enabled: !!options.build }),
1842
- createPersistTask({ persistArtifacts: !!options.build, persistIgnore: true })
1843
- ],
1844
- {
1845
- concurrent: false,
1846
- renderer: "default",
1847
- rendererOptions: {
1848
- suffixSkips: true,
1849
- collapseSubtasks: false,
1850
- collapseErrors: false
2161
+ };
2162
+ }
2163
+
2164
+ // src/compiler/intercepter/print-information.ts
2165
+ function proxyTaskWrapper(pluginName, task) {
2166
+ return new Proxy(task, {
2167
+ set(target, prop2, value) {
2168
+ if (prop2 !== "output") {
2169
+ return Reflect.set(target, prop2, value);
1851
2170
  }
2171
+ target.output = `[Plugin: ${pluginName}] ${value}`;
2172
+ return true;
1852
2173
  }
1853
- );
1854
- await tasks.run({});
2174
+ });
2175
+ }
2176
+ function printInformation(taskIndex) {
2177
+ return {
2178
+ register: (tap) => {
2179
+ const fn = tap.fn;
2180
+ if (tap.type === "promise") {
2181
+ tap.fn = (...args) => {
2182
+ const task = args[taskIndex];
2183
+ const proxyTask = proxyTaskWrapper(tap.name, task);
2184
+ args[taskIndex] = proxyTask;
2185
+ proxyTask.output = "Processing...";
2186
+ return fn(...args);
2187
+ };
2188
+ }
2189
+ if (tap.type === "sync") {
2190
+ tap.fn = (...args) => {
2191
+ const task = args[taskIndex];
2192
+ const proxyTask = proxyTaskWrapper(tap.name, task);
2193
+ args[taskIndex] = proxyTask;
2194
+ proxyTask.output = "Processing...";
2195
+ return fn(...args);
2196
+ };
2197
+ }
2198
+ if (tap.type === "async") {
2199
+ tap.fn = (...args) => {
2200
+ const task = args[taskIndex];
2201
+ const proxyTask = proxyTaskWrapper(tap.name, task);
2202
+ args[taskIndex] = proxyTask;
2203
+ proxyTask.output = "Processing...";
2204
+ return fn(...args);
2205
+ };
2206
+ }
2207
+ return tap;
2208
+ }
2209
+ };
1855
2210
  }
1856
2211
 
2212
+ // src/compiler/compiler.ts
2213
+ var Compiler = class {
2214
+ constructor(options) {
2215
+ this.options = options;
2216
+ for (const hook of Object.values(this.hooks)) {
2217
+ hook.intercept(perfectErrorMessage());
2218
+ }
2219
+ this.hooks.afterSetup.intercept(printInformation(0));
2220
+ this.hooks.afterPersist.intercept(printInformation(0));
2221
+ }
2222
+ context = {};
2223
+ hooks = {
2224
+ // core
2225
+ afterSetup: new AsyncSeriesHook(["task"]),
2226
+ afterDownload: new AsyncSeriesHook(["task"]),
2227
+ afterValidate: new AsyncSeriesHook(["task"]),
2228
+ afterShaking: new AsyncSeriesHook(["task"]),
2229
+ afterCompile: new AsyncSeriesHook(["task"]),
2230
+ afterPersist: new AsyncSeriesHook(["task"]),
2231
+ done: new SyncHook(),
2232
+ // compile
2233
+ afterCompileKeqRequest: new AsyncSeriesWaterfallHook(["artifact", "task"]),
2234
+ afterCompileSchema: new AsyncSeriesWaterfallHook(["artifact", "schema", "task"]),
2235
+ afterCompileOperationType: new AsyncSeriesWaterfallHook(["artifact", "operation", "task"]),
2236
+ afterCompileOperationRequest: new AsyncSeriesWaterfallHook(["artifact", "operation", "task"])
2237
+ };
2238
+ async run() {
2239
+ const options = this.options;
2240
+ const tasks = new Listr(
2241
+ [
2242
+ createSetupTask(this, options),
2243
+ createDownloadTask(this, { skipIgnoredModules: !options.interactive }),
2244
+ createValidateTask(this, { enabled: !!options.build }),
2245
+ createInteractiveTask({ enabled: !!options.interactive, ...typeof options.interactive === "object" ? options.interactive : { mode: "except" } }),
2246
+ createShakingTask(this, { enabled: !!options.build, ...typeof options.build === "object" ? options.build.shaking : void 0 }),
2247
+ createCompileTask(this, { enabled: !!options.build }),
2248
+ createPersistTask(this, { enabled: !!options.build })
2249
+ ],
2250
+ {
2251
+ concurrent: false,
2252
+ renderer: "default",
2253
+ rendererOptions: {
2254
+ suffixSkips: true,
2255
+ collapseSubtasks: false,
2256
+ collapseErrors: false
2257
+ }
2258
+ }
2259
+ );
2260
+ await tasks.run(this.context);
2261
+ await this.hooks.done.promise();
2262
+ }
2263
+ };
2264
+
1857
2265
  // src/cli.ts
1858
2266
  if (semver.lt(process.version, "18.0.0")) {
1859
2267
  throw new Error("Node.js version must be greater than 18");
1860
2268
  }
1861
2269
  var program = new Command();
1862
2270
  program.command("build").option("-c --config <config>", "The keq-cli config file").option("--module <modules...>", "Filter module(s) to generate").option("--debug", "Print debug information").option("--tolerant", "Tolerate wrong swagger structure").option("-i --interactive", "Interactive select the scope of generation").action(async (options) => {
1863
- await build({
2271
+ const compiler = new Compiler({
2272
+ build: {
2273
+ shaking: {
2274
+ skipIgnoredModules: true,
2275
+ skipEmptyDocuments: true
2276
+ }
2277
+ },
1864
2278
  config: options.config,
1865
2279
  modules: options.module,
1866
- debug: options.debug,
1867
- tolerant: options.tolerant,
1868
- interactive: options.interactive
2280
+ debug: !!options.debug,
2281
+ tolerant: !!options.tolerant,
2282
+ interactive: !!options.interactive
1869
2283
  });
2284
+ await compiler.run();
1870
2285
  });
1871
2286
  program.command("ignore").addArgument(
1872
- new Argument("<mode>", "The ignore mode").choices(["add", "except"]).argRequired()
2287
+ new Argument("<mode>", "The ignore mode").choices(["all", "add", "except"]).argRequired()
1873
2288
  ).option("-c --config <config>", "The keq-cli config file").option("--debug", "Print debug information").option("--module <modules...>").option("--build", "Build after updating .keqignore file").addOption(
1874
2289
  new Option("--method <method>", "Only generate files of the specified operation method").choices([
1875
2290
  ...SupportedMethods,
1876
2291
  ...SupportedMethods.map((method) => method.toUpperCase())
1877
2292
  ])
1878
2293
  ).option("--pathname <pathnames>", "Only generate files of the specified operation pathname").option("-i --interactive", "Interactive select the scope of generation").action(async (mode, options) => {
1879
- if (options.interactive) {
2294
+ let compiler;
2295
+ if (mode === "all") {
2296
+ if (options.build) throw new Error("'--build' cannot be used with 'all' mode");
2297
+ compiler = new Compiler({
2298
+ build: false,
2299
+ config: options.config,
2300
+ modules: options.module,
2301
+ debug: !!options.debug,
2302
+ interactive: false,
2303
+ ignore: {
2304
+ rules: [{
2305
+ persist: true,
2306
+ ignore: true,
2307
+ moduleName: "*",
2308
+ operationMethod: "*",
2309
+ operationPathname: "*"
2310
+ }]
2311
+ }
2312
+ });
2313
+ } else if (options.interactive) {
1880
2314
  if (options.interactive) {
1881
2315
  if (options.method) throw new Error("'--method' cannot be used with '--interactive'");
1882
2316
  if (options.pathname) throw new Error("'--pathname' cannot be used with '--interactive'");
1883
2317
  }
1884
- await ignore({
1885
- mode,
1886
- interactive: options.interactive,
2318
+ compiler = new Compiler({
2319
+ build: !!options.build && {
2320
+ shaking: {
2321
+ skipIgnoredModules: true,
2322
+ skipEmptyDocuments: true
2323
+ }
2324
+ },
1887
2325
  config: options.config,
1888
- debug: options.debug,
1889
2326
  modules: options.module,
1890
- rules: [],
1891
- build: options.build
2327
+ debug: !!options.debug,
2328
+ interactive: {
2329
+ mode,
2330
+ persist: true
2331
+ }
1892
2332
  });
1893
2333
  } else {
1894
- if (!options.module) throw new Error("required option '--module <module>' not specified");
1895
- if (!options.method) throw new Error("required option '--method <method>' not specified");
1896
- if (!options.pathname) throw new Error("required option '--pathname <pathnames>' not specified");
1897
- await ignore({
1898
- mode,
2334
+ if (!options.module && !options.method && !options.pathname) {
2335
+ throw new Error("at least one of '--module', '--method' or '--pathname' must be specified");
2336
+ }
2337
+ const moduleNames = options.module || ["*"];
2338
+ compiler = new Compiler({
2339
+ build: !!options.build && {
2340
+ shaking: {
2341
+ skipIgnoredModules: true,
2342
+ skipEmptyDocuments: true
2343
+ }
2344
+ },
1899
2345
  config: options.config,
1900
- debug: options.debug,
2346
+ debug: !!options.debug,
1901
2347
  modules: options.module,
1902
- rules: options.module.map((moduleName) => ({
1903
- moduleName,
1904
- operationMethod: options.method,
1905
- operationPathname: options.pathname
1906
- })),
1907
- build: options.build
2348
+ ignore: {
2349
+ rules: moduleNames.map((moduleNames2) => ({
2350
+ persist: true,
2351
+ ignore: mode === "add",
2352
+ moduleName: moduleNames2,
2353
+ operationMethod: options.method,
2354
+ operationPathname: options.pathname
2355
+ }))
2356
+ },
2357
+ interactive: false
1908
2358
  });
1909
2359
  }
2360
+ await compiler.run();
1910
2361
  });
1911
- async function main() {
2362
+ async function main7() {
1912
2363
  program.on("command:*", function(operands) {
1913
2364
  throw new Error(`Unknown command '${String(operands[0])}'`);
1914
2365
  });
@@ -1922,5 +2373,5 @@ async function main() {
1922
2373
  }
1923
2374
  }
1924
2375
  }
1925
- void main();
2376
+ void main7();
1926
2377
  //# sourceMappingURL=cli.js.map