@openapi-qraft/plugin 1.13.1 → 1.14.0-beta.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.
Files changed (41) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/lib/QraftCommand.d.ts.map +1 -1
  3. package/dist/lib/QraftCommand.js +27 -8
  4. package/dist/lib/QraftCommand.js.map +1 -1
  5. package/dist/lib/createServicePathMatch.d.ts +0 -9
  6. package/dist/lib/createServicePathMatch.d.ts.map +1 -1
  7. package/dist/lib/createServicePathMatch.js +0 -15
  8. package/dist/lib/createServicePathMatch.js.map +1 -1
  9. package/dist/lib/filterDocumentPaths.d.ts +1 -1
  10. package/dist/lib/filterDocumentPaths.d.ts.map +1 -1
  11. package/dist/lib/filterDocumentPaths.js +1 -1
  12. package/dist/lib/filterDocumentPaths.js.map +1 -1
  13. package/dist/lib/parseOperationGlobs.d.ts +17 -0
  14. package/dist/lib/parseOperationGlobs.d.ts.map +1 -0
  15. package/dist/lib/parseOperationGlobs.js +37 -0
  16. package/dist/lib/parseOperationGlobs.js.map +1 -0
  17. package/dist/lib/predefineSchemaParameters.d.ts +15 -11
  18. package/dist/lib/predefineSchemaParameters.d.ts.map +1 -1
  19. package/dist/lib/predefineSchemaParameters.js +50 -30
  20. package/dist/lib/predefineSchemaParameters.js.map +1 -1
  21. package/dist/lib/processOperationNameModifierOption.d.ts +57 -0
  22. package/dist/lib/processOperationNameModifierOption.d.ts.map +1 -0
  23. package/dist/lib/processOperationNameModifierOption.js +102 -0
  24. package/dist/lib/processOperationNameModifierOption.js.map +1 -0
  25. package/dist/lib/splitCommaSeparatedGlobs.d.ts +7 -0
  26. package/dist/lib/splitCommaSeparatedGlobs.d.ts.map +1 -0
  27. package/dist/lib/splitCommaSeparatedGlobs.js +16 -0
  28. package/dist/lib/splitCommaSeparatedGlobs.js.map +1 -0
  29. package/dist/packageVersion.d.ts +1 -1
  30. package/dist/packageVersion.d.ts.map +1 -1
  31. package/dist/packageVersion.js +1 -1
  32. package/dist/packageVersion.js.map +1 -1
  33. package/package.json +3 -3
  34. package/src/lib/QraftCommand.ts +59 -10
  35. package/src/lib/createServicePathMatch.ts +0 -18
  36. package/src/lib/filterDocumentPaths.ts +2 -2
  37. package/src/lib/parseOperationGlobs.ts +55 -0
  38. package/src/lib/predefineSchemaParameters.ts +108 -71
  39. package/src/lib/processOperationNameModifierOption.ts +205 -0
  40. package/src/lib/splitCommaSeparatedGlobs.ts +16 -0
  41. package/src/packageVersion.ts +1 -1
@@ -0,0 +1,102 @@
1
+ import { createServicePathMatch } from './createServicePathMatch.js';
2
+ import { parseOperationGlobs, } from './parseOperationGlobs.js';
3
+ import { splitCommaSeparatedGlobs } from './splitCommaSeparatedGlobs.js';
4
+ export const processOperationNameModifierOption = (modifiers, services) => {
5
+ if (!modifiers.length)
6
+ return {
7
+ errors: [],
8
+ services,
9
+ };
10
+ const operationNameModifiers = modifiers.map((modifier) => ({
11
+ ...modifier,
12
+ isPathMatch: createServicePathMatch(splitCommaSeparatedGlobs(modifier.pathGlobs)),
13
+ }));
14
+ const serviceOperationReplacements = new Map();
15
+ const replacedOperationNamesServices = services.map((service) => {
16
+ serviceOperationReplacements.set(service.name, new Map());
17
+ return {
18
+ ...service,
19
+ operations: service.operations.map((operation) => {
20
+ const operationReplacements = serviceOperationReplacements.get(service.name);
21
+ if (!operationReplacements)
22
+ throw new Error('operationReplacements not found');
23
+ const operationModifiers = operationNameModifiers.filter((modifier) => modifier.isPathMatch(operation.path) &&
24
+ (modifier.methods === undefined ||
25
+ modifier.methods.includes(operation.method)) &&
26
+ normalizeOperationNameModifierRegex(modifier.operationNameModifierRegex).test(operation.name));
27
+ const replacedOperationName = operationModifiers.reduce((operationName, modifier) => operationName.replace(normalizeOperationNameModifierRegex(modifier.operationNameModifierRegex), modifier.operationNameModifierReplace), operation.name);
28
+ if (replacedOperationName !== operation.name) {
29
+ if (!operationReplacements.has(replacedOperationName))
30
+ operationReplacements.set(replacedOperationName, new Map());
31
+ operationReplacements.get(replacedOperationName)?.set(operation.name, operationModifiers.map(({ isPathMatch: _, ...operationModifiersRest }) => operationModifiersRest));
32
+ }
33
+ return {
34
+ ...operation,
35
+ name: replacedOperationName,
36
+ };
37
+ }),
38
+ };
39
+ });
40
+ const errors = Array.from(serviceOperationReplacements).flatMap(([serviceName, modifiedOperations]) => Array.from(modifiedOperations).flatMap(([replacedOperationName, operationModifierMap]) => {
41
+ if (operationModifierMap.size > 1) {
42
+ return Array.from(operationModifierMap).map(([originalOperationName, modifiers]) => ({
43
+ serviceName,
44
+ replacedOperationName,
45
+ originalOperationName,
46
+ modifiers,
47
+ }));
48
+ }
49
+ const [originalOperationName, modifiers] = Array.from(operationModifierMap).at(0) ?? [];
50
+ if (modifiers && modifiers.length > 1) {
51
+ return [
52
+ {
53
+ serviceName,
54
+ replacedOperationName,
55
+ originalOperationName,
56
+ modifiers,
57
+ },
58
+ ];
59
+ }
60
+ return [];
61
+ }));
62
+ return {
63
+ errors,
64
+ services: replacedOperationNamesServices,
65
+ };
66
+ };
67
+ function normalizeOperationNameModifierRegex(regex) {
68
+ return new RegExp(regex, 'g');
69
+ }
70
+ /**
71
+ * Parses the given options string into a structured format.
72
+ *
73
+ * @param optionItems - The configuration string to parse. Eg. `/foo,/bar/**:post[A-Z][A-Za-z]+sId[A-Z][A-Za-z]+ ==> createOne` or `post /** ==> createOne`
74
+ * @returns The parsed configuration.
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * const parsedConfig = parseOperationNameModifier("/foo,/bar/**:/**:post[A-Z][A-Za-z]+sId[A-Z][A-Za-z]+ ==> createOne");
79
+ * ```
80
+ */
81
+ export function parseOperationNameModifier(...optionItems) {
82
+ const globOperationNameModifierMap = [];
83
+ for (const optionItem of optionItems) {
84
+ const operationGlobsRaw = optionItem.slice(0, Math.max(0, optionItem.indexOf(':')));
85
+ if (!operationGlobsRaw.length)
86
+ throw new Error(`Invalid operation name modifier: ${optionItem}. Must be in the format of 'pathGlobs:operationNameModifierRegex ==> operationNameModifierReplace'`);
87
+ const modifierPattern = optionItem.slice(operationGlobsRaw.length + 1);
88
+ const patternRegex = modifierPattern.slice(0, modifierPattern.indexOf('==>'));
89
+ const patternReplace = modifierPattern.slice(modifierPattern.indexOf('==>') + '==>'.length + 1);
90
+ const { methods, pathGlobs } = parseOperationGlobs(operationGlobsRaw);
91
+ if (!splitCommaSeparatedGlobs(pathGlobs).length)
92
+ throw new Error(`Invalid path glob: ${pathGlobs}. Must be a comma-separated list of globs.`);
93
+ globOperationNameModifierMap.push({
94
+ methods,
95
+ pathGlobs,
96
+ operationNameModifierRegex: patternRegex.trim(),
97
+ operationNameModifierReplace: patternReplace.trim(),
98
+ });
99
+ }
100
+ return globOperationNameModifierMap;
101
+ }
102
+ //# sourceMappingURL=processOperationNameModifierOption.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"processOperationNameModifierOption.js","sourceRoot":"","sources":["../../src/lib/processOperationNameModifierOption.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Normalize a comma-separated list of globs
3
+ * @param commaSeparatedGlobs - Example: `/foo , /bar/**, ,`
4
+ * @returns Example: `/foo,/bar/**`
5
+ */
6
+ export declare function splitCommaSeparatedGlobs(commaSeparatedGlobs: string | undefined): string[];
7
+ //# sourceMappingURL=splitCommaSeparatedGlobs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"splitCommaSeparatedGlobs.d.ts","sourceRoot":"","sources":["../../src/lib/splitCommaSeparatedGlobs.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,mBAAmB,EAAE,MAAM,GAAG,SAAS,GACtC,MAAM,EAAE,CAQV"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Normalize a comma-separated list of globs
3
+ * @param commaSeparatedGlobs - Example: `/foo , /bar/**, ,`
4
+ * @returns Example: `/foo,/bar/**`
5
+ */
6
+ export function splitCommaSeparatedGlobs(commaSeparatedGlobs) {
7
+ if (commaSeparatedGlobs === undefined)
8
+ return [];
9
+ if (typeof commaSeparatedGlobs !== 'string')
10
+ throw new Error('Invalid input');
11
+ return commaSeparatedGlobs
12
+ .split(',')
13
+ .map((path) => path.trim())
14
+ .filter(Boolean);
15
+ }
16
+ //# sourceMappingURL=splitCommaSeparatedGlobs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"splitCommaSeparatedGlobs.js","sourceRoot":"","sources":["../../src/lib/splitCommaSeparatedGlobs.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CACtC,mBAAuC;IAEvC,IAAI,mBAAmB,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IACjD,IAAI,OAAO,mBAAmB,KAAK,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;IAE9E,OAAO,mBAAmB;SACvB,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,OAAO,CAAC,CAAC;AACrB,CAAC"}
@@ -1,2 +1,2 @@
1
- export declare const packageVersion = "1.13.1";
1
+ export declare const packageVersion = "1.14.0-beta.2";
2
2
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,cAAc,WAAW,CAAC"}
1
+ {"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,cAAc,kBAAkB,CAAC"}
@@ -1,3 +1,3 @@
1
1
  // This file was generated automatically
2
- export const packageVersion = '1.13.1';
2
+ export const packageVersion = '1.14.0-beta.2';
3
3
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,MAAM,CAAC,MAAM,cAAc,GAAG,QAAQ,CAAC"}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,MAAM,CAAC,MAAM,cAAc,GAAG,eAAe,CAAC"}
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@openapi-qraft/plugin",
3
- "version": "1.13.1",
3
+ "version": "1.14.0-beta.2",
4
4
  "packageManager": "yarn@4.0.2",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "build": "tsc --project tsconfig.build.json",
8
8
  "dev": "yarn build --watch --noEmitOnError false",
9
- "test": "vitest run",
9
+ "test": "vitest run --coverage",
10
10
  "typecheck": "tsc --noEmit",
11
11
  "lint": "eslint",
12
12
  "clean": "rimraf dist/",
@@ -29,7 +29,7 @@
29
29
  "camelcase": "^8.0.0",
30
30
  "commander": "^11.1.0",
31
31
  "micromatch": "^4.0.5",
32
- "openapi-typescript": "7.0.0-next.11",
32
+ "openapi-typescript": "^7.3.0",
33
33
  "ora": "^8.0.1",
34
34
  "yaml": "^2.3.4"
35
35
  },
@@ -7,7 +7,6 @@ import c from 'ansi-colors';
7
7
  import { Command } from 'commander';
8
8
  import ora, { Ora } from 'ora';
9
9
  import { packageVersion } from '../packageVersion.js';
10
- import { parsePathGlobs } from './createServicePathMatch.js';
11
10
  import { filterDocumentPaths } from './filterDocumentPaths.js';
12
11
  import { GeneratorFile } from './GeneratorFile.js';
13
12
  import { handleSchemaInput } from './handleSchemaInput.js';
@@ -16,10 +15,15 @@ import { OpenAPISchemaType } from './open-api/OpenAPISchemaType.js';
16
15
  import { readSchema } from './open-api/readSchema.js';
17
16
  import { OutputOptions } from './OutputOptions.js';
18
17
  import {
19
- createPredefinedParametersGlobMap,
18
+ createPredefinedParametersGlobs,
20
19
  parseOperationPredefinedParametersOption,
21
20
  predefineSchemaParameters,
22
21
  } from './predefineSchemaParameters.js';
22
+ import {
23
+ parseOperationNameModifier,
24
+ processOperationNameModifierOption,
25
+ } from './processOperationNameModifierOption.js';
26
+ import { splitCommaSeparatedGlobs } from './splitCommaSeparatedGlobs.js';
23
27
  import { writeGeneratorFiles } from './writeGeneratorFiles.js';
24
28
 
25
29
  export class QraftCommand extends Command {
@@ -50,7 +54,11 @@ export class QraftCommand extends Command {
50
54
  )
51
55
  .option(
52
56
  '--operation-predefined-parameters <patterns...>',
53
- 'Predefined parameters for services. The specified services parameters will be optional. Eg: "/**:header.x-monite-version,query.x-api-key;/user/**,/post/**:header.x-monite-entity-id"'
57
+ 'Predefined parameters for services. The specified services parameters will be optional. Eg: "/**:header.x-monite-version,query.x-api-key" or "get /**:header.x-monite-entity-id"'
58
+ )
59
+ .option(
60
+ '--operation-name-modifier <patterns...>',
61
+ 'Modifies operation names using a pattern. Use the `==>` operator to separate the regular expression (left) and the substitution string (right). For example: "post /**:[A-Za-z]+Id ==> createOne"'
54
62
  )
55
63
  .option(
56
64
  '--postfix-services <string>',
@@ -96,20 +104,20 @@ export class QraftCommand extends Command {
96
104
  spinner.text = 'Reading OpenAPI Schema';
97
105
  let schema = filterDocumentPaths(
98
106
  await readSchema(input),
99
- parsePathGlobs(args.filterServices)
107
+ splitCommaSeparatedGlobs(args.filterServices)
100
108
  );
101
109
 
102
110
  if (args.operationPredefinedParameters) {
103
- const predefinedParametersGlobMap = createPredefinedParametersGlobMap(
111
+ const predefinedParametersGlobs = createPredefinedParametersGlobs(
104
112
  schema,
105
113
  parseOperationPredefinedParametersOption(
106
114
  ...args.operationPredefinedParameters
107
115
  )
108
116
  );
109
117
 
110
- const predefinedParametersErrors = Object.values(
111
- predefinedParametersGlobMap
112
- ).flatMap(({ errors }) => errors);
118
+ const predefinedParametersErrors = predefinedParametersGlobs.flatMap(
119
+ ({ errors }) => errors
120
+ );
113
121
 
114
122
  if (predefinedParametersErrors.length) {
115
123
  predefinedParametersErrors.forEach((error) => spinner.warn(error));
@@ -119,15 +127,56 @@ export class QraftCommand extends Command {
119
127
  process.exit(1);
120
128
  }
121
129
 
122
- schema = predefineSchemaParameters(schema, predefinedParametersGlobMap);
130
+ schema = predefineSchemaParameters(schema, predefinedParametersGlobs);
123
131
  }
124
132
 
125
133
  spinner.text = 'Getting OpenAPI Services';
126
- const services = getServices(schema as OpenAPISchemaType, {
134
+ let services = getServices(schema as OpenAPISchemaType, {
127
135
  postfixServices: args.postfixServices,
128
136
  serviceNameBase: args.serviceNameBase,
129
137
  });
130
138
 
139
+ if (args.operationNameModifier) {
140
+ const {
141
+ services: modifiedServicesOperationNames,
142
+ errors: operationNameModifierErrors,
143
+ } = processOperationNameModifierOption(
144
+ parseOperationNameModifier(
145
+ ...(Array.isArray(args.operationNameModifier)
146
+ ? args.operationNameModifier
147
+ : [args.operationNameModifier])
148
+ ),
149
+ services
150
+ );
151
+
152
+ if (operationNameModifierErrors.length) {
153
+ operationNameModifierErrors.forEach((error) => {
154
+ spinner.fail(
155
+ [
156
+ c.red.bold(
157
+ `Error occurred during operation name modifier setup: '${error.serviceName}.${error.originalOperationName}' to '${error.replacedOperationName}'`
158
+ ),
159
+ c.yellow(
160
+ error.modifiers
161
+ .map(
162
+ ({
163
+ pathGlobs,
164
+ operationNameModifierRegex,
165
+ operationNameModifierReplace,
166
+ }) =>
167
+ `Conflicting operation name modifier: '${pathGlobs}': '${operationNameModifierRegex}' => '${operationNameModifierReplace}'`
168
+ )
169
+ .join('\n')
170
+ ),
171
+ ].join('\n')
172
+ );
173
+ });
174
+ process.exit(1);
175
+ }
176
+
177
+ services = modifiedServicesOperationNames;
178
+ }
179
+
131
180
  spinner.text = 'Generating code';
132
181
 
133
182
  const outputDir = normalizeOutputDirPath(args.outputDir);
@@ -26,21 +26,3 @@ export const createServicePathMatch = (servicesGlob: string[]) => {
26
26
  });
27
27
  };
28
28
  };
29
-
30
- /**
31
- * Parse services filter option to array
32
- * @example
33
- * ```ts
34
- * parsePathGlobs('/user/**,/post/**')
35
- * ```
36
- * @param endpointGlobs
37
- */
38
- export function parsePathGlobs(endpointGlobs: string): string[] | undefined {
39
- return endpointGlobs
40
- ? endpointGlobs
41
- .split(',')
42
- .filter((item: unknown): item is string =>
43
- Boolean(typeof item === 'string' && item.trim())
44
- )
45
- : undefined;
46
- }
@@ -13,9 +13,9 @@ import { createServicePathMatch } from './createServicePathMatch.js';
13
13
  */
14
14
  export const filterDocumentPaths = (
15
15
  schema: OpenAPI3,
16
- servicesGlob: string[] | undefined
16
+ servicesGlob: string[]
17
17
  ): OpenAPI3 => {
18
- if (!servicesGlob) return schema;
18
+ if (!servicesGlob.length) return schema;
19
19
 
20
20
  const isPathMatch = createServicePathMatch(servicesGlob);
21
21
  const paths: typeof schema.paths = {};
@@ -0,0 +1,55 @@
1
+ import { ServiceOperation } from './open-api/getServices.js';
2
+ import { splitCommaSeparatedGlobs } from './splitCommaSeparatedGlobs.js';
3
+
4
+ /**
5
+ *
6
+ * @param operationFullGlobs - Example: `post /**`, `/**,/foo/bar`
7
+ * @returns `pathGlobs`, and `methods` as an array if methods are specified, or `undefined`
8
+ * @example
9
+ * ```ts
10
+ * parseOperationGlobs('post /**');
11
+ * parseOperationGlobs('patch,put /foo/bar');
12
+ * ```
13
+ */
14
+ export const parseOperationGlobs = (operationFullGlobs: string) => {
15
+ const methodsGlobsRaw = operationFullGlobs.slice(
16
+ 0,
17
+ Math.max(0, operationFullGlobs.indexOf('/'))
18
+ );
19
+
20
+ const methods = methodsGlobsRaw
21
+ .split(',')
22
+ .map((method) => method.trim().toLowerCase())
23
+ .filter(isSupportedOperationMethod);
24
+
25
+ methods.sort(sortSupportedMethods);
26
+
27
+ return {
28
+ methods: methods.length ? methods : undefined,
29
+ pathGlobs: splitCommaSeparatedGlobs(
30
+ operationFullGlobs.slice(methodsGlobsRaw.length)
31
+ ).join(','),
32
+ };
33
+ };
34
+
35
+ const supportedOperationMethods = Object.values({
36
+ get: 'get',
37
+ post: 'post',
38
+ put: 'put',
39
+ patch: 'patch',
40
+ delete: 'delete',
41
+ options: 'options',
42
+ head: 'head',
43
+ trace: 'trace',
44
+ } satisfies { [Method in OperationGlobMethods]: Method });
45
+
46
+ const isSupportedOperationMethod = (
47
+ operationRaw: string
48
+ ): operationRaw is OperationGlobMethods =>
49
+ supportedOperationMethods.includes(operationRaw as OperationGlobMethods);
50
+
51
+ const sortSupportedMethods = (a: string, b: string) =>
52
+ supportedOperationMethods.indexOf(a as OperationGlobMethods) -
53
+ supportedOperationMethods.indexOf(b as OperationGlobMethods);
54
+
55
+ export type OperationGlobMethods = ServiceOperation['method'];