wormajs 0.0.2-beta.3 → 0.2.0

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 (37) hide show
  1. package/dist/constant.js +7 -10
  2. package/dist/core/parser/openApiParser/helper.js +91 -69
  3. package/dist/helper/config/GeneratorHelper.js +20 -18
  4. package/dist/helper/config/zType.js +2 -2
  5. package/dist/helper/progress.js +2 -2
  6. package/dist/plugins/index.js +6 -2
  7. package/dist/plugins/presets/payloadModifier/hepler.js +29 -33
  8. package/dist/plugins/presets/payloadModifier/index.js +8 -8
  9. package/dist/plugins/presets/platform/fastapi.js +22 -0
  10. package/dist/plugins/presets/platform/index.js +15 -0
  11. package/dist/plugins/presets/platform/knife4j.js +24 -0
  12. package/dist/plugins/presets/platform/shared.js +45 -0
  13. package/dist/plugins/presets/platform/swagger.js +32 -0
  14. package/dist/plugins/presets/platform/yapi.js +75 -0
  15. package/dist/plugins/presets/rename.js +154 -21
  16. package/dist/plugins/presets/tagModifier.js +6 -2
  17. package/dist/plugins/presets/utils.js +11 -10
  18. package/dist/template/index.js +0 -34
  19. package/dist/template/presets/alova/partials/dts-extra-config.handlebars +3 -3
  20. package/dist/template/presets/alova/partials/dts-fn-declare.handlebars +1 -1
  21. package/dist/template/presets/alova/typescript/services/{tag}.ts.handlebars +5 -5
  22. package/dist/template/presets/axios/partials/dts-types.handlebars +4 -4
  23. package/dist/template/presets/axios/typescript/services/{tag}.ts.handlebars +4 -4
  24. package/dist/template/presets/config/common/worma.config.js.handlebars +1 -1
  25. package/dist/template/presets/config/module/worma.config.js.handlebars +1 -1
  26. package/dist/template/presets/config/partials/generator-content.handlebars +45 -45
  27. package/dist/template/presets/config/typescript/worma.config.ts.handlebars +1 -1
  28. package/dist/template/presets/fetch/partials/dts-types.handlebars +4 -4
  29. package/dist/template/presets/fetch/typescript/services/{tag}.ts.handlebars +4 -4
  30. package/dist/template/presets/ky/partials/dts-types.handlebars +4 -4
  31. package/dist/template/presets/ky/typescript/services/{tag}.ts.handlebars +4 -4
  32. package/dist/tsconfig.build.tsbuildinfo +1 -1
  33. package/dist/utils/template.js +23 -0
  34. package/package.json +1 -1
  35. package/typings/index.d.ts +9 -5
  36. package/typings/plugins.d.ts +134 -48
  37. package/dist/plugins/presets/platform.js +0 -73
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeBase = normalizeBase;
4
+ exports.defineUrlPlatformPlugin = defineUrlPlatformPlugin;
5
+ exports.withCookie = withCookie;
6
+ /** Remove trailing slashes from a base URL */
7
+ function normalizeBase(baseUrl) {
8
+ while (baseUrl.endsWith('/')) {
9
+ baseUrl = baseUrl.slice(0, -1);
10
+ }
11
+ return baseUrl;
12
+ }
13
+ /**
14
+ * Factory for "URL-constructing" platform plugins.
15
+ *
16
+ * Unlike the old `platform()` helper, the platform base URL(s) are supplied as
17
+ * the plugin's own argument (e.g. `swagger('https://petstore.swagger.io')`)
18
+ * rather than being read from `config.input`. The plugin writes the resolved
19
+ * candidate URLs into `config.input` inside its `config` hook, so downstream
20
+ * fetching (which tries each URL in order and keeps the first success) works
21
+ * unchanged.
22
+ */
23
+ function defineUrlPlatformPlugin(name, buildUrls) {
24
+ return (input) => {
25
+ const inputs = Array.isArray(input) ? [...new Set(input)] : [input];
26
+ return {
27
+ name,
28
+ config({ config }) {
29
+ config.input = inputs.flatMap(url => buildUrls(normalizeBase(String(url))));
30
+ return config;
31
+ },
32
+ };
33
+ };
34
+ }
35
+ /** Merge a cookie into config.fetchOptions.headers */
36
+ function withCookie(config, cookie) {
37
+ config.fetchOptions = {
38
+ ...config.fetchOptions,
39
+ headers: {
40
+ ...config.fetchOptions?.headers,
41
+ cookie,
42
+ },
43
+ };
44
+ return config;
45
+ }
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.swagger = void 0;
4
+ const constant_1 = require("../../../constant");
5
+ const shared_1 = require("./shared");
6
+ /**
7
+ * Swagger platform plugin.
8
+ *
9
+ * Pass the base URL of your Swagger UI / server; the plugin will try several
10
+ * common OpenAPI document endpoints (OAS3 first, then Swagger2, then the bare
11
+ * base URL) and let the framework pick the first one that responds.
12
+ *
13
+ * @param input - base URL string, or an array of base URLs
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { swagger, alovaGlobals } from 'wormajs/plugin';
18
+ *
19
+ * defineConfig({
20
+ * generator: [{
21
+ * plugins: [swagger('https://petstore3.swagger.io'), alovaGlobals()],
22
+ * output: './src/api',
23
+ * }]
24
+ * });
25
+ * ```
26
+ */
27
+ exports.swagger = (0, shared_1.defineUrlPlatformPlugin)(constant_1.PluginName.SWAGGER, base => [
28
+ `${base}/openapi.json`,
29
+ `${base}/v2/swagger.json`,
30
+ `${base}/api/v3/openapi.json`,
31
+ base,
32
+ ]);
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.yapi = yapi;
4
+ const constant_1 = require("../../../constant");
5
+ const shared_1 = require("./shared");
6
+ /**
7
+ * YApi platform plugin.
8
+ *
9
+ * YApi projects are private, so the OpenAPI document must be exported through
10
+ * YApi's own export endpoint, authenticated with your login cookie. The plugin
11
+ * builds the export URL from the server base URL (`url`) plus the required
12
+ * `pid` and the optional `type` / `status` / `isWiki` query params (which
13
+ * default to `OpenAPIV2`, `all`, and `true` respectively).
14
+ *
15
+ * `url`, `pid` and `cookie` are required — the plugin throws a clear error when
16
+ * any is missing.
17
+ *
18
+ * @param options - `{ url, pid, cookie?, type?, status?, isWiki?, timeout? }`
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * import { yapi, alovaGlobals } from 'wormajs/plugin';
23
+ *
24
+ * defineConfig({
25
+ * generator: [{
26
+ * plugins: [
27
+ * yapi({
28
+ * url: 'https://yapi.xxx.com',
29
+ * pid: 123,
30
+ * cookie: '_yapi_token=xxx; _yapi_uid=yyy',
31
+ * }),
32
+ * alovaGlobals(),
33
+ * ],
34
+ * output: './src/api',
35
+ * }]
36
+ * });
37
+ * ```
38
+ */
39
+ function yapi(options) {
40
+ return {
41
+ name: constant_1.PluginName.YAPI,
42
+ async config({ config }) {
43
+ const baseUrl = options.url;
44
+ if (!baseUrl) {
45
+ throw new Error('[yapi] `url` is required — the YApi server base URL '
46
+ + '(e.g. yapi({ url: "https://yapi.xxx.com", pid: 123, cookie: "..." })).');
47
+ }
48
+ const pid = options.pid;
49
+ if (pid == null) {
50
+ throw new Error('[yapi] `pid` is required — the YApi project id used to build the export URL '
51
+ + '(e.g. yapi({ url: "https://yapi.xxx.com", pid: 123, cookie: "..." })).');
52
+ }
53
+ const cookie = options.cookie ?? config.fetchOptions?.headers?.cookie;
54
+ if (!cookie) {
55
+ throw new Error('[yapi] `cookie` is required. YApi projects are private, so the export '
56
+ + 'endpoint needs your login cookie to fetch the OpenAPI document.\n'
57
+ + ' e.g. yapi({ url: "https://yapi.xxx.com", pid: 123, cookie: "_yapi_token=xxx; ..." })');
58
+ }
59
+ const type = options.type ?? 'OpenAPIV2';
60
+ const status = options.status ?? 'all';
61
+ const isWiki = options.isWiki ?? true;
62
+ const base = (0, shared_1.normalizeBase)(baseUrl);
63
+ config.input = `${base}/api/plugin/exportSwagger`
64
+ + `?type=${encodeURIComponent(type)}`
65
+ + `&pid=${encodeURIComponent(String(pid))}`
66
+ + `&status=${encodeURIComponent(status)}`
67
+ + `&isWiki=${isWiki}`;
68
+ (0, shared_1.withCookie)(config, cookie);
69
+ if (options.timeout != null) {
70
+ config.fetchOptions = { ...config.fetchOptions, timeout: options.timeout };
71
+ }
72
+ return config;
73
+ },
74
+ };
75
+ }
@@ -27,8 +27,12 @@ function toPascalCase(str) {
27
27
  * Applies renaming rules to the specified value
28
28
  * @returns The renamed value, or original value if not matched
29
29
  */
30
- function applyRenameRule(value, config, apiDescriptor) {
31
- if (!(0, utils_1.isMatch)(value, config.match)) {
30
+ function applyRenameRule(value, config, apiDescriptor, level = 0) {
31
+ // Skip non-string values (e.g. a missing or empty operationId) to avoid runtime errors
32
+ if (typeof value !== 'string') {
33
+ return value;
34
+ }
35
+ if (!(0, utils_1.isMatch)(value, config.match, level)) {
32
36
  return value;
33
37
  }
34
38
  if (config.transform) {
@@ -38,7 +42,7 @@ function applyRenameRule(value, config, apiDescriptor) {
38
42
  return value;
39
43
  }
40
44
  if (config.style === 'kebabCase' && config.scope === 'refName') {
41
- throw new Error(`Invalid rename style: ${config.style}、${config.scope}`);
45
+ throw new Error(`Invalid rename style: ${config.style}, ${config.scope}`);
42
46
  }
43
47
  switch (config.style) {
44
48
  case 'camelCase':
@@ -53,6 +57,59 @@ function applyRenameRule(value, config, apiDescriptor) {
53
57
  throw new Error(`Invalid rename style: ${config.style}`);
54
58
  }
55
59
  }
60
+ /**
61
+ * Validates that no duplicate names exist after renaming.
62
+ * Throws an error with details if duplicates are found within the same scope.
63
+ *
64
+ * @param names the renamed names to check for duplicates
65
+ * @param scopeLabel used to identify the scope in the error message
66
+ * @param apiDescriptor the API descriptor the names belong to
67
+ * @param originalNames optional, the original keys before renaming (same order
68
+ * as `names`). When provided, the error message also lists which original keys
69
+ * were mapped to each duplicated name, making the conflict easier to locate.
70
+ */
71
+ function assertNoDuplicates(names, scopeLabel, apiDescriptor, originalNames) {
72
+ if (!names || names.length === 0)
73
+ return;
74
+ const counts = new Map();
75
+ for (const name of names) {
76
+ counts.set(name, (counts.get(name) ?? 0) + 1);
77
+ }
78
+ const duplicates = [...counts.entries()]
79
+ .filter(([, count]) => count > 1)
80
+ .map(([name]) => name);
81
+ if (duplicates.length === 0)
82
+ return;
83
+ // When original keys are available, group them by the duplicated (renamed) name
84
+ // so users can see exactly which keys collided.
85
+ let detail = '';
86
+ if (originalNames && originalNames.length === names.length) {
87
+ const grouped = new Map();
88
+ for (let i = 0; i < names.length; i++) {
89
+ if (duplicates.includes(names[i])) {
90
+ const list = grouped.get(names[i]) ?? [];
91
+ list.push(originalNames[i]);
92
+ grouped.set(names[i], list);
93
+ }
94
+ }
95
+ detail = [...grouped.entries()]
96
+ .map(([renamed, originals]) => ` ${renamed} <- [${originals.join(', ')}]`)
97
+ .join('\n');
98
+ }
99
+ else {
100
+ detail = ` ${duplicates.join(', ')}`;
101
+ }
102
+ const method = apiDescriptor.method ? String(apiDescriptor.method).toUpperCase() : '';
103
+ const url = apiDescriptor.url ?? '';
104
+ throw new Error(`[rename] Duplicate names found after renaming (scope=${scopeLabel}):\n`
105
+ + ` Conflicting (renamed) keys and their original keys:\n`
106
+ + `${detail}\n`
107
+ + ` Reason: different original names were mapped to the same name after `
108
+ + `match/transform/style processing, which would cause naming conflicts or `
109
+ + `missing references in the generated code.\n`
110
+ + ` Please adjust the rename config to avoid mapping multiple names to the same result.\n`
111
+ + ` API: ${method} ${url}`);
112
+ }
56
113
  /**
57
114
  * renames URL path by processing each segment individually
58
115
  * while keeping path parameter placeholders
@@ -65,27 +122,77 @@ function renameUrl(url, config, apiDescriptor) {
65
122
  if ((segment.startsWith('{') && segment.endsWith('}')) || !segment) {
66
123
  return segment;
67
124
  }
68
- return applyRenameRule(segment, config, apiDescriptor);
125
+ return applyRenameRule(segment, config, apiDescriptor, 0);
69
126
  })
70
127
  .join('/')
71
128
  .replace(/^\/{2,}/g, '/');
72
129
  }
73
130
  /**
74
- * Transforms object properties using the renaming rules
131
+ * Recursively processes a schema (supports nested objects and arrays),
132
+ * applying property renaming to nested objects.
133
+ * @param schema current schema
134
+ * @param config rename configuration
135
+ * @param apiDescriptor API descriptor
136
+ * @param level current nesting level (starts from 0)
137
+ * @param scopeLabel used to identify the scope in duplicate-name errors
138
+ */
139
+ function transformSchema(schema, config, apiDescriptor, level, scopeLabel) {
140
+ if (!schema || typeof schema !== 'object')
141
+ return schema;
142
+ // Nested object: recursively process its properties
143
+ if ('properties' in schema && schema.properties) {
144
+ return transformProperties(schema, config, apiDescriptor, level, scopeLabel);
145
+ }
146
+ // Array: recursively process items (supports a single schema or an array of schemas)
147
+ if (schema.items && typeof schema.items === 'object') {
148
+ if (Array.isArray(schema.items)) {
149
+ return {
150
+ ...schema,
151
+ items: schema.items.map((item) => transformSchema(item, config, apiDescriptor, level, scopeLabel)),
152
+ };
153
+ }
154
+ return {
155
+ ...schema,
156
+ items: transformSchema(schema.items, config, apiDescriptor, level, scopeLabel),
157
+ };
158
+ }
159
+ return schema;
160
+ }
161
+ /**
162
+ * Transforms object properties using the renaming rules (supports deep recursive renaming)
163
+ * @param obj object whose properties to transform
164
+ * @param config rename configuration
165
+ * @param apiDescriptor API descriptor
166
+ * @param level current nesting level (starts from 0), passed through to the match function
167
+ * @param scopeLabel used to identify the scope in duplicate-name errors
75
168
  */
76
- function transformProperties(obj, config, apiDescriptor) {
77
- if (!obj || typeof obj !== 'object' || !('properties' in obj)) {
169
+ function transformProperties(obj, config, apiDescriptor, level = 0, scopeLabel = config.scope ?? 'data') {
170
+ if (!obj || typeof obj !== 'object' || !('properties' in obj) || !obj.properties) {
78
171
  return obj;
79
172
  }
80
- const properties = { ...obj.properties };
173
+ const properties = obj.properties;
81
174
  const newProperties = {};
175
+ const newKeys = [];
176
+ // Record the oldKey -> newKey mapping, used to keep the same-level required array in sync
177
+ const keyMap = new Map();
82
178
  for (const key in properties) {
83
- const newKey = applyRenameRule(key, config, apiDescriptor);
84
- newProperties[newKey] = properties[key];
179
+ const newKey = applyRenameRule(key, config, apiDescriptor, level);
180
+ newKeys.push(newKey);
181
+ keyMap.set(key, newKey);
182
+ newProperties[newKey] = transformSchema(properties[key], config, apiDescriptor, level + 1, scopeLabel);
183
+ }
184
+ // Duplicate property names within the same object level would overwrite each other, so report an error
185
+ assertNoDuplicates(newKeys, scopeLabel, apiDescriptor, Object.keys(properties));
186
+ // Keep the required array of the current level in sync with the renamed property names;
187
+ // otherwise the generator would crash during normalization because required references a non-existent property
188
+ let newRequired = obj.required;
189
+ if (Array.isArray(newRequired)) {
190
+ newRequired = newRequired.map((r) => keyMap.get(r) ?? r);
85
191
  }
86
192
  return {
87
193
  ...obj,
88
194
  properties: newProperties,
195
+ ...(newRequired !== obj.required ? { required: newRequired } : {}),
89
196
  };
90
197
  }
91
198
  /**
@@ -99,7 +206,7 @@ function transformParameters(parameters, type, config, apiDescriptor) {
99
206
  if (param.in === type) {
100
207
  return {
101
208
  ...param,
102
- name: applyRenameRule(param.name, config, apiDescriptor),
209
+ name: applyRenameRule(param.name, config, apiDescriptor, 0),
103
210
  };
104
211
  }
105
212
  return param;
@@ -110,10 +217,14 @@ function transformRefNameMap(refNameMap, config, apiDescriptor) {
110
217
  return refNameMap;
111
218
  }
112
219
  const newRefNameMap = {};
220
+ const newValues = [];
113
221
  for (const key in refNameMap) {
114
- const newValue = applyRenameRule(refNameMap[key], config, apiDescriptor);
222
+ const newValue = applyRenameRule(refNameMap[key], config, apiDescriptor, 0);
223
+ newValues.push(newValue);
115
224
  newRefNameMap[key] = newValue;
116
225
  }
226
+ // Different $refs mapping to the same type name would generate duplicate interfaces, so report an error
227
+ assertNoDuplicates(newValues, 'refName', apiDescriptor, Object.keys(refNameMap));
117
228
  return newRefNameMap;
118
229
  }
119
230
  /**
@@ -125,6 +236,7 @@ function transformRefNameMap(refNameMap, config, apiDescriptor) {
125
236
  * - pathParams: Renames path parameters and their placeholders in URL
126
237
  * - data: Renames request body properties
127
238
  * - response: Renames response body properties
239
+ * - name: Renames the generated API function name (operationId)
128
240
  */
129
241
  function renameApiDescriptor(apiDescriptor, config) {
130
242
  if (!apiDescriptor)
@@ -134,33 +246,49 @@ function renameApiDescriptor(apiDescriptor, config) {
134
246
  switch (scope) {
135
247
  case constant_1.RenameScope.PARAMS:
136
248
  if (newDescriptor.parameters) {
249
+ const originalParams = newDescriptor.parameters.filter(p => p.in === constant_1.ParameterIn.QUERY).map(p => p.name);
137
250
  newDescriptor.parameters = transformParameters(newDescriptor.parameters, constant_1.ParameterIn.QUERY, config, apiDescriptor);
251
+ // Duplicate query parameter names would be indistinguishable when calling the API, so report an error
252
+ assertNoDuplicates(newDescriptor.parameters.filter(p => p.in === constant_1.ParameterIn.QUERY).map(p => p.name), 'params', apiDescriptor, originalParams);
138
253
  }
139
254
  break;
140
255
  case constant_1.RenameScope.PATH_PARAMS:
141
256
  if (newDescriptor.parameters) {
257
+ const originalParams = newDescriptor.parameters.filter(p => p.in === constant_1.ParameterIn.PATH).map(p => p.name);
142
258
  newDescriptor.parameters = transformParameters(newDescriptor.parameters, constant_1.ParameterIn.PATH, config, apiDescriptor);
143
- }
144
- if (newDescriptor.url) {
145
- newDescriptor.url = newDescriptor.url.replace(/\{([^}]+)\}/g, (match, paramName) => {
146
- const newName = applyRenameRule(paramName, config, apiDescriptor);
147
- return `{${newName}}`;
148
- });
259
+ if (newDescriptor.url) {
260
+ newDescriptor.url = newDescriptor.url.replace(/\{([^}]+)\}/g, (match, paramName) => {
261
+ const newName = applyRenameRule(paramName, config, apiDescriptor, 0);
262
+ return `{${newName}}`;
263
+ });
264
+ }
265
+ // Duplicate path parameter names would make URL placeholders no longer match the parameters, so report an error
266
+ assertNoDuplicates((newDescriptor.parameters ?? []).filter(p => p.in === constant_1.ParameterIn.PATH).map(p => p.name), 'pathParams', apiDescriptor, originalParams);
149
267
  }
150
268
  break;
151
269
  case constant_1.RenameScope.DATA:
152
270
  if (newDescriptor.requestBody) {
153
- newDescriptor.requestBody = transformProperties(newDescriptor.requestBody, config, apiDescriptor);
271
+ newDescriptor.requestBody = transformProperties(newDescriptor.requestBody, config, apiDescriptor, 0, 'data');
154
272
  }
155
273
  break;
156
274
  case constant_1.RenameScope.RESPONSE:
157
275
  if (newDescriptor.responses) {
158
- newDescriptor.responses = transformProperties(newDescriptor.responses, config, apiDescriptor);
276
+ newDescriptor.responses = transformProperties(newDescriptor.responses, config, apiDescriptor, 0, 'response');
159
277
  }
160
278
  break;
161
279
  case constant_1.RenameScope.URL:
162
280
  if (newDescriptor.url) {
281
+ const originalUrlNames = newDescriptor.url
282
+ .split('/')
283
+ .filter(Boolean)
284
+ .map(segment => (segment.startsWith('{') && segment.endsWith('}') ? segment.slice(1, -1) : segment));
163
285
  newDescriptor.url = renameUrl(newDescriptor.url, config, apiDescriptor);
286
+ // Duplicate path segments would make the URL unable to distinguish different resources, so report an error
287
+ const urlNames = newDescriptor.url
288
+ .split('/')
289
+ .filter(Boolean)
290
+ .map(segment => (segment.startsWith('{') && segment.endsWith('}') ? segment.slice(1, -1) : segment));
291
+ assertNoDuplicates(urlNames, 'url', apiDescriptor, originalUrlNames);
164
292
  }
165
293
  break;
166
294
  case constant_1.RenameScope.REF_NAME:
@@ -168,6 +296,11 @@ function renameApiDescriptor(apiDescriptor, config) {
168
296
  newDescriptor.refNameMap = transformRefNameMap(newDescriptor.refNameMap, config, apiDescriptor);
169
297
  }
170
298
  break;
299
+ case constant_1.RenameScope.NAME:
300
+ if (newDescriptor.operationId != null) {
301
+ newDescriptor.operationId = applyRenameRule(newDescriptor.operationId, config, apiDescriptor, 0);
302
+ }
303
+ break;
171
304
  default:
172
305
  // No action needed, keep original descriptor
173
306
  break;
@@ -185,7 +318,7 @@ function rename(config) {
185
318
  throw new Error('at least one of `style` or `transform` is required');
186
319
  }
187
320
  if (conf.style === 'kebabCase' && conf.scope === 'refName') {
188
- throw new Error(`Invalid rename style: ${conf.style}、${conf.scope}`);
321
+ throw new Error(`Invalid rename style: ${conf.style}, ${conf.scope}`);
189
322
  }
190
323
  }
191
324
  return {
@@ -38,6 +38,10 @@ function processApiTags(apiDescriptor, handler) {
38
38
  // Process each tag and filter out null/undefined results
39
39
  newDescriptor.tags = newDescriptor.tags
40
40
  .map((tag) => {
41
+ // Resolve the tag to keep when the modification cannot be applied:
42
+ // keep the original tag only if it is itself valid, otherwise drop it.
43
+ // This guarantees that the final output never contains an invalid tag.
44
+ const keepOriginalOrDrop = () => isValidTagName(tag) ? tag : null;
41
45
  try {
42
46
  // Call user provided handler function
43
47
  const modifiedTag = handler(tag);
@@ -47,12 +51,12 @@ function processApiTags(apiDescriptor, handler) {
47
51
  }
48
52
  // Validate if modified tag follows naming conventions
49
53
  if (!isValidTagName(modifiedTag)) {
50
- return tag; // Keep original tag if invalid
54
+ return keepOriginalOrDrop(); // Keep original tag if valid, otherwise drop
51
55
  }
52
56
  return modifiedTag.trim(); // Return trimmed modified tag
53
57
  }
54
58
  catch {
55
- return tag; // Return original tag on error
59
+ return keepOriginalOrDrop(); // Keep original tag if valid, otherwise drop on error
56
60
  }
57
61
  })
58
62
  .filter((tag) => tag != null); // Filter out null/undefined values
@@ -4,23 +4,24 @@ exports.extend = extend;
4
4
  exports.isMatch = isMatch;
5
5
  const prepareConfig_1 = require("../../functions/prepareConfig");
6
6
  /**
7
- * 扩展生成器配置:
8
- * 根据传入的 newConfig(对象或函数)与基础 config 生成合并后的配置。
9
- * 当未提供 newConfig 时,直接回退到原始 config
10
- * @param config 基础配置
11
- * @param newConfig 需要扩展的配置或用于生成扩展配置的函数
12
- * @returns 合并且标准化后的配置
7
+ * Extends the generator configuration:
8
+ * merges the provided newConfig (object or function) with the base config to produce the merged config.
9
+ * When newConfig is not provided, falls back to the original config.
10
+ * @param config base configuration
11
+ * @param newConfig config to merge, or a function that produces the merged config
12
+ * @returns the merged and normalized configuration
13
13
  */
14
14
  function extend(config, newConfig) {
15
- // 根据 newConfig 类型计算扩展配置:函数则调用生成配置,否则直接使用对象;未提供则回退到原始 config
15
+ // Compute the extension config based on newConfig's type: call it if it's a function,
16
+ // otherwise use it directly; fall back to the original config if not provided
16
17
  const pluginExtendsConfig = typeof newConfig === 'function' ? newConfig(config) : (newConfig ?? config);
17
- // 使用 extendsConfig 进行配置合并与标准化,确保最终结构满足生成器需求
18
+ // Use extendsConfig to merge and normalize, ensuring the final structure meets the generator's requirements
18
19
  return (0, prepareConfig_1.extendsConfig)(config, pluginExtendsConfig);
19
20
  }
20
21
  /**
21
22
  * Tests if value matches the specified rule
22
23
  */
23
- function isMatch(value, match) {
24
+ function isMatch(value, match, level = 0) {
24
25
  if (!match)
25
26
  return true;
26
27
  if (typeof match === 'string') {
@@ -30,7 +31,7 @@ function isMatch(value, match) {
30
31
  return match.test(value);
31
32
  }
32
33
  if (typeof match === 'function') {
33
- return match(value);
34
+ return match(value, level);
34
35
  }
35
36
  return false;
36
37
  }
@@ -4,7 +4,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.getPresetTemplatePath = getPresetTemplatePath;
7
- exports.registerProcessTypeHelper = registerProcessTypeHelper;
8
7
  exports.config = config;
9
8
  exports.alovaGlobals = alovaGlobals;
10
9
  exports.alova = alova;
@@ -21,27 +20,6 @@ function getPresetTemplatePath(presetName) {
21
20
  // 编译后在 dist/template/presets 目录
22
21
  return node_path_1.default.join(__dirname, 'presets', presetName);
23
22
  }
24
- /**
25
- * Register processType helper on an hbs instance.
26
- *
27
- * Scans the type string for every PascalCase identifier that is in componentNames
28
- * (and not already prefixed with "ComponentTypes.") and prefixes it.
29
- * Works uniformly for top-level names, generics, object literals, and arrays.
30
- */
31
- function registerProcessTypeHelper(hbs) {
32
- hbs.registerHelper('processType', (_typeStr, _componentNames) => {
33
- const typeStr = _typeStr;
34
- const componentNames = _componentNames;
35
- if (!typeStr || !Array.isArray(componentNames) || componentNames.length === 0) {
36
- return new hbs.SafeString(typeStr || 'unknown');
37
- }
38
- const componentSet = new Set(componentNames);
39
- const result = typeStr.replace(/(?<!ComponentTypes\.)(\b[A-Z]\w*\b)/g, (match) => {
40
- return componentSet.has(match) ? `ComponentTypes.${match}` : match;
41
- });
42
- return new hbs.SafeString(result);
43
- });
44
- }
45
23
  // ========== Template Preset Plugins ==========
46
24
  /**
47
25
  * worma.config 模板预设 - plugin mode
@@ -100,9 +78,6 @@ function alova(opts) {
100
78
  getTemplate() {
101
79
  return { path: getPresetTemplatePath(constant_1.PresetTemplateName.ALOVA) };
102
80
  },
103
- onHandlebarsCreated({ hbs }) {
104
- registerProcessTypeHelper(hbs);
105
- },
106
81
  beforeCodeGenerate({ data }) {
107
82
  data.config = {
108
83
  ...data.config,
@@ -122,9 +97,6 @@ function axios(opts) {
122
97
  getTemplate() {
123
98
  return { path: getPresetTemplatePath(constant_1.PresetTemplateName.AXIOS) };
124
99
  },
125
- onHandlebarsCreated({ hbs }) {
126
- registerProcessTypeHelper(hbs);
127
- },
128
100
  beforeCodeGenerate({ data }) {
129
101
  data.config = {
130
102
  ...data.config,
@@ -144,9 +116,6 @@ function fetch(opts) {
144
116
  getTemplate() {
145
117
  return { path: getPresetTemplatePath(constant_1.PresetTemplateName.FETCH) };
146
118
  },
147
- onHandlebarsCreated({ hbs }) {
148
- registerProcessTypeHelper(hbs);
149
- },
150
119
  beforeCodeGenerate({ data }) {
151
120
  data.config = {
152
121
  ...data.config,
@@ -166,9 +135,6 @@ function ky(opts) {
166
135
  getTemplate() {
167
136
  return { path: getPresetTemplatePath(constant_1.PresetTemplateName.KY) };
168
137
  },
169
- onHandlebarsCreated({ hbs }) {
170
- registerProcessTypeHelper(hbs);
171
- },
172
138
  beforeCodeGenerate({ data }) {
173
139
  data.config = {
174
140
  ...data.config,
@@ -1,8 +1,8 @@
1
1
  {{#or pathParameters queryParameters requestBody}}
2
2
  type {{{name}}}ExtraConfig = {
3
- {{#if pathParameters}}pathParams: {{processType pathParameters @root.componentNames}};
4
- {{/if}}{{#if queryParameters}}params: {{processType queryParameters @root.componentNames}};
5
- {{/if}}{{#if requestBody}}data: {{processType requestBody @root.componentNames}};
3
+ {{#if pathParameters}}pathParams: {{addNamespace pathParameters @root.componentNames}};
4
+ {{/if}}{{#if queryParameters}}params: {{addNamespace queryParameters @root.componentNames}};
5
+ {{/if}}{{#if requestBody}}data: {{addNamespace requestBody @root.componentNames}};
6
6
  {{/if}}
7
7
  };
8
8
  {{/or}}
@@ -1 +1 @@
1
- export declare function {{{name}}}<Config extends Alova2MethodConfig<{{processType response @root.componentNames}}> & {{{name}}}ExtraConfig>(config: Config): Alova2Method<ExtractResponded<Config, '{{{name}}}', {{processType response @root.componentNames}}>>;
1
+ export declare function {{{name}}}<Config extends Alova2MethodConfig<{{addNamespace response @root.componentNames}}> & {{{name}}}ExtraConfig>(config: Config): Alova2Method<ExtractResponded<Config, '{{{name}}}', {{addNamespace response @root.componentNames}}>>;
@@ -12,15 +12,15 @@ import type * as ComponentTypes from '../components';
12
12
  {{#each apis}}
13
13
 
14
14
  interface {{{name}}}ExtraConfig {
15
- {{#if pathParameters}}pathParams: {{processType pathParameters @root.componentNames}};
16
- {{/if}}{{#if queryParameters}}params: {{processType queryParameters @root.componentNames}};
17
- {{/if}}{{#if requestBody}}data: {{processType requestBody @root.componentNames}};
15
+ {{#if pathParameters}}pathParams: {{addNamespace pathParameters @root.componentNames}};
16
+ {{/if}}{{#if queryParameters}}params: {{addNamespace queryParameters @root.componentNames}};
17
+ {{/if}}{{#if requestBody}}data: {{addNamespace requestBody @root.componentNames}};
18
18
  {{/if}}
19
19
  }
20
20
  {{> api-jsdoc}}
21
- export function {{{name}}}<Config extends Alova2MethodConfig<{{processType response @root.componentNames}}> & {{{name}}}ExtraConfig>(config: Config): Alova2Method<ExtractResponded<Config, '{{{name}}}', {{processType response @root.componentNames}}>> {
21
+ export function {{{name}}}<Config extends Alova2MethodConfig<{{addNamespace response @root.componentNames}}> & {{{name}}}ExtraConfig>(config: Config): Alova2Method<ExtractResponded<Config, '{{{name}}}', {{addNamespace response @root.componentNames}}>> {
22
22
  const { url, data, mergedConfig } = buildPayload('{{{path}}}', {{{tag}}}DefaultConfig, {{{name}}}.name, config);
23
- return alovaInstance.Request<ExtractResponded<Config, '{{{name}}}', {{processType response @root.componentNames}}>>({
23
+ return alovaInstance.Request<ExtractResponded<Config, '{{{name}}}', {{addNamespace response @root.componentNames}}>>({
24
24
  ...mergedConfig,
25
25
  url,
26
26
  data,
@@ -1,7 +1,7 @@
1
- type {{{name}}}Response = {{processType response @root.componentNames}};
1
+ type {{{name}}}Response = {{addNamespace response @root.componentNames}};
2
2
  type {{{name}}}ExtraConfig = Omit<AxiosRequestConfig, 'data' | 'params'> & {
3
- {{#if pathParameters}}pathParams: {{processType pathParameters @root.componentNames}};
4
- {{/if}}{{#if queryParameters}}params: {{processType queryParameters @root.componentNames}};
5
- {{/if}}{{#if requestBody}}data: {{processType requestBody @root.componentNames}};
3
+ {{#if pathParameters}}pathParams: {{addNamespace pathParameters @root.componentNames}};
4
+ {{/if}}{{#if queryParameters}}params: {{addNamespace queryParameters @root.componentNames}};
5
+ {{/if}}{{#if requestBody}}data: {{addNamespace requestBody @root.componentNames}};
6
6
  {{/if}}
7
7
  };
@@ -9,11 +9,11 @@ import { {{{tagName}}}DefaultConfig } from '.';
9
9
 
10
10
  {{#each tagedApis}}
11
11
  {{#each apis}}
12
- type {{{name}}}Response = {{processType response @root.componentNames}};
12
+ type {{{name}}}Response = {{addNamespace response @root.componentNames}};
13
13
  type {{{name}}}ExtraConfig = Omit<AxiosRequestConfig, 'data' | 'params'> & {
14
- {{#if pathParameters}}pathParams: {{processType pathParameters @root.componentNames}};
15
- {{/if}}{{#if queryParameters}}params: {{processType queryParameters @root.componentNames}};
16
- {{/if}}{{#if requestBody}}data: {{processType requestBody @root.componentNames}};
14
+ {{#if pathParameters}}pathParams: {{addNamespace pathParameters @root.componentNames}};
15
+ {{/if}}{{#if queryParameters}}params: {{addNamespace queryParameters @root.componentNames}};
16
+ {{/if}}{{#if requestBody}}data: {{addNamespace requestBody @root.componentNames}};
17
17
  {{/if}}
18
18
  };
19
19
  {{> api-jsdoc}}
@@ -1,5 +1,5 @@
1
1
  const { defineConfig } = require('wormajs');
2
- const { platform, aiDoc{{#if templateImport}}, {{{templateImport}}}{{/if}} } = require('wormajs/plugin');
2
+ const { swagger, aiDoc{{#if templateImport}}, {{{templateImport}}}{{/if}} } = require('wormajs/plugin');
3
3
 
4
4
  // For more config detailed visit:
5
5
  // https://github.com/alovajs/devtools