@ir-kit/openapi-tools 0.1.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 (63) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +48 -0
  3. package/dist/diff.d.ts +65 -0
  4. package/dist/diff.d.ts.map +1 -0
  5. package/dist/diff.js +296 -0
  6. package/dist/diff.js.map +1 -0
  7. package/dist/index.d.ts +10 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +8 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/ir.d.ts +5 -0
  12. package/dist/ir.d.ts.map +1 -0
  13. package/dist/ir.js +36 -0
  14. package/dist/ir.js.map +1 -0
  15. package/dist/load.d.ts +27 -0
  16. package/dist/load.d.ts.map +1 -0
  17. package/dist/load.js +38 -0
  18. package/dist/load.js.map +1 -0
  19. package/dist/match.d.ts +20 -0
  20. package/dist/match.d.ts.map +1 -0
  21. package/dist/match.js +60 -0
  22. package/dist/match.js.map +1 -0
  23. package/dist/merge/components.d.ts +7 -0
  24. package/dist/merge/components.d.ts.map +1 -0
  25. package/dist/merge/components.js +86 -0
  26. package/dist/merge/components.js.map +1 -0
  27. package/dist/merge/core.d.ts +3 -0
  28. package/dist/merge/core.d.ts.map +1 -0
  29. package/dist/merge/core.js +181 -0
  30. package/dist/merge/core.js.map +1 -0
  31. package/dist/merge/paths.d.ts +9 -0
  32. package/dist/merge/paths.d.ts.map +1 -0
  33. package/dist/merge/paths.js +43 -0
  34. package/dist/merge/paths.js.map +1 -0
  35. package/dist/merge/refs.d.ts +3 -0
  36. package/dist/merge/refs.d.ts.map +1 -0
  37. package/dist/merge/refs.js +34 -0
  38. package/dist/merge/refs.js.map +1 -0
  39. package/dist/merge/types.d.ts +55 -0
  40. package/dist/merge/types.d.ts.map +1 -0
  41. package/dist/merge/types.js +2 -0
  42. package/dist/merge/types.js.map +1 -0
  43. package/dist/merge.d.ts +5 -0
  44. package/dist/merge.d.ts.map +1 -0
  45. package/dist/merge.js +4 -0
  46. package/dist/merge.js.map +1 -0
  47. package/dist/parse.d.ts +7 -0
  48. package/dist/parse.d.ts.map +1 -0
  49. package/dist/parse.js +23 -0
  50. package/dist/parse.js.map +1 -0
  51. package/dist/route.d.ts +17 -0
  52. package/dist/route.d.ts.map +1 -0
  53. package/dist/route.js +2 -0
  54. package/dist/route.js.map +1 -0
  55. package/dist/router.d.ts +22 -0
  56. package/dist/router.d.ts.map +1 -0
  57. package/dist/router.js +40 -0
  58. package/dist/router.js.map +1 -0
  59. package/dist/schema.d.ts +7 -0
  60. package/dist/schema.d.ts.map +1 -0
  61. package/dist/schema.js +15 -0
  62. package/dist/schema.js.map +1 -0
  63. package/package.json +104 -0
package/dist/match.js ADDED
@@ -0,0 +1,60 @@
1
+ import { URLPattern } from "urlpattern-polyfill";
2
+ /** Higher = more specific; literals outweigh `{param}` segments. */
3
+ function scorePath(spec) {
4
+ let score = 0;
5
+ for (const segment of spec.split("/").filter(Boolean)) {
6
+ score += segment.startsWith("{") ? 1 : 100;
7
+ }
8
+ return score;
9
+ }
10
+ const cache = new WeakMap();
11
+ function compile(routes) {
12
+ const hit = cache.get(routes);
13
+ if (hit)
14
+ return hit;
15
+ const compiled = routes.map((r) => ({
16
+ ...r,
17
+ compiled: new URLPattern({ pathname: r.pattern }),
18
+ score: scorePath(r.spec),
19
+ }));
20
+ compiled.sort((a, b) => b.score - a.score);
21
+ cache.set(routes, compiled);
22
+ return compiled;
23
+ }
24
+ /** Match a request against routes. Returns `MatchResult<R>` discriminated union or `null`. */
25
+ export function match(routes, request) {
26
+ const url = new URL(request.url);
27
+ const lower = request.method.toLowerCase();
28
+ for (const route of compile(routes)) {
29
+ if (route.method !== lower)
30
+ continue;
31
+ const m = route.compiled.exec({ pathname: url.pathname });
32
+ if (!m)
33
+ continue;
34
+ const params = {};
35
+ for (const [k, v] of Object.entries(m.pathname.groups ?? {})) {
36
+ if (typeof v === "string")
37
+ params[k] = v;
38
+ }
39
+ return {
40
+ spec: route.spec,
41
+ method: route.method,
42
+ params,
43
+ operationId: route.operationId,
44
+ };
45
+ }
46
+ return null;
47
+ }
48
+ /** Boolean: does this request hit any route? */
49
+ export function isInSpec(routes, request) {
50
+ const url = new URL(request.url);
51
+ const lower = request.method.toLowerCase();
52
+ for (const route of compile(routes)) {
53
+ if (route.method !== lower)
54
+ continue;
55
+ if (route.compiled.test({ pathname: url.pathname }))
56
+ return true;
57
+ }
58
+ return false;
59
+ }
60
+ //# sourceMappingURL=match.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"match.js","sourceRoot":"","sources":["../src/match.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAyBjD,oEAAoE;AACpE,SAAS,SAAS,CAAC,IAAY;IAC7B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;QACtD,KAAK,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IAC7C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,KAAK,GAAG,IAAI,OAAO,EAAqC,CAAC;AAE/D,SAAS,OAAO,CAAC,MAAwB;IACvC,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,IAAI,GAAG;QAAE,OAAO,GAAG,CAAC;IACpB,MAAM,QAAQ,GAAoB,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACnD,GAAG,CAAC;QACJ,QAAQ,EAAE,IAAI,UAAU,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;QACjD,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;KACzB,CAAC,CAAC,CAAC;IACJ,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAC3C,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC5B,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,KAAK,CACnB,MAAoB,EACpB,OAAgB;IAEhB,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACjC,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;IAC3C,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACpC,IAAI,KAAK,CAAC,MAAM,KAAK,KAAK;YAAE,SAAS;QACrC,MAAM,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC1D,IAAI,CAAC,CAAC;YAAE,SAAS;QACjB,MAAM,MAAM,GAA2B,EAAE,CAAC;QAC1C,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC;YAC7D,IAAI,OAAO,CAAC,KAAK,QAAQ;gBAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC3C,CAAC;QACD,OAAO;YACL,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,MAAM;YACN,WAAW,EAAE,KAAK,CAAC,WAAW;SACb,CAAC;IACtB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,QAAQ,CAAC,MAAwB,EAAE,OAAgB;IACjE,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACjC,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;IAC3C,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACpC,IAAI,KAAK,CAAC,MAAM,KAAK,KAAK;YAAE,SAAS;QACrC,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC;YAAE,OAAO,IAAI,CAAC;IACnE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { ComponentPolicy, Components, MergeSource, RenameMap } from "./types.js";
2
+ export declare function mergeComponents(sources: MergeSource[], policy?: ComponentPolicy): {
3
+ components: Components;
4
+ renames: Record<string, RenameMap>;
5
+ };
6
+ export declare function flattenRenames(perSource: Record<string, RenameMap>): RenameMap;
7
+ //# sourceMappingURL=components.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../src/merge/components.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,eAAe,EACf,UAAU,EACV,WAAW,EACX,SAAS,EACV,MAAM,YAAY,CAAC;AAoBpB,wBAAgB,eAAe,CAC7B,OAAO,EAAE,WAAW,EAAE,EACtB,MAAM,GAAE,eAAoB,GAC3B;IACD,UAAU,EAAE,UAAU,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACpC,CAqEA;AAED,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GACnC,SAAS,CASX"}
@@ -0,0 +1,86 @@
1
+ import { MergeConflictError } from "./paths.js";
2
+ import { rewriteRefs } from "./refs.js";
3
+ const DEFAULTS = {
4
+ onConflict: "namespace",
5
+ namespace: (label, name) => `${label}_${name}`,
6
+ };
7
+ const COMPONENT_SECTIONS = [
8
+ "schemas",
9
+ "responses",
10
+ "parameters",
11
+ "examples",
12
+ "requestBodies",
13
+ "headers",
14
+ "securitySchemes",
15
+ "links",
16
+ "callbacks",
17
+ "pathItems",
18
+ ];
19
+ export function mergeComponents(sources, policy = {}) {
20
+ const cfg = { ...DEFAULTS, ...policy };
21
+ const out = {};
22
+ const renames = {};
23
+ const claimed = {};
24
+ for (const section of COMPONENT_SECTIONS) {
25
+ claimed[section] = new Set();
26
+ }
27
+ for (const { label, spec } of sources) {
28
+ const renameMap = {};
29
+ renames[label] = renameMap;
30
+ const components = spec.components ?? {};
31
+ for (const section of COMPONENT_SECTIONS) {
32
+ const entries = components[section];
33
+ if (!entries || typeof entries !== "object")
34
+ continue;
35
+ const seen = claimed[section];
36
+ const sectionOut = out[section] ?? {};
37
+ for (const [name, value] of Object.entries(entries)) {
38
+ const wantRename = cfg.onConflict === "namespace" || seen.has(name);
39
+ const finalName = wantRename ? cfg.namespace(label, name) : name;
40
+ if (finalName !== name) {
41
+ renameMap[section] ??= {};
42
+ renameMap[section][name] = finalName;
43
+ }
44
+ if (sectionOut[finalName] !== undefined) {
45
+ switch (cfg.onConflict) {
46
+ case "error":
47
+ throw new MergeConflictError(`components.${section}.${name} collides across sources (source: ${label})`);
48
+ case "first-wins":
49
+ continue;
50
+ case "last-wins":
51
+ sectionOut[finalName] = value;
52
+ continue;
53
+ case "namespace":
54
+ sectionOut[finalName] = value;
55
+ continue;
56
+ }
57
+ }
58
+ else {
59
+ sectionOut[finalName] = value;
60
+ }
61
+ seen.add(finalName);
62
+ }
63
+ if (Object.keys(sectionOut).length > 0) {
64
+ out[section] = sectionOut;
65
+ }
66
+ }
67
+ }
68
+ for (const section of COMPONENT_SECTIONS) {
69
+ const sectionOut = out[section];
70
+ if (!sectionOut)
71
+ continue;
72
+ out[section] = rewriteRefs(sectionOut, flattenRenames(renames));
73
+ }
74
+ return { components: out, renames };
75
+ }
76
+ export function flattenRenames(perSource) {
77
+ const out = {};
78
+ for (const map of Object.values(perSource)) {
79
+ for (const [section, names] of Object.entries(map)) {
80
+ out[section] ??= {};
81
+ Object.assign(out[section], names);
82
+ }
83
+ }
84
+ return out;
85
+ }
86
+ //# sourceMappingURL=components.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"components.js","sourceRoot":"","sources":["../../src/merge/components.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAQxC,MAAM,QAAQ,GAA8B;IAC1C,UAAU,EAAE,WAAW;IACvB,SAAS,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,KAAK,IAAI,IAAI,EAAE;CAC/C,CAAC;AAEF,MAAM,kBAAkB,GAAG;IACzB,SAAS;IACT,WAAW;IACX,YAAY;IACZ,UAAU;IACV,eAAe;IACf,SAAS;IACT,iBAAiB;IACjB,OAAO;IACP,WAAW;IACX,WAAW;CACH,CAAC;AAEX,MAAM,UAAU,eAAe,CAC7B,OAAsB,EACtB,SAA0B,EAAE;IAK5B,MAAM,GAAG,GAAG,EAAE,GAAG,QAAQ,EAAE,GAAG,MAAM,EAAE,CAAC;IACvC,MAAM,GAAG,GAAe,EAAE,CAAC;IAC3B,MAAM,OAAO,GAA8B,EAAE,CAAC;IAC9C,MAAM,OAAO,GAAgC,EAAE,CAAC;IAEhD,KAAK,MAAM,OAAO,IAAI,kBAAkB,EAAE,CAAC;QACzC,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,GAAG,EAAE,CAAC;IAC/B,CAAC;IAED,KAAK,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,OAAO,EAAE,CAAC;QACtC,MAAM,SAAS,GAAc,EAAE,CAAC;QAChC,OAAO,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC;QAC3B,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC;QAEzC,KAAK,MAAM,OAAO,IAAI,kBAAkB,EAAE,CAAC;YACzC,MAAM,OAAO,GAAI,UAAsC,CAAC,OAAO,CAAC,CAAC;YACjE,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ;gBAAE,SAAS;YAEtD,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;YAC9B,MAAM,UAAU,GACb,GAAG,CAAC,OAAO,CAAyC,IAAI,EAAE,CAAC;YAE9D,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;gBACpD,MAAM,UAAU,GAAG,GAAG,CAAC,UAAU,KAAK,WAAW,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACpE,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;gBAEjE,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;oBACvB,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;oBAC1B,SAAS,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC;gBACvC,CAAC;gBAED,IAAI,UAAU,CAAC,SAAS,CAAC,KAAK,SAAS,EAAE,CAAC;oBACxC,QAAQ,GAAG,CAAC,UAAU,EAAE,CAAC;wBACvB,KAAK,OAAO;4BACV,MAAM,IAAI,kBAAkB,CAC1B,cAAc,OAAO,IAAI,IAAI,qCAAqC,KAAK,GAAG,CAC3E,CAAC;wBACJ,KAAK,YAAY;4BACf,SAAS;wBACX,KAAK,WAAW;4BACd,UAAU,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC;4BAC9B,SAAS;wBACX,KAAK,WAAW;4BACd,UAAU,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC;4BAC9B,SAAS;oBACb,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,UAAU,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC;gBAChC,CAAC;gBACD,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YACtB,CAAC;YAED,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtC,GAA+B,CAAC,OAAO,CAAC,GAAG,UAAU,CAAC;YACzD,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,MAAM,OAAO,IAAI,kBAAkB,EAAE,CAAC;QACzC,MAAM,UAAU,GAAI,GAA+B,CAAC,OAAO,CAAC,CAAC;QAC7D,IAAI,CAAC,UAAU;YAAE,SAAS;QACzB,GAA+B,CAAC,OAAO,CAAC,GAAG,WAAW,CACrD,UAAU,EACV,cAAc,CAAC,OAAO,CAAC,CACxB,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,SAAoC;IAEpC,MAAM,GAAG,GAAc,EAAE,CAAC;IAC1B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3C,KAAK,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACnD,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACpB,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Document, MergeOptions, MergeSource } from "./types.js";
2
+ export declare function merge(sources: MergeSource[], opts?: MergeOptions): Document;
3
+ //# sourceMappingURL=core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/merge/core.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,QAAQ,EACR,YAAY,EACZ,WAAW,EAIZ,MAAM,YAAY,CAAC;AAapB,wBAAgB,KAAK,CACnB,OAAO,EAAE,WAAW,EAAE,EACtB,IAAI,GAAE,YAAiB,GACtB,QAAQ,CAqDV"}
@@ -0,0 +1,181 @@
1
+ import { flattenRenames, mergeComponents } from "./components.js";
2
+ import { MergeConflictError, mergePaths } from "./paths.js";
3
+ import { rewriteRefs } from "./refs.js";
4
+ const HTTP_METHODS = [
5
+ "get",
6
+ "put",
7
+ "post",
8
+ "delete",
9
+ "options",
10
+ "head",
11
+ "patch",
12
+ "trace",
13
+ ];
14
+ export function merge(sources, opts = {}) {
15
+ if (sources.length === 0) {
16
+ return {
17
+ openapi: "3.1.0",
18
+ info: { title: "Merged API", version: "0.0.0" },
19
+ paths: {},
20
+ };
21
+ }
22
+ const { components, renames } = mergeComponents(sources, opts.components);
23
+ const rewrittenSources = sources.map(({ label, spec }) => {
24
+ const renameMap = renames[label];
25
+ if (!renameMap || Object.keys(renameMap).length === 0) {
26
+ return { label, spec };
27
+ }
28
+ const rewrittenPaths = rewriteRefs(spec.paths ?? {}, renameMap);
29
+ const rewrittenWebhooks = spec.webhooks
30
+ ? rewriteRefs(spec.webhooks, renameMap)
31
+ : undefined;
32
+ return {
33
+ label,
34
+ spec: {
35
+ ...spec,
36
+ paths: rewrittenPaths,
37
+ ...(rewrittenWebhooks ? { webhooks: rewrittenWebhooks } : {}),
38
+ },
39
+ };
40
+ });
41
+ resolveOperationIdConflicts(rewrittenSources, opts.operationIds);
42
+ const { paths } = mergePaths(rewrittenSources, opts.paths);
43
+ const allRenames = flattenRenames(renames);
44
+ const finalPaths = rewriteRefs(paths, allRenames);
45
+ const webhooks = mergeWebhooks(rewrittenSources);
46
+ const tags = mergeTags(sources, opts.tags);
47
+ const servers = mergeServers(sources, opts.servers);
48
+ const security = mergeSecurity(sources);
49
+ const info = mergeInfo(sources, opts.info);
50
+ const out = {
51
+ openapi: "3.1.0",
52
+ info,
53
+ paths: finalPaths,
54
+ };
55
+ if (servers.length > 0)
56
+ out.servers = servers;
57
+ if (Object.keys(components).length > 0)
58
+ out.components = components;
59
+ if (tags.length > 0)
60
+ out.tags = tags;
61
+ if (security.length > 0)
62
+ out.security = security;
63
+ if (Object.keys(webhooks).length > 0)
64
+ out.webhooks = webhooks;
65
+ return out;
66
+ }
67
+ function mergeInfo(sources, override) {
68
+ const first = sources[0]?.spec.info ?? {};
69
+ const merged = {
70
+ ...first,
71
+ title: override?.title ?? first.title ?? "Merged API",
72
+ version: override?.version ?? first.version ?? "0.0.0",
73
+ };
74
+ if (override?.description !== undefined)
75
+ merged.description = override.description;
76
+ if (override?.summary !== undefined)
77
+ merged.summary = override.summary;
78
+ if (override?.contact !== undefined)
79
+ merged.contact = override.contact;
80
+ if (override?.license !== undefined)
81
+ merged.license = override.license;
82
+ if (override?.termsOfService !== undefined)
83
+ merged.termsOfService = override.termsOfService;
84
+ return merged;
85
+ }
86
+ function mergeTags(sources, policy = {}) {
87
+ const strategy = policy.strategy ?? "union";
88
+ const namespace = policy.namespace ?? ((label, tag) => `${label}:${tag}`);
89
+ const seen = new Map();
90
+ for (const { label, spec } of sources) {
91
+ for (const tag of spec.tags ?? []) {
92
+ const finalName = strategy === "namespace" ? namespace(label, tag.name) : tag.name;
93
+ if (!seen.has(finalName)) {
94
+ seen.set(finalName, { ...tag, name: finalName });
95
+ }
96
+ }
97
+ }
98
+ return [...seen.values()];
99
+ }
100
+ function mergeServers(sources, policy = {}) {
101
+ const strategy = policy.strategy ?? "union";
102
+ if (strategy === "first")
103
+ return sources[0]?.spec.servers ?? [];
104
+ if (strategy === "last") {
105
+ return sources[sources.length - 1]?.spec.servers ?? [];
106
+ }
107
+ const seen = new Set();
108
+ const out = [];
109
+ for (const { spec } of sources) {
110
+ for (const server of spec.servers ?? []) {
111
+ if (seen.has(server.url))
112
+ continue;
113
+ seen.add(server.url);
114
+ out.push(server);
115
+ }
116
+ }
117
+ return out;
118
+ }
119
+ function mergeSecurity(sources) {
120
+ const seen = new Set();
121
+ const out = [];
122
+ for (const { spec } of sources) {
123
+ for (const req of spec.security ?? []) {
124
+ const key = JSON.stringify(req);
125
+ if (seen.has(key))
126
+ continue;
127
+ seen.add(key);
128
+ out.push(req);
129
+ }
130
+ }
131
+ return out;
132
+ }
133
+ function mergeWebhooks(sources) {
134
+ const out = {};
135
+ for (const { spec } of sources) {
136
+ for (const [name, item] of Object.entries(spec.webhooks ?? {})) {
137
+ if (!(name in out))
138
+ out[name] = item;
139
+ }
140
+ }
141
+ return out;
142
+ }
143
+ function resolveOperationIdConflicts(sources, policy = {}) {
144
+ const onConflict = policy.onConflict ?? "namespace";
145
+ const namespace = policy.namespace ?? ((label, id) => `${label}_${id}`);
146
+ const claimed = new Map();
147
+ for (const { label, spec } of sources) {
148
+ for (const item of Object.values(spec.paths ?? {})) {
149
+ if (!item)
150
+ continue;
151
+ for (const method of HTTP_METHODS) {
152
+ const op = item[method];
153
+ if (!op?.operationId)
154
+ continue;
155
+ const id = op.operationId;
156
+ if (onConflict === "namespace") {
157
+ op.operationId = namespace(label, id);
158
+ continue;
159
+ }
160
+ const owner = claimed.get(id);
161
+ if (!owner) {
162
+ claimed.set(id, label);
163
+ continue;
164
+ }
165
+ if (owner === label)
166
+ continue;
167
+ switch (onConflict) {
168
+ case "error":
169
+ throw new MergeConflictError(`operationId "${id}" appears in both "${owner}" and "${label}"`);
170
+ case "first-wins":
171
+ delete op.operationId;
172
+ continue;
173
+ case "last-wins":
174
+ claimed.set(id, label);
175
+ continue;
176
+ }
177
+ }
178
+ }
179
+ }
180
+ }
181
+ //# sourceMappingURL=core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../../src/merge/core.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { Document, MergeSource, PathPolicy } from "./types.js";
2
+ export declare function mergePaths(sources: MergeSource[], policy?: PathPolicy): {
3
+ paths: Document["paths"];
4
+ pathPrefixes: Record<string, string>;
5
+ };
6
+ export declare class MergeConflictError extends Error {
7
+ constructor(message: string);
8
+ }
9
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/merge/paths.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAY,UAAU,EAAE,MAAM,YAAY,CAAC;AAO9E,wBAAgB,UAAU,CACxB,OAAO,EAAE,WAAW,EAAE,EACtB,MAAM,GAAE,UAAe,GACtB;IACD,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtC,CAsCA;AAED,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B"}
@@ -0,0 +1,43 @@
1
+ const DEFAULTS = {
2
+ onConflict: "error",
3
+ prefix: (label) => `/${label}`,
4
+ };
5
+ export function mergePaths(sources, policy = {}) {
6
+ const cfg = { ...DEFAULTS, ...policy };
7
+ const out = {};
8
+ const pathPrefixes = {};
9
+ for (const { label, spec } of sources) {
10
+ const sourcePaths = spec.paths ?? {};
11
+ const prefix = cfg.onConflict === "prefix" ? cfg.prefix(label) : "";
12
+ if (prefix)
13
+ pathPrefixes[label] = prefix;
14
+ for (const [path, item] of Object.entries(sourcePaths)) {
15
+ if (!item)
16
+ continue;
17
+ const fullPath = `${prefix}${path}`;
18
+ if (!(fullPath in out)) {
19
+ out[fullPath] = item;
20
+ continue;
21
+ }
22
+ switch (cfg.onConflict) {
23
+ case "error":
24
+ throw new MergeConflictError(`path collision at "${fullPath}" (source: ${label})`);
25
+ case "first-wins":
26
+ continue;
27
+ case "last-wins":
28
+ out[fullPath] = item;
29
+ continue;
30
+ case "prefix":
31
+ throw new MergeConflictError(`path collision after prefixing at "${fullPath}" — duplicate label "${label}"?`);
32
+ }
33
+ }
34
+ }
35
+ return { paths: out, pathPrefixes };
36
+ }
37
+ export class MergeConflictError extends Error {
38
+ constructor(message) {
39
+ super(message);
40
+ this.name = "MergeConflictError";
41
+ }
42
+ }
43
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/merge/paths.ts"],"names":[],"mappings":"AAEA,MAAM,QAAQ,GAAyB;IACrC,UAAU,EAAE,OAAO;IACnB,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,KAAK,EAAE;CAC/B,CAAC;AAEF,MAAM,UAAU,UAAU,CACxB,OAAsB,EACtB,SAAqB,EAAE;IAKvB,MAAM,GAAG,GAAG,EAAE,GAAG,QAAQ,EAAE,GAAG,MAAM,EAAE,CAAC;IACvC,MAAM,GAAG,GAA6B,EAAE,CAAC;IACzC,MAAM,YAAY,GAA2B,EAAE,CAAC;IAEhD,KAAK,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,OAAO,EAAE,CAAC;QACtC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;QACrC,MAAM,MAAM,GAAG,GAAG,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,IAAI,MAAM;YAAE,YAAY,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC;QAEzC,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;YACvD,IAAI,CAAC,IAAI;gBAAE,SAAS;YACpB,MAAM,QAAQ,GAAG,GAAG,MAAM,GAAG,IAAI,EAAE,CAAC;YAEpC,IAAI,CAAC,CAAC,QAAQ,IAAI,GAAG,CAAC,EAAE,CAAC;gBACvB,GAAG,CAAC,QAAQ,CAAC,GAAG,IAAgB,CAAC;gBACjC,SAAS;YACX,CAAC;YAED,QAAQ,GAAG,CAAC,UAAU,EAAE,CAAC;gBACvB,KAAK,OAAO;oBACV,MAAM,IAAI,kBAAkB,CAC1B,sBAAsB,QAAQ,cAAc,KAAK,GAAG,CACrD,CAAC;gBACJ,KAAK,YAAY;oBACf,SAAS;gBACX,KAAK,WAAW;oBACd,GAAG,CAAC,QAAQ,CAAC,GAAG,IAAgB,CAAC;oBACjC,SAAS;gBACX,KAAK,QAAQ;oBACX,MAAM,IAAI,kBAAkB,CAC1B,sCAAsC,QAAQ,wBAAwB,KAAK,IAAI,CAChF,CAAC;YACN,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,GAAwB,EAAE,YAAY,EAAE,CAAC;AAC3D,CAAC;AAED,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAC3C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF"}
@@ -0,0 +1,3 @@
1
+ import type { RenameMap } from "./types.js";
2
+ export declare function rewriteRefs<T>(node: T, renames: RenameMap): T;
3
+ //# sourceMappingURL=refs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refs.d.ts","sourceRoot":"","sources":["../../src/merge/refs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,wBAAgB,WAAW,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,GAAG,CAAC,CAc7D"}
@@ -0,0 +1,34 @@
1
+ export function rewriteRefs(node, renames) {
2
+ if (node === null || typeof node !== "object")
3
+ return node;
4
+ if (Array.isArray(node)) {
5
+ return node.map((v) => rewriteRefs(v, renames));
6
+ }
7
+ const out = {};
8
+ for (const [k, v] of Object.entries(node)) {
9
+ if (k === "$ref" && typeof v === "string") {
10
+ out[k] = rewriteRef(v, renames);
11
+ }
12
+ else {
13
+ out[k] = rewriteRefs(v, renames);
14
+ }
15
+ }
16
+ return out;
17
+ }
18
+ const REF_PREFIX = "#/components/";
19
+ function rewriteRef(ref, renames) {
20
+ if (!ref.startsWith(REF_PREFIX))
21
+ return ref;
22
+ const tail = ref.slice(REF_PREFIX.length);
23
+ const slash = tail.indexOf("/");
24
+ if (slash === -1)
25
+ return ref;
26
+ const section = tail.slice(0, slash);
27
+ const rest = tail.slice(slash + 1);
28
+ const nameEnd = rest.indexOf("/");
29
+ const name = nameEnd === -1 ? rest : rest.slice(0, nameEnd);
30
+ const remainder = nameEnd === -1 ? "" : rest.slice(nameEnd);
31
+ const next = renames[section]?.[name];
32
+ return next ? `${REF_PREFIX}${section}/${next}${remainder}` : ref;
33
+ }
34
+ //# sourceMappingURL=refs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refs.js","sourceRoot":"","sources":["../../src/merge/refs.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,WAAW,CAAI,IAAO,EAAE,OAAkB;IACxD,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3D,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC,CAAiB,CAAC;IAClE,CAAC;IACD,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAA+B,CAAC,EAAE,CAAC;QACrE,IAAI,CAAC,KAAK,MAAM,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC1C,GAAG,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QAClC,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;IACD,OAAO,GAAmB,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,GAAG,eAAe,CAAC;AAEnC,SAAS,UAAU,CAAC,GAAW,EAAE,OAAkB;IACjD,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,GAAG,CAAC;IAC5C,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,KAAK,KAAK,CAAC,CAAC;QAAE,OAAO,GAAG,CAAC;IAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACrC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,IAAI,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAC5D,MAAM,SAAS,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC5D,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;IACtC,OAAO,IAAI,CAAC,CAAC,CAAC,GAAG,UAAU,GAAG,OAAO,IAAI,IAAI,GAAG,SAAS,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;AACpE,CAAC"}
@@ -0,0 +1,55 @@
1
+ import type { OpenAPIV3_1 } from "@hey-api/spec-types";
2
+ export type Document = OpenAPIV3_1.Document;
3
+ export type PathItem = OpenAPIV3_1.PathItemObject;
4
+ export type Components = NonNullable<Document["components"]>;
5
+ export interface MergeSource {
6
+ /** Stable identifier used for namespacing/prefixing on conflict. */
7
+ label: string;
8
+ spec: Document;
9
+ }
10
+ export interface PathPolicy {
11
+ /** Default: `error`. `prefix` rewrites every path with `prefix(label)`. */
12
+ onConflict?: "error" | "first-wins" | "last-wins" | "prefix";
13
+ /** Default: `(label) => "/" + label`. Only used when `onConflict === "prefix"`. */
14
+ prefix?: (label: string) => string;
15
+ }
16
+ export interface ComponentPolicy {
17
+ /**
18
+ * Default: `namespace`. `namespace` always renames *every* component name
19
+ * with `namespace(label, name)`. `error` throws on collision.
20
+ */
21
+ onConflict?: "error" | "namespace" | "first-wins" | "last-wins";
22
+ /** Default: `(label, name) => label + "_" + name`. */
23
+ namespace?: (label: string, name: string) => string;
24
+ }
25
+ export interface TagPolicy {
26
+ /** Default: `union`. `namespace` prefixes each tag with the source label. */
27
+ strategy?: "union" | "namespace";
28
+ /** Default: `(label, tag) => label + ":" + tag`. */
29
+ namespace?: (label: string, tag: string) => string;
30
+ }
31
+ export interface ServerPolicy {
32
+ /** Default: `union`. */
33
+ strategy?: "union" | "first" | "last";
34
+ }
35
+ export interface OperationIdPolicy {
36
+ /** Default: `namespace`. */
37
+ onConflict?: "error" | "namespace" | "first-wins" | "last-wins";
38
+ /** Default: `(label, id) => label + "_" + id`. */
39
+ namespace?: (label: string, operationId: string) => string;
40
+ }
41
+ export interface MergeOptions {
42
+ paths?: PathPolicy;
43
+ components?: ComponentPolicy;
44
+ tags?: TagPolicy;
45
+ servers?: ServerPolicy;
46
+ operationIds?: OperationIdPolicy;
47
+ /** Override `info` on the output. Defaults to the first source's `info`. */
48
+ info?: Partial<OpenAPIV3_1.InfoObject>;
49
+ }
50
+ /**
51
+ * Per-component-section rename map: `{ schemas: { Pet: "apiA_Pet" }, ... }`.
52
+ * Used to rewrite `$ref` strings consistently after a rename.
53
+ */
54
+ export type RenameMap = Record<string, Record<string, string>>;
55
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/merge/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,MAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC;AAC5C,MAAM,MAAM,QAAQ,GAAG,WAAW,CAAC,cAAc,CAAC;AAClD,MAAM,MAAM,UAAU,GAAG,WAAW,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;AAE7D,MAAM,WAAW,WAAW;IAC1B,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,QAAQ,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,OAAO,GAAG,YAAY,GAAG,WAAW,GAAG,QAAQ,CAAC;IAC7D,mFAAmF;IACnF,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;CACpC;AAED,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,GAAG,WAAW,GAAG,YAAY,GAAG,WAAW,CAAC;IAChE,sDAAsD;IACtD,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACrD;AAED,MAAM,WAAW,SAAS;IACxB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;IACjC,oDAAoD;IACpD,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;CACpD;AAED,MAAM,WAAW,YAAY;IAC3B,wBAAwB;IACxB,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;CACvC;AAED,MAAM,WAAW,iBAAiB;IAChC,4BAA4B;IAC5B,UAAU,CAAC,EAAE,OAAO,GAAG,WAAW,GAAG,YAAY,GAAG,WAAW,CAAC;IAChE,kDAAkD;IAClD,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,MAAM,CAAC;CAC5D;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC,4EAA4E;IAC5E,IAAI,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;CACxC;AAED;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/merge/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,5 @@
1
+ export { merge } from "./merge/core.js";
2
+ export { MergeConflictError } from "./merge/paths.js";
3
+ export { rewriteRefs } from "./merge/refs.js";
4
+ export type { ComponentPolicy, Document, MergeOptions, MergeSource, OperationIdPolicy, PathPolicy, RenameMap, ServerPolicy, TagPolicy, } from "./merge/types.js";
5
+ //# sourceMappingURL=merge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.d.ts","sourceRoot":"","sources":["../src/merge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,YAAY,EACV,eAAe,EACf,QAAQ,EACR,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,UAAU,EACV,SAAS,EACT,YAAY,EACZ,SAAS,GACV,MAAM,kBAAkB,CAAC"}
package/dist/merge.js ADDED
@@ -0,0 +1,4 @@
1
+ export { merge } from "./merge/core.js";
2
+ export { MergeConflictError } from "./merge/paths.js";
3
+ export { rewriteRefs } from "./merge/refs.js";
4
+ //# sourceMappingURL=merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.js","sourceRoot":"","sources":["../src/merge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { type IR } from "@hey-api/shared";
2
+ /**
3
+ * Parse an OpenAPI spec (2.0, 3.0, or 3.1) into hey-api's normalized IR.
4
+ */
5
+ export declare function parseSpec(spec: Record<string, unknown>): IR.Model;
6
+ export type { IR };
7
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AACA,OAAO,EAAsB,KAAK,EAAE,EAAoB,MAAM,iBAAiB,CAAC;AAEhF;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,KAAK,CAgBjE;AAED,YAAY,EAAE,EAAE,EAAE,CAAC"}
package/dist/parse.js ADDED
@@ -0,0 +1,23 @@
1
+ import { Logger, Project } from "@hey-api/codegen-core";
2
+ import { Context, getParser, parseOpenApiSpec } from "@hey-api/shared";
3
+ /**
4
+ * Parse an OpenAPI spec (2.0, 3.0, or 3.1) into hey-api's normalized IR.
5
+ */
6
+ export function parseSpec(spec) {
7
+ const context = new Context({
8
+ config: {
9
+ dryRun: true,
10
+ input: [],
11
+ parser: getParser({}),
12
+ plugins: {},
13
+ pluginOrder: [],
14
+ },
15
+ dependencies: {},
16
+ logger: new Logger(),
17
+ project: new Project({ root: "" }),
18
+ spec,
19
+ });
20
+ parseOpenApiSpec(context);
21
+ return context.ir;
22
+ }
23
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,SAAS,EAAW,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEhF;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,IAA6B;IACrD,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC;QAC1B,MAAM,EAAE;YACN,MAAM,EAAE,IAAI;YACZ,KAAK,EAAE,EAAE;YACT,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC;YACrB,OAAO,EAAE,EAAE;YACX,WAAW,EAAE,EAAE;SACiD;QAClE,YAAY,EAAE,EAAE;QAChB,MAAM,EAAE,IAAI,MAAM,EAAE;QACpB,OAAO,EAAE,IAAI,OAAO,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;QAClC,IAAI;KACL,CAAC,CAAC;IACH,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC1B,OAAO,OAAO,CAAC,EAAE,CAAC;AACpB,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * A route descriptor — the minimal data needed to match an inbound request
3
+ * against an OpenAPI operation. Designed to be tree-shakable: each route
4
+ * generated by the codegen plugin is its own named export, so unused routes
5
+ * disappear from the bundle.
6
+ */
7
+ export interface Route<TSpec extends string = string, TMethod extends string = string> {
8
+ /** OpenAPI path template, e.g. `/pets/{petId}` */
9
+ spec: TSpec;
10
+ /** URLPattern-ready pathname, e.g. `/pets/:petId` */
11
+ pattern: string;
12
+ /** HTTP method, lowercase. */
13
+ method: TMethod;
14
+ /** OperationId from the spec, when defined. */
15
+ operationId?: string;
16
+ }
17
+ //# sourceMappingURL=route.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../src/route.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,KAAK,CACpB,KAAK,SAAS,MAAM,GAAG,MAAM,EAC7B,OAAO,SAAS,MAAM,GAAG,MAAM;IAE/B,kDAAkD;IAClD,IAAI,EAAE,KAAK,CAAC;IACZ,qDAAqD;IACrD,OAAO,EAAE,MAAM,CAAC;IAChB,8BAA8B;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB"}