wormajs 0.3.1 → 1.0.0-beta.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 (52) hide show
  1. package/dist/bin/actions.js +162 -5
  2. package/dist/bin/cli.js +7 -1
  3. package/dist/bin/renderer.js +2 -8
  4. package/dist/checkUpdates.js +98 -0
  5. package/dist/config.js +7 -0
  6. package/dist/constant.js +1 -2
  7. package/dist/core/WorkerPool.js +14 -0
  8. package/dist/core/loader/callingCodeLoader/helper.js +2 -3
  9. package/dist/core/loader/callingCodeLoader/index.js +1 -1
  10. package/dist/core/parser/openApiParser/helper.js +32 -19
  11. package/dist/core/parser/templateParser/index.js +25 -12
  12. package/dist/core/workerPool/index.js +2 -1
  13. package/dist/functions/changeReport.js +230 -0
  14. package/dist/functions/diffApis.js +82 -0
  15. package/dist/functions/diffDocument.js +542 -0
  16. package/dist/functions/sourceSnapshot.js +107 -0
  17. package/dist/functions/wormaJson.js +306 -66
  18. package/dist/generate.js +24 -2
  19. package/dist/helper/config/ConfigHelper.js +1 -2
  20. package/dist/helper/config/ConfigManager.js +7 -0
  21. package/dist/helper/config/GeneratorHelper.js +74 -21
  22. package/dist/helper/config/zType.js +24 -1
  23. package/dist/helper/template/index.js +60 -4
  24. package/dist/index.js +17 -1
  25. package/dist/plugins/index.js +2 -2
  26. package/dist/plugins/presets/aiDoc.js +4 -0
  27. package/dist/plugins/presets/payloadModifier/dsl.js +147 -0
  28. package/dist/plugins/presets/payloadModifier/index.js +122 -135
  29. package/dist/plugins/presets/payloadModifier/patch.js +171 -0
  30. package/dist/plugins/presets/payloadModifier/scope.js +109 -0
  31. package/dist/plugins/presets/platform/index.js +1 -3
  32. package/dist/plugins/presets/postman.js +105 -0
  33. package/dist/template/presets/ai-doc/SKILL.md.handlebars +1 -1
  34. package/dist/template/presets/alova/common/services/{tag}.d.cts.handlebars +1 -1
  35. package/dist/template/presets/alova/module/services/{tag}.d.ts.handlebars +1 -1
  36. package/dist/template/presets/alova/partials/dts-fn-declare.handlebars +1 -1
  37. package/dist/template/presets/alova/partials/dts-types.handlebars +12 -0
  38. package/dist/template/presets/alova/typescript/services/{tag}.ts.handlebars +11 -6
  39. package/dist/template/presets/axios/partials/dts-types.handlebars +9 -5
  40. package/dist/template/presets/axios/typescript/services/{tag}.ts.handlebars +9 -5
  41. package/dist/template/presets/fetch/partials/dts-types.handlebars +8 -5
  42. package/dist/template/presets/fetch/typescript/services/{tag}.ts.handlebars +9 -5
  43. package/dist/template/presets/ky/partials/dts-types.handlebars +8 -5
  44. package/dist/template/presets/ky/typescript/services/{tag}.ts.handlebars +9 -5
  45. package/dist/utils/format.js +62 -15
  46. package/dist/utils/template.js +1 -1
  47. package/package.json +3 -2
  48. package/typings/index.d.ts +266 -13
  49. package/typings/plugins.d.ts +171 -80
  50. package/dist/plugins/presets/payloadModifier/hepler.js +0 -289
  51. package/dist/plugins/presets/platform/fastapi.js +0 -22
  52. package/dist/template/presets/alova/partials/dts-extra-config.handlebars +0 -8
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.unwrapTransformationOutput = unwrapTransformationOutput;
4
+ exports.postman = postman;
5
+ const constant_1 = require("../../constant");
6
+ /** Base address of the Postman API */
7
+ const POSTMAN_API_BASE = 'https://api.getpostman.com';
8
+ /**
9
+ * Unwraps the OpenAPI definition returned by the Postman collection
10
+ * transformation endpoint, which responds with `{ output: "<stringified spec>" }`
11
+ * instead of the specification itself.
12
+ *
13
+ * The response is parsed exactly once. Anything that is not a transformation
14
+ * envelope (an error payload, an HTML page, a malformed body, …) throws instead
15
+ * of being silently passed through, so the real problem surfaces immediately.
16
+ * The unwrapped spec is then validated by the generator's parser, like any other
17
+ * input — this function does not re-parse or validate it.
18
+ */
19
+ function unwrapTransformationOutput(spec) {
20
+ let parsed;
21
+ try {
22
+ parsed = JSON.parse(spec);
23
+ }
24
+ catch (error) {
25
+ throw new Error('[postman] The transformation response is not valid JSON: '
26
+ + `${error instanceof Error ? error.message : String(error)}. `
27
+ + `Received: ${spec.slice(0, 200)}`);
28
+ }
29
+ const output = parsed?.output;
30
+ if (typeof output !== 'string') {
31
+ throw new TypeError('[postman] The transformation response must be a JSON object with a string `output` field. '
32
+ + 'Check that the collection uid is correct and that you have access to it. '
33
+ + `Received: ${spec.slice(0, 200)}`);
34
+ }
35
+ return output;
36
+ }
37
+ /**
38
+ * Postman platform plugin.
39
+ *
40
+ * Postman collections are not OpenAPI documents, so the plugin points `input` to
41
+ * the collection transformation endpoint, which converts the collection into an
42
+ * OpenAPI definition:
43
+ *
44
+ * ```
45
+ * https://api.getpostman.com/collections/<collectionId>/transformations
46
+ * ```
47
+ *
48
+ * The `x-api-key` header is injected through `fetchOptions`. The endpoint responds
49
+ * with `{ output: "<spec>" }`, so the plugin unwraps that envelope in its
50
+ * `beforeSpecParse` hook.
51
+ *
52
+ * `apiKey` and `collectionId` are both required — the plugin throws a clear error
53
+ * when either is missing.
54
+ *
55
+ * @param options - `{ apiKey, collectionId }`
56
+ * @param options.apiKey - Postman API key used to read the collection
57
+ * @param options.collectionId - The uid of the Postman collection
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * import { postman, alovaGlobals } from 'wormajs/plugin';
62
+ *
63
+ * defineConfig({
64
+ * generator: [{
65
+ * plugins: [
66
+ * postman({
67
+ * apiKey: 'PMAK-xxx',
68
+ * collectionId: '12345678-a1b2-c3d4-e5f6-7890abcdef12',
69
+ * }),
70
+ * alovaGlobals(),
71
+ * ],
72
+ * output: './src/api',
73
+ * }]
74
+ * });
75
+ * ```
76
+ */
77
+ function postman({ apiKey, collectionId }) {
78
+ return {
79
+ name: constant_1.PluginName.POSTMAN,
80
+ async config({ config }) {
81
+ if (!apiKey) {
82
+ throw new Error('[postman] `apiKey` is required — the Postman API key used to read the collection '
83
+ + '(e.g. postman({ apiKey: "PMAK-xxx", collectionId: "12345678-..." })).');
84
+ }
85
+ if (!collectionId) {
86
+ throw new Error('[postman] `collectionId` is required — the uid of the Postman collection '
87
+ + '(e.g. postman({ apiKey: "PMAK-xxx", collectionId: "12345678-..." })).');
88
+ }
89
+ config.input = `${POSTMAN_API_BASE}/collections/${encodeURIComponent(collectionId.trim())}/transformations`;
90
+ config.fetchOptions = {
91
+ ...config.fetchOptions,
92
+ method: 'GET',
93
+ headers: {
94
+ ...config.fetchOptions?.headers,
95
+ 'x-api-key': apiKey,
96
+ },
97
+ };
98
+ return config;
99
+ },
100
+ beforeSpecParse({ spec }) {
101
+ return unwrapTransformationOutput(spec);
102
+ },
103
+ };
104
+ }
105
+ exports.default = postman;
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: apis-{{{title}}}
2
+ name: {{{skillName}}}
3
3
  description: >-
4
4
  API reference documentation for {{{serverName}}} ({{{title}}} v{{{version}}}).
5
5
  Contains specifications for all REST API endpoints, including HTTP request methods,
@@ -6,7 +6,7 @@ type {{{currentTag.tag}}}DefaultConfig = TagDefaultConfig<typeof defaultConfig,
6
6
 
7
7
  {{> extract-responded}}
8
8
  {{#each currentTag.apis}}
9
- {{> dts-extra-config}}
9
+ {{> dts-types}}
10
10
  {{> api-jsdoc}}
11
11
  {{> dts-fn-declare}}
12
12
 
@@ -6,7 +6,7 @@ type {{{currentTag.tag}}}DefaultConfig = TagDefaultConfig<typeof defaultConfig,
6
6
 
7
7
  {{> extract-responded}}
8
8
  {{#each currentTag.apis}}
9
- {{> dts-extra-config}}
9
+ {{> dts-types}}
10
10
  {{> api-jsdoc}}
11
11
  {{> dts-fn-declare}}
12
12
 
@@ -1 +1 @@
1
- export declare function {{{name}}}<Config extends Alova2MethodConfig<{{addNamespace response @root.componentNames}}> & {{{name}}}ExtraConfig>(config{{#or pathParameters queryParameters requestBody }}{{else}}?{{/or}}: Config): Alova2Method<ExtractResponded<Config, '{{{name}}}', {{addNamespace response @root.componentNames}}>>;
1
+ export declare function {{{name}}}<Config extends Alova2MethodConfig<{{{name}}}Response> & {{{name}}}ExtraConfig>(config{{#or pathParameters queryParameters requestBody }}{{else}}?{{/or}}: Config): Alova2Method<ExtractResponded<Config, '{{{name}}}', {{{name}}}Response>>;
@@ -0,0 +1,12 @@
1
+ {{#if pathParameters}}export type {{{name}}}PathParams = {{addNamespace pathParameters @root.componentNames}};
2
+ {{/if}}{{#if queryParameters}}export type {{{name}}}Params = {{addNamespace queryParameters @root.componentNames}};
3
+ {{/if}}{{#if requestBody}}export type {{{name}}}Data = {{addNamespace requestBody @root.componentNames}};
4
+ {{/if}}export type {{{name}}}Response = {{addNamespace response @root.componentNames}};
5
+ {{#or pathParameters queryParameters requestBody}}
6
+ export interface {{{name}}}ExtraConfig {
7
+ {{#if pathParameters}}pathParams: {{{name}}}PathParams;
8
+ {{/if}}{{#if queryParameters}}params: {{{name}}}Params;
9
+ {{/if}}{{#if requestBody}}data: {{{name}}}Data;
10
+ {{/if}}
11
+ }
12
+ {{/or}}
@@ -10,16 +10,21 @@ const {{{currentTag.tag}}}DefaultConfig = resolveTagDefaultConfig(defaultConfig,
10
10
  {{> extract-responded}}
11
11
  {{#each currentTag.apis}}
12
12
 
13
- interface {{{name}}}ExtraConfig {
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}};
13
+ export type {{{name}}}Response = {{addNamespace response @root.componentNames}};
14
+ {{#if pathParameters}}export type {{{name}}}PathParams = {{addNamespace pathParameters @root.componentNames}};
15
+ {{/if}}{{#if queryParameters}}export type {{{name}}}Params = {{addNamespace queryParameters @root.componentNames}};
16
+ {{/if}}{{#if requestBody}}export type {{{name}}}Data = {{addNamespace requestBody @root.componentNames}};
17
+ {{/if}}
18
+ export interface {{{name}}}ExtraConfig {
19
+ {{#if pathParameters}}pathParams: {{{name}}}PathParams;
20
+ {{/if}}{{#if queryParameters}}params: {{{name}}}Params;
21
+ {{/if}}{{#if requestBody}}data: {{{name}}}Data;
17
22
  {{/if}}
18
23
  }
19
24
  {{> api-jsdoc}}
20
- export function {{{name}}}<Config extends Alova2MethodConfig<{{addNamespace response @root.componentNames}}> & {{{name}}}ExtraConfig>(config{{#or pathParameters queryParameters requestBody }}{{else}}?{{/or}}: Config): Alova2Method<ExtractResponded<Config, '{{{name}}}', {{addNamespace response @root.componentNames}}>> {
25
+ export function {{{name}}}<Config extends Alova2MethodConfig<{{{name}}}Response> & {{{name}}}ExtraConfig>(config{{#or pathParameters queryParameters requestBody }}{{else}}?{{/or}}: Config): Alova2Method<ExtractResponded<Config, '{{{name}}}', {{{name}}}Response>> {
21
26
  const { url, data, mergedConfig } = buildPayload('{{{path}}}', {{../currentTag.tag}}DefaultConfig, {{{name}}}.name, config);
22
- return alovaInstance.Request<ExtractResponded<Config, '{{{name}}}', {{addNamespace response @root.componentNames}}>>({
27
+ return alovaInstance.Request<ExtractResponded<Config, '{{{name}}}', {{{name}}}Response>>({
23
28
  ...mergedConfig,
24
29
  url,
25
30
  data,
@@ -1,7 +1,11 @@
1
- type {{{name}}}Response = {{addNamespace response @root.componentNames}};
2
- type {{{name}}}ExtraConfig = Omit<AxiosRequestConfig, 'data' | 'params'> & {
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}};
1
+ export type {{{name}}}Response = {{addNamespace response @root.componentNames}};
2
+ {{#if pathParameters}}export type {{{name}}}PathParams = {{addNamespace pathParameters @root.componentNames}};
3
+ {{/if}}{{#if queryParameters}}export type {{{name}}}Params = {{addNamespace queryParameters @root.componentNames}};
4
+ {{/if}}{{#if requestBody}}export type {{{name}}}Data = {{addNamespace requestBody @root.componentNames}};
5
+ {{/if}}
6
+ export type {{{name}}}ExtraConfig = Omit<AxiosRequestConfig, 'data' | 'params'> & {
7
+ {{#if pathParameters}}pathParams: {{{name}}}PathParams;
8
+ {{/if}}{{#if queryParameters}}params: {{{name}}}Params;
9
+ {{/if}}{{#if requestBody}}data: {{{name}}}Data;
6
10
  {{/if}}
7
11
  };
@@ -8,11 +8,15 @@ import type * as ComponentTypes from '../components';
8
8
  const {{{currentTag.tag}}}DefaultConfig = resolveTagDefaultConfig(defaultConfig, '{{{currentTag.tag}}}DefaultConfig');
9
9
 
10
10
  {{#each currentTag.apis}}
11
- type {{{name}}}Response = {{addNamespace response @root.componentNames}};
12
- type {{{name}}}ExtraConfig = Omit<AxiosRequestConfig, 'data' | 'params'> & {
13
- {{#if pathParameters}}pathParams: {{addNamespace pathParameters @root.componentNames}};
14
- {{/if}}{{#if queryParameters}}params: {{addNamespace queryParameters @root.componentNames}};
15
- {{/if}}{{#if requestBody}}data: {{addNamespace requestBody @root.componentNames}};
11
+ export type {{{name}}}Response = {{addNamespace response @root.componentNames}};
12
+ {{#if pathParameters}}export type {{{name}}}PathParams = {{addNamespace pathParameters @root.componentNames}};
13
+ {{/if}}{{#if queryParameters}}export type {{{name}}}Params = {{addNamespace queryParameters @root.componentNames}};
14
+ {{/if}}{{#if requestBody}}export type {{{name}}}Data = {{addNamespace requestBody @root.componentNames}};
15
+ {{/if}}
16
+ export type {{{name}}}ExtraConfig = Omit<AxiosRequestConfig, 'data' | 'params'> & {
17
+ {{#if pathParameters}}pathParams: {{{name}}}PathParams;
18
+ {{/if}}{{#if queryParameters}}params: {{{name}}}Params;
19
+ {{/if}}{{#if requestBody}}data: {{{name}}}Data;
16
20
  {{/if}}
17
21
  };
18
22
  {{> api-jsdoc}}
@@ -1,7 +1,10 @@
1
- type {{{name}}}Response = {{addNamespace response @root.componentNames}};
2
- type {{{name}}}ExtraConfig = Omit<RequestInit, 'body'> & {
3
- {{#if pathParameters}}pathParams: {{addNamespace pathParameters @root.componentNames}};
4
- {{/if}}{{#if queryParameters}}params?: {{addNamespace queryParameters @root.componentNames}};
5
- {{/if}}{{#if requestBody}}body?: {{addNamespace requestBody @root.componentNames}} | BodyInit;
1
+ {{#if pathParameters}}export type {{{name}}}PathParams = {{addNamespace pathParameters @root.componentNames}};
2
+ {{/if}}{{#if queryParameters}}export type {{{name}}}Params = {{addNamespace queryParameters @root.componentNames}};
3
+ {{/if}}{{#if requestBody}}export type {{{name}}}Data = {{addNamespace requestBody @root.componentNames}};
4
+ {{/if}}export type {{{name}}}Response = {{addNamespace response @root.componentNames}};
5
+ export type {{{name}}}ExtraConfig = Omit<RequestInit, 'body'> & {
6
+ {{#if pathParameters}}pathParams: {{{name}}}PathParams;
7
+ {{/if}}{{#if queryParameters}}params?: {{{name}}}Params;
8
+ {{/if}}{{#if requestBody}}body?: {{{name}}}Data | BodyInit;
6
9
  {{/if}}
7
10
  };
@@ -7,11 +7,15 @@ import type * as ComponentTypes from '../components';
7
7
  const {{{currentTag.tag}}}DefaultConfig = resolveTagDefaultConfig(defaultConfig, '{{{currentTag.tag}}}DefaultConfig');
8
8
 
9
9
  {{#each currentTag.apis}}
10
- type {{{name}}}Response = {{addNamespace response @root.componentNames}};
11
- type {{{name}}}ExtraConfig = Omit<RequestInit, 'body'> & {
12
- {{#if pathParameters}}pathParams: {{addNamespace pathParameters @root.componentNames}};
13
- {{/if}}{{#if queryParameters}}params?: {{addNamespace queryParameters @root.componentNames}};
14
- {{/if}}{{#if requestBody}}body?: {{addNamespace requestBody @root.componentNames}};
10
+ export type {{{name}}}Response = {{addNamespace response @root.componentNames}};
11
+ {{#if pathParameters}}export type {{{name}}}PathParams = {{addNamespace pathParameters @root.componentNames}};
12
+ {{/if}}{{#if queryParameters}}export type {{{name}}}Params = {{addNamespace queryParameters @root.componentNames}};
13
+ {{/if}}{{#if requestBody}}export type {{{name}}}Data = {{addNamespace requestBody @root.componentNames}};
14
+ {{/if}}
15
+ export type {{{name}}}ExtraConfig = Omit<RequestInit, 'body'> & {
16
+ {{#if pathParameters}}pathParams: {{{name}}}PathParams;
17
+ {{/if}}{{#if queryParameters}}params?: {{{name}}}Params;
18
+ {{/if}}{{#if requestBody}}body?: {{{name}}}Data;
15
19
  {{/if}}
16
20
  };
17
21
  {{> api-jsdoc}}
@@ -1,9 +1,12 @@
1
- type {{{name}}}Response = {{addNamespace response @root.componentNames}};
1
+ {{#if pathParameters}}export type {{{name}}}PathParams = {{addNamespace pathParameters @root.componentNames}};
2
+ {{/if}}{{#if queryParameters}}export type {{{name}}}Params = {{addNamespace queryParameters @root.componentNames}};
3
+ {{/if}}{{#if requestBody}}export type {{{name}}}Data = {{addNamespace requestBody @root.componentNames}};
4
+ {{/if}}export type {{{name}}}Response = {{addNamespace response @root.componentNames}};
2
5
  {{#or pathParameters queryParameters requestBody}}
3
- type {{{name}}}ExtraConfig = Options & {
4
- {{#if pathParameters}}pathParams: {{addNamespace pathParameters @root.componentNames}};
5
- {{/if}}{{#if queryParameters}}searchParams: {{addNamespace queryParameters @root.componentNames}};
6
- {{/if}}{{#if requestBody}}json: {{addNamespace requestBody @root.componentNames}};
6
+ export type {{{name}}}ExtraConfig = Options & {
7
+ {{#if pathParameters}}pathParams: {{{name}}}PathParams;
8
+ {{/if}}{{#if queryParameters}}searchParams: {{{name}}}Params;
9
+ {{/if}}{{#if requestBody}}json: {{{name}}}Data;
7
10
  {{/if}}
8
11
  };
9
12
  {{/or}}
@@ -8,11 +8,15 @@ import type * as ComponentTypes from '../components';
8
8
  const {{{currentTag.tag}}}DefaultConfig = resolveTagDefaultConfig(defaultConfig, '{{{currentTag.tag}}}DefaultConfig');
9
9
 
10
10
  {{#each currentTag.apis}}
11
- type {{{name}}}Response = {{addNamespace response @root.componentNames}};
12
- type {{{name}}}ExtraConfig = Options & {
13
- {{#if pathParameters}}pathParams: {{addNamespace pathParameters @root.componentNames}};
14
- {{/if}}{{#if queryParameters}}searchParams: {{addNamespace queryParameters @root.componentNames}};
15
- {{/if}}{{#if requestBody}}json: {{addNamespace requestBody @root.componentNames}};
11
+ export type {{{name}}}Response = {{addNamespace response @root.componentNames}};
12
+ {{#if pathParameters}}export type {{{name}}}PathParams = {{addNamespace pathParameters @root.componentNames}};
13
+ {{/if}}{{#if queryParameters}}export type {{{name}}}Params = {{addNamespace queryParameters @root.componentNames}};
14
+ {{/if}}{{#if requestBody}}export type {{{name}}}Data = {{addNamespace requestBody @root.componentNames}};
15
+ {{/if}}
16
+ export type {{{name}}}ExtraConfig = Options & {
17
+ {{#if pathParameters}}pathParams: {{{name}}}PathParams;
18
+ {{/if}}{{#if queryParameters}}searchParams: {{{name}}}Params;
19
+ {{/if}}{{#if requestBody}}json: {{{name}}}Data;
16
20
  {{/if}}
17
21
  };
18
22
  {{> api-jsdoc}}
@@ -33,13 +33,37 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.prettierConfig = void 0;
36
+ exports.defaultFormatOptions = void 0;
37
+ exports.isFormatEnabled = isFormatEnabled;
37
38
  exports.format = format;
38
- const prettierBabel = __importStar(require("prettier/plugins/babel"));
39
- const prettierEsTree = __importStar(require("prettier/plugins/estree"));
40
- const prettierTs = __importStar(require("prettier/plugins/typescript"));
41
- const prettier = __importStar(require("prettier/standalone"));
42
- exports.prettierConfig = {
39
+ const config_1 = require("../config");
40
+ /**
41
+ * 回退用的真实动态 import。
42
+ * `new Function` 内的 `import()` 不会被 TypeScript 降级为 `require()`,用于 CJS 产物中加载纯 ESM 包。
43
+ */
44
+ // eslint-disable-next-line no-new-func -- CJS 产物必须保留 new Function 包裹的真实动态 import,才能加载纯 ESM 的 oxfmt
45
+ const fallbackImport = new Function('specifier', 'return import(specifier)');
46
+ /** oxfmt 只加载一次,后续复用 */
47
+ let oxfmtPromise;
48
+ /**
49
+ * oxfmt 是 ESM-only(`"type": "module"`,无 require 条件),而 worma 的编译产物是 CommonJS。
50
+ *
51
+ * 优先使用字面量 `import()`:vite/vitest 的 SSR 转换器只会识别源码中直接出现的 `import(...)`
52
+ * 并替换为它的 dynamic import 回调,因此测试环境必须走这条路径。
53
+ * 而在 `module: CommonJS` 编译产物中,TypeScript 会把 `import()` 降级为 `require()`,
54
+ * 对纯 ESM 包会抛 `ERR_REQUIRE_ESM`(或 oxfmt 含顶层 await 时抛 `ERR_REQUIRE_ASYNC_MODULE`),
55
+ * 此时回退到 `new Function` 包裹的真实动态 import。
56
+ */
57
+ function loadOxfmt() {
58
+ oxfmtPromise ??= Promise.resolve().then(() => __importStar(require('oxfmt'))).catch(() => fallbackImport('oxfmt'));
59
+ return oxfmtPromise;
60
+ }
61
+ /**
62
+ * 与历史 prettier 配置等价的默认格式化参数。
63
+ * prettier 的 `insertPragma` 在 oxfmt 中不存在(原本即为 false,直接去掉);
64
+ * `endOfLine: 'auto'` 不为 oxfmt 支持,语义最接近的是 `lf`。
65
+ */
66
+ exports.defaultFormatOptions = {
43
67
  printWidth: 120,
44
68
  tabWidth: 2,
45
69
  useTabs: false,
@@ -47,18 +71,41 @@ exports.prettierConfig = {
47
71
  singleQuote: true,
48
72
  trailingComma: 'none',
49
73
  bracketSpacing: true,
50
- insertPragma: false,
51
- endOfLine: 'auto',
52
74
  bracketSameLine: true,
53
75
  arrowParens: 'avoid',
54
- vueIndentScriptAndStyle: false,
55
76
  singleAttributePerLine: true,
77
+ vueIndentScriptAndStyle: false,
78
+ endOfLine: 'lf',
56
79
  };
57
- async function format(text, config) {
58
- return prettier.format(text, {
59
- ...exports.prettierConfig,
60
- parser: 'typescript', // Specify to use babel parser
80
+ /** 合并 默认 < 用户全局配置 < 本次调用覆盖,并剥掉 worma 自有的 `enabled` 字段 */
81
+ function resolveOptions(config) {
82
+ const { enabled, ...oxfmtOptions } = {
83
+ ...exports.defaultFormatOptions,
84
+ ...((0, config_1.getGlobalConfig)().format ?? {}),
61
85
  ...(config ?? {}),
62
- plugins: [prettierTs, prettierEsTree, prettierBabel],
63
- });
86
+ };
87
+ void enabled;
88
+ return oxfmtOptions;
89
+ }
90
+ /**
91
+ * 是否对生成产物执行格式化。由 `format.enabled` 控制,默认 true。
92
+ */
93
+ function isFormatEnabled() {
94
+ return (0, config_1.getGlobalConfig)().format?.enabled ?? true;
95
+ }
96
+ /**
97
+ * 格式化一段代码。
98
+ * @param fileName 文件名,oxfmt 依据扩展名推断语言(无 prettier 的 `parser` 选项)
99
+ * @param text 源码文本
100
+ * @param config 单次调用的覆盖配置,优先级最高
101
+ * @returns 格式化后的代码;解析失败时抛错,由调用方回退原文
102
+ */
103
+ async function format(fileName, text, config) {
104
+ const { format: oxfmtFormat } = await loadOxfmt();
105
+ const result = await oxfmtFormat(fileName, text, resolveOptions(config));
106
+ const fatal = result.errors?.find(error => error.severity === 'Error');
107
+ if (fatal) {
108
+ throw new Error(`oxfmt failed to format ${fileName}: ${fatal.message}`);
109
+ }
110
+ return result.code;
64
111
  }
@@ -111,6 +111,6 @@ async function generateFile(distDir, fileName, content) {
111
111
  await promises_1.default.mkdir(distDir, { recursive: true });
112
112
  }
113
113
  const filePath = node_path_1.default.join(distDir, fileName);
114
- const formattedText = await (0, format_1.format)(content);
114
+ const formattedText = await (0, format_1.format)(fileName, content);
115
115
  await promises_1.default.writeFile(filePath, formattedText);
116
116
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wormajs",
3
- "version": "0.3.1",
3
+ "version": "1.0.0-beta.0",
4
4
  "description": "A modern OpenAPI code generator - Generate type-safe API clients from OpenAPI specs",
5
5
  "author": "worma",
6
6
  "license": "MIT",
@@ -50,6 +50,7 @@
50
50
  "dependencies": {
51
51
  "alova": "^3.3.4",
52
52
  "chalk": "4.1.2",
53
+ "cli-table3": "^0.6.5",
53
54
  "cli-truncate": "^4.0.0",
54
55
  "commander": "^14.0.0",
55
56
  "esbuild": "^0.25.6",
@@ -60,7 +61,7 @@
60
61
  "log-update": "^6.1.0",
61
62
  "openapi-types": "^12.1.3",
62
63
  "ora": "5.4.1",
63
- "prettier": "^3.6.2",
64
+ "oxfmt": "^0.67.0",
64
65
  "skills": "^1.5.13",
65
66
  "string-width": "^7.2.0",
66
67
  "swagger2openapi": "^7.0.8",