wormajs 0.4.0 → 1.0.0-beta.1

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 (51) hide show
  1. package/dist/bin/actions.js +182 -5
  2. package/dist/bin/cli.js +8 -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 +265 -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 +113 -5
  24. package/dist/index.js +18 -1
  25. package/dist/plugins/index.js +2 -2
  26. package/dist/plugins/presets/aiDoc.js +27 -2
  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/alova/common/services/{tag}.d.cts.handlebars +1 -1
  34. package/dist/template/presets/alova/module/services/{tag}.d.ts.handlebars +1 -1
  35. package/dist/template/presets/alova/partials/dts-fn-declare.handlebars +1 -1
  36. package/dist/template/presets/alova/partials/dts-types.handlebars +12 -0
  37. package/dist/template/presets/alova/typescript/services/{tag}.ts.handlebars +11 -6
  38. package/dist/template/presets/axios/partials/dts-types.handlebars +9 -5
  39. package/dist/template/presets/axios/typescript/services/{tag}.ts.handlebars +9 -5
  40. package/dist/template/presets/fetch/partials/dts-types.handlebars +8 -5
  41. package/dist/template/presets/fetch/typescript/services/{tag}.ts.handlebars +9 -5
  42. package/dist/template/presets/ky/partials/dts-types.handlebars +8 -5
  43. package/dist/template/presets/ky/typescript/services/{tag}.ts.handlebars +9 -5
  44. package/dist/utils/format.js +62 -15
  45. package/dist/utils/template.js +1 -1
  46. package/package.json +3 -2
  47. package/typings/index.d.ts +279 -13
  48. package/typings/plugins.d.ts +166 -81
  49. package/dist/plugins/presets/payloadModifier/hepler.js +0 -347
  50. package/dist/plugins/presets/platform/fastapi.js +0 -22
  51. package/dist/template/presets/alova/partials/dts-extra-config.handlebars +0 -8
@@ -1,15 +1,8 @@
1
1
  import { MethodType, RequestBody } from 'alova';
2
2
  import { OpenAPIV3_1 } from 'openapi-types';
3
+ import { FormatConfig as OxfmtFormatConfig } from 'oxfmt';
3
4
  import { z } from 'zod/v3';
4
5
 
5
- declare const DEFAULT_CONFIG: {
6
- cacheDir: string;
7
- /** Overrides cacheDir's parent directory for monorepo unified cache. */
8
- cacheRoot: string | undefined;
9
- Error: ErrorConstructor;
10
- templateData: Map<string, any>;
11
- };
12
- export declare function setGlobalConfig(config: Partial<typeof DEFAULT_CONFIG>): void;
13
6
  export type OpenAPIDocument = OpenAPIV3_1.Document;
14
7
  export type SchemaObject = OpenAPIV3_1.SchemaObject;
15
8
  export type Parameter = OpenAPIV3_1.ParameterObject;
@@ -203,11 +196,34 @@ export interface PerformanceConfig {
203
196
  transformConcurrency?: number;
204
197
  /** Max parallelism for file writes. Default 32 */
205
198
  writeConcurrency?: number;
206
- /** Apply prettier formatting to final files before write. Default true (schema-level prettier is always disabled) */
207
- formatFile?: boolean;
208
- /** Sort tags/APIs/components alphabetically for deterministic output. Default true */
199
+ /**
200
+ * Sort the collected component types alphabetically so the output order stays
201
+ * stable regardless of worker scheduling. `false` keeps collection order.
202
+ * Default true
203
+ */
209
204
  deterministicSort?: boolean;
210
205
  }
206
+ /**
207
+ * 生成产物的格式化配置。
208
+ *
209
+ * 除 `enabled` 外的所有字段都是 oxfmt 原生选项,worma 不做校验、原样透传给 oxfmt,
210
+ * 由 oxfmt 自行校验;类型提示直接来自 oxfmt,因此随 oxfmt 版本自动保持同步。
211
+ *
212
+ * @example
213
+ * ```js
214
+ * // 关闭格式化
215
+ * format: { enabled: false }
216
+ *
217
+ * // 自定义风格
218
+ * format: { printWidth: 100, trailingComma: 'all', semi: false }
219
+ * ```
220
+ */
221
+ export interface FormatOptions extends OxfmtFormatConfig {
222
+ /**
223
+ * 是否格式化生成的代码,默认 true。
224
+ */
225
+ enabled?: boolean;
226
+ }
211
227
  export interface GeneratorConfig {
212
228
  /**
213
229
  * Openapi file path, it supports json and yaml file, and network url.
@@ -324,6 +340,17 @@ export interface Config {
324
340
  * Currently, only OpenAPI specifications are supported, including OpenAPI 2.0 and 3.0 specifications.
325
341
  */
326
342
  generator: GeneratorConfig[];
343
+ /**
344
+ * 生成产物的格式化配置(基于 oxfmt),对所有 generator 生效。
345
+ * 除 `enabled` 外的字段原样透传给 oxfmt,worma 不做额外校验。
346
+ *
347
+ * @example
348
+ * ```js
349
+ * format: { enabled: false }
350
+ * format: { printWidth: 100, trailingComma: 'all', semi: false }
351
+ * ```
352
+ */
353
+ format?: FormatOptions;
327
354
  }
328
355
  export type UserConfig = Config;
329
356
  export type UserConfigFnObject = () => UserConfig;
@@ -437,12 +464,83 @@ export type GeneratorProgressEvent = {
437
464
  phase: "failed";
438
465
  error: string;
439
466
  });
467
+ /** Id and aggregated row counts of a change record persisted by one `generate()` run. */
468
+ export interface RecordedChangeInfo {
469
+ /** Zero-padded record id, e.g. `"0007"` */
470
+ id: string;
471
+ added: number;
472
+ removed: number;
473
+ modified: number;
474
+ }
440
475
  export interface GenerateApiOptions {
441
- force?: boolean;
442
476
  projectPath?: string;
443
477
  /** Per-generator lifecycle callback. Receives a discriminated union of {@link GeneratorProgressEvent}. */
444
478
  onProgress?: (event: GeneratorProgressEvent) => void;
479
+ /**
480
+ * Called once when this run persisted a change record, with its id and
481
+ * aggregated counts. Never called when the source document did not change,
482
+ * so callers can tell "source updated" apart from "nothing to record".
483
+ */
484
+ onChangeRecorded?: (change: RecordedChangeInfo) => void;
485
+ }
486
+ export type SourceStatus = "unchanged" | "changed" | "new" | "error";
487
+ export interface SourceUpdateInfo {
488
+ /** Index inside `config.generator` */
489
+ index: number;
490
+ output: string;
491
+ serverName?: string;
492
+ status: SourceStatus;
493
+ /** The URL / file that actually served the spec — also the cache key */
494
+ resolvedInput?: string;
495
+ /** Normalized hash of the raw spec text */
496
+ hash?: string;
497
+ error?: string;
498
+ }
499
+ export interface CheckUpdatesResult {
500
+ projectPath: string;
501
+ updates: SourceUpdateInfo[];
502
+ hasChanges: boolean;
503
+ /**
504
+ * Whether the project already carries a generation baseline (any index entry
505
+ * with a non-empty `tags` map). Lets callers decide whether a `new` source is
506
+ * worth surfacing: a brand-new project must stay silent on its first run,
507
+ * while an established project that gained a source should be noticed.
508
+ */
509
+ hasGenerationBaseline: boolean;
445
510
  }
511
+ /**
512
+ * Detect whether the configured OpenAPI sources changed since the last
513
+ * recorded baseline.
514
+ *
515
+ * This is a **source-level, side-effect free** check:
516
+ *
517
+ * - it only hashes the raw spec text — no parsing, no plugin hooks;
518
+ * - it only reads/writes the `source` sub-field of `index.json` entries, never
519
+ * the generation-side `hash` / `tags`;
520
+ * - when no baseline exists yet (`new`) it writes the baseline silently and
521
+ * does *not* report a change (first run must not nag the user).
522
+ *
523
+ * Nothing on the user's disk is rewritten — callers decide what to do with the
524
+ * result (the VS Code extension asks for confirmation before generating).
525
+ */
526
+ export declare function checkUpdates(config: Config, options?: {
527
+ projectPath?: string;
528
+ }): Promise<CheckUpdatesResult>;
529
+ declare const DEFAULT_CONFIG: {
530
+ cacheDir: string;
531
+ /** Overrides cacheDir's parent directory for monorepo unified cache. */
532
+ cacheRoot: string | undefined;
533
+ /**
534
+ * Maximum number of `changes/<NNNN>.json` records to keep.
535
+ * `0` (or any non-positive value) keeps every record.
536
+ */
537
+ changeHistoryLimit: number;
538
+ /** 用户自定义的产物格式化配置,未设置时使用内置默认值 */
539
+ format: FormatOptions | undefined;
540
+ Error: ErrorConstructor;
541
+ templateData: Map<string, any>;
542
+ };
543
+ export declare function setGlobalConfig(config: Partial<typeof DEFAULT_CONFIG>): void;
446
544
  export type TemplatePreset = "alova" | "alovaGlobals" | "axios" | "fetch" | "ky";
447
545
  export interface ConfigCreationOptions {
448
546
  projectPath?: string;
@@ -460,6 +558,174 @@ export declare function defineConfig(config: UserConfigFnObject): UserConfigFnOb
460
558
  export declare function defineConfig(config: UserConfigFnPromise): UserConfigFnPromise;
461
559
  export declare function defineConfig(config: UserConfigFn): UserConfigFn;
462
560
  export declare function defineConfig(config: UserConfigExport): UserConfigExport;
561
+ /**
562
+ * Structural diff of the **source** OpenAPI document.
563
+ *
564
+ * The baseline is the document parsed from the `beforeSpecParse` output, i.e.
565
+ * taken *before* the `specParsed` hooks run: it is the source file as authored,
566
+ * not the plugin-normalised document that generation consumes. Every difference
567
+ * is reported as a flat {@link SourceChange} row so a caller (the CLI table, the
568
+ * editor webview, a CI script) can render it without any further shaping.
569
+ *
570
+ * Design notes:
571
+ * - `$ref`s are deliberately **not** inlined: the record is a source view, so a
572
+ * component change is reported once under `#/components/...`, with the
573
+ * affected operations attached as `affects` (resolved through the reverse
574
+ * `$ref` index, including transitive references) so the impact stays visible
575
+ * without duplicating the row.
576
+ * - Description-ish keys are still recorded (they are source changes) but get
577
+ * the `doc` level so callers can de-emphasise them.
578
+ */
579
+ /** Category of a change row. */
580
+ export type ChangeKind = "api" | "param" | "body" | "resp" | "comp" | "meta";
581
+ /** `+` added, `-` removed, `~` modified. */
582
+ export type ChangeOp = "+" | "-" | "~";
583
+ /** Coarse severity, used for ordering and colour only. */
584
+ export type ChangeLevel = "breaking" | "additive" | "doc";
585
+ /** One flattened source-document change. */
586
+ export interface SourceChange {
587
+ op: ChangeOp;
588
+ kind: ChangeKind;
589
+ /** `GET /pets`, `#/components/schemas/Pet` or `#/info` */
590
+ target: string;
591
+ /** Location inside the target, e.g. `query.status.schema.enum` */
592
+ item?: string;
593
+ /** Short description, e.g. `createPet -> addPet` or `+"sold"` */
594
+ detail?: string;
595
+ level: ChangeLevel;
596
+ /**
597
+ * Operations affected by a `comp` change, rendered as a list next to the
598
+ * change (one per line). Always absent for non-component kinds.
599
+ */
600
+ affects?: string[];
601
+ }
602
+ /**
603
+ * Diff two source documents and return the flattened change rows.
604
+ *
605
+ * Returns an empty array when the documents are structurally identical, so the
606
+ * caller can decide not to write a change record at all.
607
+ */
608
+ export declare function diffSourceDocument(before: unknown, after: unknown): SourceChange[];
609
+ /** Alias accepted by {@link getChange} — resolves to the newest record. */
610
+ export declare const LATEST_CHANGE_ID = "latest";
611
+ /** One generator's (output's) contribution to a change record. */
612
+ export interface ChangeItem {
613
+ output: string;
614
+ serverName?: string;
615
+ /** URL / file that served the spec this record was built from */
616
+ resolvedInput?: string;
617
+ /** Flattened source-document changes (see `diffSourceDocument`) */
618
+ changes: SourceChange[];
619
+ }
620
+ /** Aggregated row counts of a change record. */
621
+ export interface ChangeCounts {
622
+ added: number;
623
+ removed: number;
624
+ modified: number;
625
+ }
626
+ /** Lightweight list entry returned by {@link listChanges}. */
627
+ export interface ChangeSummary {
628
+ id: string;
629
+ createdAt: number;
630
+ summary: {
631
+ generators: number;
632
+ } & ChangeCounts;
633
+ outputs: string[];
634
+ }
635
+ /** A full change record — one `generate()` run aggregated. */
636
+ export interface Change {
637
+ /** Record schema; `1` for the source-document view (absent on legacy records) */
638
+ schemaVersion?: number;
639
+ id: string;
640
+ createdAt: number;
641
+ projectPath: string;
642
+ generators: ChangeItem[];
643
+ }
644
+ /** Aggregate the change rows of every generator into flat counts. */
645
+ export declare function countChanges(generators: ChangeItem[]): ChangeCounts;
646
+ /**
647
+ * List recorded changes, newest first.
648
+ *
649
+ * Sorted by `createdAt` (id as tie-breaker) rather than by file name: an id is
650
+ * only chronological as long as `index.json#changeSeq` never resets, and a
651
+ * reset would otherwise make a brand-new record show up last.
652
+ */
653
+ export declare function listChanges(projectPath: string): Promise<ChangeSummary[]>;
654
+ /**
655
+ * Read a single change record.
656
+ *
657
+ * @param projectPath absolute path of the project root
658
+ * @param id `"0007"` or the alias `"latest"` (newest record)
659
+ */
660
+ export declare function getChange(projectPath: string, id: string): Promise<Change | undefined>;
661
+ /**
662
+ * Delete a single recorded change.
663
+ *
664
+ * @param projectPath absolute path of the project root
665
+ * @param id `"0007"` or the alias `"latest"` (newest record)
666
+ *
667
+ * `index.json#changeSeq` is deliberately left untouched: it only ever allocates
668
+ * new* ids, so keeping it monotonic guarantees the deleted id is never handed
669
+ * out again for a different record.
670
+ *
671
+ * @returns the id that was deleted, or `undefined` when nothing matched
672
+ */
673
+ export declare function removeChange(projectPath: string, id: string): Promise<string | undefined>;
674
+ /** A newly added or removed API (identified by `method` + `path`). */
675
+ export interface ApiChange {
676
+ method: string;
677
+ path: string;
678
+ name?: string;
679
+ tag?: string;
680
+ }
681
+ /** An API that still exists but whose definition changed. */
682
+ export interface ApiFieldChange extends ApiChange {
683
+ /** Names of the fields whose value differs between the two versions */
684
+ changedFields: string[];
685
+ }
686
+ export interface ApiDiffResult {
687
+ added: ApiChange[];
688
+ removed: ApiChange[];
689
+ modified: ApiFieldChange[];
690
+ }
691
+ /**
692
+ * Stable matching key for an API.
693
+ *
694
+ * `method` + `path` is used instead of `name` because it survives function
695
+ * renames: a renamed API is reported as *modified* rather than
696
+ * removed + added.
697
+ */
698
+ export declare function apiDiffKey(api: Pick<Api, "method" | "path">): string;
699
+ /**
700
+ * Diff two API lists at API level.
701
+ *
702
+ * @param oldApis API list as of the previous generation (from cache)
703
+ * @param newApis API list parsed from the current spec
704
+ */
705
+ export declare function diffApis(oldApis?: Api[], newApis?: Api[]): ApiDiffResult;
706
+ /**
707
+ * The source document as of the last successful generation.
708
+ *
709
+ * It is captured **before** the `specParsed` hooks run, so the snapshot is the
710
+ * source file the user authored (after `beforeSpecParse`), not the document the
711
+ * plugin pipeline turns it into.
712
+ */
713
+ export interface SourceSnapshot {
714
+ version: number;
715
+ /** URL / file that served the spec */
716
+ resolvedInput?: string;
717
+ /** Hash of the stable-stringified document */
718
+ hash: string;
719
+ updatedAt: number;
720
+ /** The stable-stringified document, parsed back into a plain value */
721
+ doc: unknown;
722
+ }
723
+ /** Stable hash of a stable-stringified source document. */
724
+ export declare function sourceDocumentHash(documentText: string): string;
725
+ /** Read one generator's last source snapshot. */
726
+ export declare function readSourceSnapshot(projectRoot: string, outputPath: string): Promise<SourceSnapshot | null>;
727
+ /** Persist one generator's source snapshot. */
728
+ export declare function writeSourceSnapshot(projectRoot: string, outputPath: string, snapshot: SourceSnapshot): Promise<void>;
463
729
  /**
464
730
  * Generate relevant API information based on the configuration object.
465
731
  *
@@ -467,7 +733,7 @@ export declare function defineConfig(config: UserConfigExport): UserConfigExport
467
733
  * its lifecycle via {@link GeneratorProgressEvent} discriminated union events.
468
734
  *
469
735
  * @param config generating config
470
- * @param options config rules that contains `force`, `projectPath`, `onProgress`
736
+ * @param options config rules that contains `projectPath`, `onProgress`
471
737
  * @returns An array that contains the result of `generator` items in configuration whether generation is successful.
472
738
  */
473
739
  export declare function generate(config: Config, options?: GenerateApiOptions): Promise<boolean[]>;
@@ -231,9 +231,11 @@ export interface PerformanceConfig {
231
231
  transformConcurrency?: number;
232
232
  /** Max parallelism for file writes. Default 32 */
233
233
  writeConcurrency?: number;
234
- /** Apply prettier formatting to final files before write. Default true (schema-level prettier is always disabled) */
235
- formatFile?: boolean;
236
- /** Sort tags/APIs/components alphabetically for deterministic output. Default true */
234
+ /**
235
+ * Sort the collected component types alphabetically so the output order stays
236
+ * stable regardless of worker scheduling. `false` keeps collection order.
237
+ * Default true
238
+ */
237
239
  deterministicSort?: boolean;
238
240
  }
239
241
  export interface GeneratorConfig {
@@ -580,105 +582,129 @@ export interface ImportTypeOptions {
580
582
  export declare function importType(imports: Record<string, string[]>, options?: {
581
583
  files?: string[];
582
584
  }): ApiPlugin;
583
- export type ModifierScope = "params" | "pathParams" | "data" | "response";
584
- export type SchemaPrimitive = "number" | "string" | "boolean" | "undefined" | "null" | "unknown" | "any" | "never";
585
585
  /**
586
- * Array type: a native JS array whose elements are Schemas.
587
- * e.g. ['string'] means string[]; ['string', 'number'] means the tuple [string, number]
586
+ * The part of the API the modification applies to.
587
+ * - `params` — query parameters
588
+ * - `pathParams` — path parameters
589
+ * - `data` — request body
590
+ * - `response` — response body
588
591
  */
589
- export type SchemaArray = Schema[];
592
+ export type ModifierScope = "params" | "pathParams" | "data" | "response";
590
593
  /**
591
- * Object/reference type.
592
- * Required properties are written directly; optional properties are wrapped
593
- * with the `SchemaOptional` form `{ required: false, type: Schema }`
594
- * (consistent with how a standalone optional primitive is represented).
594
+ * A matching rule.
595
+ * - string: the value contains this substring
596
+ * - RegExp: the value matches this pattern
597
+ * - function: a predicate receiving the value
595
598
  */
596
- export interface SchemaReference {
597
- [attr: string]: Schema;
598
- }
599
+ export type Matcher = string | RegExp | ((value: string) => boolean);
599
600
  /**
600
- * Enum type representation.
601
+ * Type expressions understood by the plugin. TS-only types (`undefined`, `unknown`,
602
+ * `any`, `never`) are valid and are written through to the schema as-is.
601
603
  */
602
- export interface SchemaEnum {
604
+ export type SchemaPrimitive = "number" | "string" | "boolean" | "undefined" | "null" | "unknown" | "any" | "never";
605
+ /**
606
+ * The spec DSL. It only ever *describes a type*, therefore it always appears in a type
607
+ * value position (`FieldPatchObject.type`, `FieldPatchObject.items`, union members, ...).
608
+ */
609
+ export type SchemaDSL = SchemaPrimitive
610
+ /** `['string']` = `string[]`, `['string', 'number']` = the tuple `[string, number]` */
611
+ | SchemaDSL[] | {
612
+ oneOf: SchemaDSL[];
613
+ } | {
614
+ anyOf: SchemaDSL[];
615
+ } | {
616
+ allOf: SchemaDSL[];
617
+ } | {
603
618
  enum: Array<string | number | boolean | null>;
604
619
  type?: SchemaPrimitive;
605
620
  }
621
+ /** object shorthand: every listed field is required */
622
+ | {
623
+ [field: string]: SchemaDSL;
624
+ };
606
625
  /**
607
- * Composite types (oneOf / anyOf / allOf).
608
- */
609
- export interface SchemaOneOf {
610
- oneOf: Schema[];
611
- }
612
- export interface SchemaAnyOf {
613
- anyOf: Schema[];
614
- }
615
- export interface SchemaAllOf {
616
- allOf: Schema[];
617
- }
618
- /**
619
- * Standalone primitive type that is itself optional (driven by the `type` field).
620
- * Used in handler input/output to mean "this field is optional / make it optional".
621
- */
622
- export interface SchemaOptional {
623
- required: boolean;
624
- type: Schema;
625
- }
626
- /**
627
- * The data Schema.
628
- * - SchemaArray is a native array (elements are Schemas)
629
- * - composite types use { oneOf | anyOf | allOf: Schema[] }
630
- * - optional object properties are wrapped with `SchemaOptional` ({ required: false, type: Schema });
631
- * a standalone optional primitive uses the same SchemaOptional wrapper
632
- */
633
- export type Schema = SchemaPrimitive | SchemaReference | SchemaArray | SchemaEnum | SchemaOneOf | SchemaAnyOf | SchemaAllOf | SchemaOptional;
626
+ * OpenAPI keywords usable inside a patch object. Every other key is documented by the
627
+ * plugin itself, so a patch object holding one of these keys is a partial patch of the
628
+ * target while an object holding none of them is a shorthand for `properties`.
629
+ */
630
+ export interface FieldPatchObject {
631
+ /** Replaces the type: type-family keys are cleared, documentation keys are kept. */
632
+ type?: SchemaDSL;
633
+ /** Field-level requiredness, translated to the parent `required` array (or to `ParameterObject.required`). */
634
+ required?: boolean;
635
+ description?: string;
636
+ /** Explicit field-table patch, also the escape hatch when a field is named like a reserved key. */
637
+ properties?: Record<string, FieldValue>;
638
+ items?: SchemaDSL;
639
+ enum?: Array<string | number | boolean | null>;
640
+ oneOf?: SchemaDSL[];
641
+ anyOf?: SchemaDSL[];
642
+ allOf?: SchemaDSL[];
643
+ format?: string;
644
+ example?: unknown;
645
+ default?: unknown;
646
+ deprecated?: boolean;
647
+ nullable?: boolean;
648
+ title?: string;
649
+ }
650
+ /**
651
+ * A field table: an object without reserved keys, read as a patch of the field table of
652
+ * the target. Every value follows the same rules as `FieldValue`, recursively.
653
+ */
654
+ export interface FieldTable {
655
+ [field: string]: FieldValue;
656
+ }
657
+ /**
658
+ * A patch value. The same syntax is used for the top level `patch` and for every value
659
+ * inside a field table, so the rules below apply recursively.
660
+ *
661
+ * | form | meaning |
662
+ * | --- | --- |
663
+ * | `null` | delete the target |
664
+ * | string / array | shorthand for `{ type: value }`, documentation keys are kept |
665
+ * | object without reserved keys | field table, merged into the target field table |
666
+ * | object with reserved keys | partial patch of the target itself |
667
+ */
668
+ export type FieldValue = null | SchemaDSL | FieldPatchObject | FieldTable;
634
669
  export interface ModifierConfig {
635
- /**
636
- * The scope the modifier applies to (which parameter location to process).
637
- */
670
+ /** The scope the config applies to. */
638
671
  scope: ModifierScope;
639
- /**
640
- * API path filter: this config applies only when `apiDescriptor.url` matches;
641
- * when omitted it applies to all APIs. Matching rules are the same as `match` (string substring / RegExp / function).
642
- */
643
- path?: string | RegExp | ((url: string) => boolean);
644
- /**
645
- * Match rule. Only matched fields are transformed; when omitted, all fields are transformed.
646
- * - string: the original field name contains this string
647
- * - RegExp: the original field name matches this pattern
648
- * - function: receives the key and returns a boolean indicating a match
649
- */
650
- match?: string | RegExp | ((key: string) => boolean);
651
- /**
652
- * handler flexibly modifies the parameter type value.
653
- * @param schema the original field type, already converted to the user-facing Schema representation.
654
- * When the field itself is optional and is a primitive, it is passed as { required: false, type: 'string' }.
655
- * Narrow the type inside handler if needed (e.g. with a cast).
656
- * @param key the matched field key. When `match` is omitted, the whole scope object is passed to the handler
657
- * once and `key` is `undefined`; when `match` is set, `key` is the matched field name for each call.
658
- * @returns Schema to change the type; { required: boolean, type: Schema } to change requiredness (driven by `type`);
659
- * void | null | undefined to remove the field.
660
- */
661
- handler: (schema: Schema, key?: string) => Schema | {
662
- required: boolean;
663
- type: Schema;
664
- } | void | null | undefined;
672
+ /** URL filter. Omitted = every API. Multiple rules are ORed, `path` and `tag` are ANDed. */
673
+ path?: Matcher | Matcher[];
674
+ /** Tag filter: any tag of the API hitting any rule makes the config apply. */
675
+ tag?: Matcher | Matcher[];
676
+ /** Replaces the scope root with a nested node, navigating along `properties` only. */
677
+ unwrap?: string;
678
+ /** Locator. Omitted = the root itself, otherwise every matching top-level field. */
679
+ match?: Matcher;
680
+ /** Declarative patch (add / delete / modify). Runs before `handler`. */
681
+ patch?: FieldValue;
682
+ /**
683
+ * Escape hatch taking and returning raw OpenAPI schema objects.
684
+ * @param schema the located raw schema
685
+ * @param key the located field name, `undefined` when the root itself is located
686
+ * @returns the replacement schema, or `null` / `undefined` to delete the target
687
+ */
688
+ handler?: (schema: SchemaObject, key?: string) => SchemaObject | null | undefined;
665
689
  }
666
690
  export type PayloadModifierConfig = ModifierConfig;
667
- export declare function payloadModifier(configs: PayloadModifierConfig[]): ApiPlugin;
668
691
  /**
669
- * FastAPI platform plugin.
670
- *
671
- * Pass the base URL of your FastAPI app; the plugin will try `/openapi.json`
672
- * first, then fall back to the bare base URL.
692
+ * Flexibly adds, deletes and modifies the payload of your APIs.
673
693
  *
674
- * @param input - base URL string, or an array of base URLs
694
+ * Every config runs the same fixed pipeline: interface filter (`path` / `tag`) → redirect
695
+ * (`unwrap`) → locate (`match`) → patch (`patch`) → custom (`handler`). Configs are applied
696
+ * in array order, so a later config sees the result of the previous ones.
675
697
  *
676
698
  * @example
677
699
  * ```ts
678
- * plugins: [fastapi('http://fastapi-example.dokkuapp.com'), alovaGlobals()]
700
+ * payloadModifier([
701
+ * { scope: 'response', unwrap: 'data' },
702
+ * { scope: 'response', match: /[Ii]d$/, patch: 'string' },
703
+ * { scope: 'data', path: '/planPoint', patch: { operatorId: { type: 'string', required: true } } },
704
+ * ])
679
705
  * ```
680
706
  */
681
- export declare const fastapi: (input: string | string[]) => ApiPlugin;
707
+ export declare function payloadModifier(configs: PayloadModifierConfig[]): ApiPlugin;
682
708
  /**
683
709
  * Knife4j platform plugin.
684
710
  *
@@ -766,6 +792,65 @@ export interface YapiOptions {
766
792
  * ```
767
793
  */
768
794
  export declare function yapi(options: YapiOptions): ApiPlugin;
795
+ export interface PostmanOptions {
796
+ /** Postman API Key, generated from Postman → Settings → API keys */
797
+ apiKey: string;
798
+ /** The uid of the Postman collection */
799
+ collectionId: string;
800
+ }
801
+ /**
802
+ * Unwraps the OpenAPI definition returned by the Postman collection
803
+ * transformation endpoint, which responds with `{ output: "<stringified spec>" }`
804
+ * instead of the specification itself.
805
+ *
806
+ * The response is parsed exactly once. Anything that is not a transformation
807
+ * envelope (an error payload, an HTML page, a malformed body, …) throws instead
808
+ * of being silently passed through, so the real problem surfaces immediately.
809
+ * The unwrapped spec is then validated by the generator's parser, like any other
810
+ * input — this function does not re-parse or validate it.
811
+ */
812
+ export declare function unwrapTransformationOutput(spec: string): string;
813
+ /**
814
+ * Postman platform plugin.
815
+ *
816
+ * Postman collections are not OpenAPI documents, so the plugin points `input` to
817
+ * the collection transformation endpoint, which converts the collection into an
818
+ * OpenAPI definition:
819
+ *
820
+ * ```
821
+ * https://api.getpostman.com/collections/<collectionId>/transformations
822
+ * ```
823
+ *
824
+ * The `x-api-key` header is injected through `fetchOptions`. The endpoint responds
825
+ * with `{ output: "<spec>" }`, so the plugin unwraps that envelope in its
826
+ * `beforeSpecParse` hook.
827
+ *
828
+ * `apiKey` and `collectionId` are both required — the plugin throws a clear error
829
+ * when either is missing.
830
+ *
831
+ * @param options - `{ apiKey, collectionId }`
832
+ * @param options.apiKey - Postman API key used to read the collection
833
+ * @param options.collectionId - The uid of the Postman collection
834
+ *
835
+ * @example
836
+ * ```ts
837
+ * import { postman, alovaGlobals } from 'wormajs/plugin';
838
+ *
839
+ * defineConfig({
840
+ * generator: [{
841
+ * plugins: [
842
+ * postman({
843
+ * apiKey: 'PMAK-xxx',
844
+ * collectionId: '12345678-a1b2-c3d4-e5f6-7890abcdef12',
845
+ * }),
846
+ * alovaGlobals(),
847
+ * ],
848
+ * output: './src/api',
849
+ * }]
850
+ * });
851
+ * ```
852
+ */
853
+ export declare function postman({ apiKey, collectionId }: PostmanOptions): ApiPlugin;
769
854
  /**
770
855
  * Rename style options
771
856
  */