@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.
- package/LICENSE.md +21 -0
- package/README.md +48 -0
- package/dist/diff.d.ts +65 -0
- package/dist/diff.d.ts.map +1 -0
- package/dist/diff.js +296 -0
- package/dist/diff.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/ir.d.ts +5 -0
- package/dist/ir.d.ts.map +1 -0
- package/dist/ir.js +36 -0
- package/dist/ir.js.map +1 -0
- package/dist/load.d.ts +27 -0
- package/dist/load.d.ts.map +1 -0
- package/dist/load.js +38 -0
- package/dist/load.js.map +1 -0
- package/dist/match.d.ts +20 -0
- package/dist/match.d.ts.map +1 -0
- package/dist/match.js +60 -0
- package/dist/match.js.map +1 -0
- package/dist/merge/components.d.ts +7 -0
- package/dist/merge/components.d.ts.map +1 -0
- package/dist/merge/components.js +86 -0
- package/dist/merge/components.js.map +1 -0
- package/dist/merge/core.d.ts +3 -0
- package/dist/merge/core.d.ts.map +1 -0
- package/dist/merge/core.js +181 -0
- package/dist/merge/core.js.map +1 -0
- package/dist/merge/paths.d.ts +9 -0
- package/dist/merge/paths.d.ts.map +1 -0
- package/dist/merge/paths.js +43 -0
- package/dist/merge/paths.js.map +1 -0
- package/dist/merge/refs.d.ts +3 -0
- package/dist/merge/refs.d.ts.map +1 -0
- package/dist/merge/refs.js +34 -0
- package/dist/merge/refs.js.map +1 -0
- package/dist/merge/types.d.ts +55 -0
- package/dist/merge/types.d.ts.map +1 -0
- package/dist/merge/types.js +2 -0
- package/dist/merge/types.js.map +1 -0
- package/dist/merge.d.ts +5 -0
- package/dist/merge.d.ts.map +1 -0
- package/dist/merge.js +4 -0
- package/dist/merge.js.map +1 -0
- package/dist/parse.d.ts +7 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +23 -0
- package/dist/parse.js.map +1 -0
- package/dist/route.d.ts +17 -0
- package/dist/route.d.ts.map +1 -0
- package/dist/route.js +2 -0
- package/dist/route.js.map +1 -0
- package/dist/router.d.ts +22 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +40 -0
- package/dist/router.js.map +1 -0
- package/dist/schema.d.ts +7 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +15 -0
- package/dist/schema.js.map +1 -0
- package/package.json +104 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Ahmed Rowaihi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# @ir-kit/openapi-tools
|
|
2
|
+
|
|
3
|
+
OpenAPI utilities built on top of [`@hey-api/codegen-core`](https://github.com/hey-api/openapi-ts) and `@hey-api/shared`. Spec diffing, parsing, and helpers — usable on their own without `@hey-api/openapi-ts` plugins.
|
|
4
|
+
|
|
5
|
+
Part of [ir-kit](https://github.com/ir-kit/ir-kit).
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @ir-kit/openapi-tools @hey-api/codegen-core @hey-api/shared
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
### Diff two OpenAPI specs
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { diffSpecs, parseSpec } from "@ir-kit/openapi-tools";
|
|
19
|
+
|
|
20
|
+
const before = parseSpec(beforeJson);
|
|
21
|
+
const after = parseSpec(afterJson);
|
|
22
|
+
|
|
23
|
+
const report = diffSpecs(before, after, {
|
|
24
|
+
filter: (method, path) => path.startsWith("/v1"),
|
|
25
|
+
compare: { request: true, response: true, params: true },
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Parse a spec into hey-api's IR
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import { parseSpec } from "@ir-kit/openapi-tools";
|
|
33
|
+
|
|
34
|
+
const ir = parseSpec(openApiSpecJson);
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## API
|
|
38
|
+
|
|
39
|
+
| Export | Description |
|
|
40
|
+
| --- | --- |
|
|
41
|
+
| `diffSpecs(before, after, options?)` | Compare two parsed specs, return endpoint-level diff |
|
|
42
|
+
| `parseSpec(spec)` | Parse OpenAPI 2.0 / 3.0 / 3.1 into the shared IR |
|
|
43
|
+
| `DiffOptions` / `DiffReport` / `EndpointDiff` / `ShapeDiff` / `TypeChange` / `RequiredChange` | Public types |
|
|
44
|
+
| `IR` (re-export) | hey-api shared IR namespace |
|
|
45
|
+
|
|
46
|
+
## Origin
|
|
47
|
+
|
|
48
|
+
Previously shipped as `@ir-kit/openapi-ts-orpc/tools` subpath. Extracted into its own package since the utilities are spec-host-agnostic — they don't depend on oRPC.
|
package/dist/diff.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { type IR } from "@hey-api/shared";
|
|
2
|
+
export interface DiffOptions {
|
|
3
|
+
/** Only include endpoints where this returns true. */
|
|
4
|
+
filter?: (method: string, path: string) => boolean;
|
|
5
|
+
/** Which layers to compare. All enabled by default. Set to false to skip. */
|
|
6
|
+
compare?: {
|
|
7
|
+
request?: boolean;
|
|
8
|
+
response?: boolean;
|
|
9
|
+
params?: boolean;
|
|
10
|
+
query?: boolean;
|
|
11
|
+
headers?: boolean;
|
|
12
|
+
cookies?: boolean;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export interface TypeChange {
|
|
16
|
+
key: string;
|
|
17
|
+
base: string;
|
|
18
|
+
head: string;
|
|
19
|
+
}
|
|
20
|
+
export interface RequiredChange {
|
|
21
|
+
key: string;
|
|
22
|
+
base: boolean;
|
|
23
|
+
head: boolean;
|
|
24
|
+
}
|
|
25
|
+
export interface ShapeDiff {
|
|
26
|
+
added: string[];
|
|
27
|
+
removed: string[];
|
|
28
|
+
typeChanged: TypeChange[];
|
|
29
|
+
requiredChanged: RequiredChange[];
|
|
30
|
+
}
|
|
31
|
+
export interface EndpointDiff {
|
|
32
|
+
endpoint: string;
|
|
33
|
+
method: string;
|
|
34
|
+
path: string;
|
|
35
|
+
request: ShapeDiff | null;
|
|
36
|
+
response: ShapeDiff | null;
|
|
37
|
+
params: ShapeDiff | null;
|
|
38
|
+
query: ShapeDiff | null;
|
|
39
|
+
headers: ShapeDiff | null;
|
|
40
|
+
cookies: ShapeDiff | null;
|
|
41
|
+
}
|
|
42
|
+
export interface DiffReport {
|
|
43
|
+
generatedAt: string;
|
|
44
|
+
summary: {
|
|
45
|
+
shared: number;
|
|
46
|
+
matching: number;
|
|
47
|
+
differing: number;
|
|
48
|
+
onlyInBase: number;
|
|
49
|
+
onlyInHead: number;
|
|
50
|
+
drifts: number;
|
|
51
|
+
};
|
|
52
|
+
matching: string[];
|
|
53
|
+
diffed: EndpointDiff[];
|
|
54
|
+
onlyInBase: string[];
|
|
55
|
+
onlyInHead: string[];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Diff two parsed OpenAPI specs (IR models).
|
|
59
|
+
*
|
|
60
|
+
* @param base - The reference spec (source of truth).
|
|
61
|
+
* @param head - The spec to compare against base.
|
|
62
|
+
* @param options - Filter endpoints, configure behavior.
|
|
63
|
+
*/
|
|
64
|
+
export declare function diffSpecs(base: IR.Model, head: IR.Model, options?: DiffOptions): DiffReport;
|
|
65
|
+
//# sourceMappingURL=diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,EAAE,EAKR,MAAM,iBAAiB,CAAC;AAMzB,MAAM,WAAW,WAAW;IAC1B,sDAAsD;IACtD,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACnD,6EAA6E;IAC7E,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,CAAC;CACH;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,eAAe,EAAE,cAAc,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,SAAS,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,SAAS,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,SAAS,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,SAAS,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE;QACP,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAqPD;;;;;;GAMG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,EAAE,CAAC,KAAK,EACd,IAAI,EAAE,EAAE,CAAC,KAAK,EACd,OAAO,CAAC,EAAE,WAAW,GACpB,UAAU,CAkHZ"}
|
package/dist/diff.js
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { fromRef, ref } from "@hey-api/codegen-core";
|
|
2
|
+
import { childContext, createSchemaWalker, operationResponsesMap, } from "@hey-api/shared";
|
|
3
|
+
function typedEntries(obj) {
|
|
4
|
+
return Object.entries(obj);
|
|
5
|
+
}
|
|
6
|
+
function pathKey(ctx) {
|
|
7
|
+
return fromRef(ctx.path).join(".");
|
|
8
|
+
}
|
|
9
|
+
function createShapeCollector(store) {
|
|
10
|
+
const shape = new Map();
|
|
11
|
+
const visitor = {
|
|
12
|
+
applyModifiers() { },
|
|
13
|
+
array(schema, ctx, walk) {
|
|
14
|
+
const key = pathKey(ctx);
|
|
15
|
+
const item = schema.items?.[0];
|
|
16
|
+
if (item && (item.properties || item.$ref)) {
|
|
17
|
+
shape.set(key, { type: "array<object>", required: false });
|
|
18
|
+
walk(item, childContext(ctx, "[]"));
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
shape.set(key, {
|
|
22
|
+
type: `array<${item?.type ?? "unknown"}>`,
|
|
23
|
+
required: false,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
boolean(_s, ctx) {
|
|
28
|
+
shape.set(pathKey(ctx), { type: "boolean", required: false });
|
|
29
|
+
},
|
|
30
|
+
enum(schema, ctx) {
|
|
31
|
+
const values = (schema.items ?? [])
|
|
32
|
+
.map((i) => (i.const != null ? String(i.const) : ""))
|
|
33
|
+
.filter(Boolean)
|
|
34
|
+
.sort();
|
|
35
|
+
shape.set(pathKey(ctx), {
|
|
36
|
+
type: values.length ? `enum(${values.join("|")})` : "enum",
|
|
37
|
+
required: false,
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
integer(_s, ctx) {
|
|
41
|
+
shape.set(pathKey(ctx), { type: "integer", required: false });
|
|
42
|
+
},
|
|
43
|
+
intersection(items) {
|
|
44
|
+
void items;
|
|
45
|
+
},
|
|
46
|
+
never(_s, ctx) {
|
|
47
|
+
shape.set(pathKey(ctx), { type: "never", required: false });
|
|
48
|
+
},
|
|
49
|
+
null(_s, ctx) {
|
|
50
|
+
shape.set(pathKey(ctx), { type: "null", required: false });
|
|
51
|
+
},
|
|
52
|
+
number(_s, ctx) {
|
|
53
|
+
shape.set(pathKey(ctx), { type: "number", required: false });
|
|
54
|
+
},
|
|
55
|
+
object(schema, ctx, walk) {
|
|
56
|
+
const key = pathKey(ctx);
|
|
57
|
+
if (key)
|
|
58
|
+
shape.set(key, { type: "object", required: false });
|
|
59
|
+
if (!schema.properties)
|
|
60
|
+
return;
|
|
61
|
+
const requiredSet = new Set(schema.required ?? []);
|
|
62
|
+
for (const [name, prop] of typedEntries(schema.properties)) {
|
|
63
|
+
const propCtx = childContext(ctx, name);
|
|
64
|
+
walk(prop, propCtx);
|
|
65
|
+
const existing = shape.get(pathKey(propCtx));
|
|
66
|
+
if (existing)
|
|
67
|
+
existing.required = requiredSet.has(name);
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
reference($ref, _schema, ctx) {
|
|
71
|
+
const name = $ref.split("/").at(-1);
|
|
72
|
+
if (name && store[name])
|
|
73
|
+
walk(store[name], ctx);
|
|
74
|
+
},
|
|
75
|
+
string(_s, ctx) {
|
|
76
|
+
shape.set(pathKey(ctx), { type: "string", required: false });
|
|
77
|
+
},
|
|
78
|
+
tuple(schema, ctx, walk) {
|
|
79
|
+
shape.set(pathKey(ctx), { type: "tuple", required: false });
|
|
80
|
+
for (const [i, item] of (schema.items ?? []).entries()) {
|
|
81
|
+
walk(item, childContext(ctx, i));
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
undefined(_s, ctx) {
|
|
85
|
+
shape.set(pathKey(ctx), { type: "undefined", required: false });
|
|
86
|
+
},
|
|
87
|
+
union(items) {
|
|
88
|
+
void items;
|
|
89
|
+
},
|
|
90
|
+
unknown(_s, ctx) {
|
|
91
|
+
shape.set(pathKey(ctx), { type: "unknown", required: false });
|
|
92
|
+
},
|
|
93
|
+
void(_s, ctx) {
|
|
94
|
+
shape.set(pathKey(ctx), { type: "void", required: false });
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
const walk = createSchemaWalker(visitor);
|
|
98
|
+
return { walk, shape };
|
|
99
|
+
}
|
|
100
|
+
function collectShape(schema, store) {
|
|
101
|
+
const { walk, shape } = createShapeCollector(store);
|
|
102
|
+
walk(schema, { path: ref([]), plugin: null });
|
|
103
|
+
// Replace empty root key with a typed root entry
|
|
104
|
+
if (shape.has("")) {
|
|
105
|
+
const root = shape.get("");
|
|
106
|
+
shape.delete("");
|
|
107
|
+
shape.set("(root)", root);
|
|
108
|
+
}
|
|
109
|
+
else if (shape.size === 0 && schema.type) {
|
|
110
|
+
shape.set("(root)", { type: schema.type, required: false });
|
|
111
|
+
}
|
|
112
|
+
return shape;
|
|
113
|
+
}
|
|
114
|
+
function collectParamsShape(params, store) {
|
|
115
|
+
const shape = new Map();
|
|
116
|
+
if (!params)
|
|
117
|
+
return shape;
|
|
118
|
+
for (const [name, param] of typedEntries(params)) {
|
|
119
|
+
const paramShape = collectShape(param.schema, store);
|
|
120
|
+
if (paramShape.size === 1 && paramShape.has("(root)")) {
|
|
121
|
+
const root = paramShape.get("(root)");
|
|
122
|
+
shape.set(name, { type: root.type, required: param.required ?? false });
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
shape.set(name, { type: "object", required: param.required ?? false });
|
|
126
|
+
for (const [key, info] of paramShape) {
|
|
127
|
+
if (key === "(root)")
|
|
128
|
+
continue;
|
|
129
|
+
shape.set(`${name}.${key}`, info);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return shape;
|
|
134
|
+
}
|
|
135
|
+
function diffShapes(base, head) {
|
|
136
|
+
const added = [];
|
|
137
|
+
const removed = [];
|
|
138
|
+
const typeChanged = [];
|
|
139
|
+
const requiredChanged = [];
|
|
140
|
+
for (const [key] of head)
|
|
141
|
+
if (!base.has(key))
|
|
142
|
+
added.push(key);
|
|
143
|
+
for (const [key] of base)
|
|
144
|
+
if (!head.has(key))
|
|
145
|
+
removed.push(key);
|
|
146
|
+
for (const [key, b] of base) {
|
|
147
|
+
const h = head.get(key);
|
|
148
|
+
if (!h)
|
|
149
|
+
continue;
|
|
150
|
+
if (b.type !== h.type)
|
|
151
|
+
typeChanged.push({ key, base: b.type, head: h.type });
|
|
152
|
+
if (b.required !== h.required)
|
|
153
|
+
requiredChanged.push({ key, base: b.required, head: h.required });
|
|
154
|
+
}
|
|
155
|
+
if (!added.length &&
|
|
156
|
+
!removed.length &&
|
|
157
|
+
!typeChanged.length &&
|
|
158
|
+
!requiredChanged.length)
|
|
159
|
+
return null;
|
|
160
|
+
return { added, removed, typeChanged, requiredChanged };
|
|
161
|
+
}
|
|
162
|
+
function extractEndpoints(paths, filter) {
|
|
163
|
+
const result = new Map();
|
|
164
|
+
if (!paths)
|
|
165
|
+
return result;
|
|
166
|
+
for (const [path, pathItem] of typedEntries(paths)) {
|
|
167
|
+
for (const method of ["get", "post", "put", "patch", "delete"]) {
|
|
168
|
+
const op = pathItem[method];
|
|
169
|
+
if (!op)
|
|
170
|
+
continue;
|
|
171
|
+
if (filter && !filter(method.toUpperCase(), path))
|
|
172
|
+
continue;
|
|
173
|
+
const key = `${method.toUpperCase()} ${path}`;
|
|
174
|
+
const resMap = operationResponsesMap(op);
|
|
175
|
+
result.set(key, {
|
|
176
|
+
request: op.body?.schema,
|
|
177
|
+
response: resMap.response,
|
|
178
|
+
params: op.parameters?.path,
|
|
179
|
+
query: op.parameters?.query,
|
|
180
|
+
headers: op.parameters?.header,
|
|
181
|
+
cookies: op.parameters?.cookie,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return result;
|
|
186
|
+
}
|
|
187
|
+
function countDrifts(diffed) {
|
|
188
|
+
let n = 0;
|
|
189
|
+
for (const d of diffed) {
|
|
190
|
+
for (const s of [
|
|
191
|
+
d.request,
|
|
192
|
+
d.response,
|
|
193
|
+
d.params,
|
|
194
|
+
d.query,
|
|
195
|
+
d.headers,
|
|
196
|
+
d.cookies,
|
|
197
|
+
]) {
|
|
198
|
+
if (!s)
|
|
199
|
+
continue;
|
|
200
|
+
n +=
|
|
201
|
+
s.removed.length +
|
|
202
|
+
s.added.length +
|
|
203
|
+
s.typeChanged.length +
|
|
204
|
+
s.requiredChanged.length;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return n;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Diff two parsed OpenAPI specs (IR models).
|
|
211
|
+
*
|
|
212
|
+
* @param base - The reference spec (source of truth).
|
|
213
|
+
* @param head - The spec to compare against base.
|
|
214
|
+
* @param options - Filter endpoints, configure behavior.
|
|
215
|
+
*/
|
|
216
|
+
export function diffSpecs(base, head, options) {
|
|
217
|
+
const baseStore = base.components?.schemas ?? {};
|
|
218
|
+
const headStore = head.components?.schemas ?? {};
|
|
219
|
+
const cmp = {
|
|
220
|
+
request: options?.compare?.request !== false,
|
|
221
|
+
response: options?.compare?.response !== false,
|
|
222
|
+
params: options?.compare?.params !== false,
|
|
223
|
+
query: options?.compare?.query !== false,
|
|
224
|
+
headers: options?.compare?.headers !== false,
|
|
225
|
+
cookies: options?.compare?.cookies !== false,
|
|
226
|
+
};
|
|
227
|
+
const baseEps = extractEndpoints(base.paths, options?.filter);
|
|
228
|
+
const headEps = extractEndpoints(head.paths, options?.filter);
|
|
229
|
+
const baseKeys = new Set(baseEps.keys());
|
|
230
|
+
const headKeys = new Set(headEps.keys());
|
|
231
|
+
const shared = [...headKeys].filter((k) => baseKeys.has(k)).sort();
|
|
232
|
+
const onlyInBase = [...baseKeys].filter((k) => !headKeys.has(k)).sort();
|
|
233
|
+
const onlyInHead = [...headKeys].filter((k) => !baseKeys.has(k)).sort();
|
|
234
|
+
const matching = [];
|
|
235
|
+
const diffed = [];
|
|
236
|
+
for (const key of shared) {
|
|
237
|
+
const b = baseEps.get(key);
|
|
238
|
+
const h = headEps.get(key);
|
|
239
|
+
const reqDiff = cmp.request && b.request && h.request
|
|
240
|
+
? diffShapes(collectShape(b.request, baseStore), collectShape(h.request, headStore))
|
|
241
|
+
: null;
|
|
242
|
+
const resDiff = cmp.response && b.response && h.response
|
|
243
|
+
? diffShapes(collectShape(b.response, baseStore), collectShape(h.response, headStore))
|
|
244
|
+
: null;
|
|
245
|
+
const paramsDiff = cmp.params
|
|
246
|
+
? diffShapes(collectParamsShape(b.params, baseStore), collectParamsShape(h.params, headStore))
|
|
247
|
+
: null;
|
|
248
|
+
const queryDiff = cmp.query
|
|
249
|
+
? diffShapes(collectParamsShape(b.query, baseStore), collectParamsShape(h.query, headStore))
|
|
250
|
+
: null;
|
|
251
|
+
const headersDiff = cmp.headers
|
|
252
|
+
? diffShapes(collectParamsShape(b.headers, baseStore), collectParamsShape(h.headers, headStore))
|
|
253
|
+
: null;
|
|
254
|
+
const cookiesDiff = cmp.cookies
|
|
255
|
+
? diffShapes(collectParamsShape(b.cookies, baseStore), collectParamsShape(h.cookies, headStore))
|
|
256
|
+
: null;
|
|
257
|
+
if (reqDiff ||
|
|
258
|
+
resDiff ||
|
|
259
|
+
paramsDiff ||
|
|
260
|
+
queryDiff ||
|
|
261
|
+
headersDiff ||
|
|
262
|
+
cookiesDiff) {
|
|
263
|
+
const [method, ...rest] = key.split(" ");
|
|
264
|
+
diffed.push({
|
|
265
|
+
endpoint: key,
|
|
266
|
+
method: method,
|
|
267
|
+
path: rest.join(" "),
|
|
268
|
+
request: reqDiff,
|
|
269
|
+
response: resDiff,
|
|
270
|
+
params: paramsDiff,
|
|
271
|
+
query: queryDiff,
|
|
272
|
+
headers: headersDiff,
|
|
273
|
+
cookies: cookiesDiff,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
matching.push(key);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return {
|
|
281
|
+
generatedAt: new Date().toISOString(),
|
|
282
|
+
summary: {
|
|
283
|
+
shared: shared.length,
|
|
284
|
+
matching: matching.length,
|
|
285
|
+
differing: diffed.length,
|
|
286
|
+
onlyInBase: onlyInBase.length,
|
|
287
|
+
onlyInHead: onlyInHead.length,
|
|
288
|
+
drifts: countDrifts(diffed),
|
|
289
|
+
},
|
|
290
|
+
matching,
|
|
291
|
+
diffed,
|
|
292
|
+
onlyInBase,
|
|
293
|
+
onlyInHead,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
//# sourceMappingURL=diff.js.map
|
package/dist/diff.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { type DiffOptions, type DiffReport, diffSpecs, type EndpointDiff, type RequiredChange, type ShapeDiff, type TypeChange, } from "./diff.js";
|
|
2
|
+
export { routesFromIR } from "./ir.js";
|
|
3
|
+
export { type LoadSpecOptions, loadSpec, resolveSpecInput, type SpecInput, } from "./load.js";
|
|
4
|
+
export { type ExtractParams, isInSpec, type MatchResult, match, } from "./match.js";
|
|
5
|
+
export type { IR } from "./parse.js";
|
|
6
|
+
export { parseSpec } from "./parse.js";
|
|
7
|
+
export type { Route } from "./route.js";
|
|
8
|
+
export { createRouter, type Router } from "./router.js";
|
|
9
|
+
export { type EnumLiteral, getEnumLiterals, isEnumSchema, isUnionSchema, } from "./schema.js";
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,SAAS,EACT,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,UAAU,GAChB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EACL,KAAK,eAAe,EACpB,QAAQ,EACR,gBAAgB,EAChB,KAAK,SAAS,GACf,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,KAAK,aAAa,EAClB,QAAQ,EACR,KAAK,WAAW,EAChB,KAAK,GACN,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,YAAY,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EACL,KAAK,WAAW,EAChB,eAAe,EACf,YAAY,EACZ,aAAa,GACd,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { diffSpecs, } from "./diff.js";
|
|
2
|
+
export { routesFromIR } from "./ir.js";
|
|
3
|
+
export { loadSpec, resolveSpecInput, } from "./load.js";
|
|
4
|
+
export { isInSpec, match, } from "./match.js";
|
|
5
|
+
export { parseSpec } from "./parse.js";
|
|
6
|
+
export { createRouter } from "./router.js";
|
|
7
|
+
export { getEnumLiterals, isEnumSchema, isUnionSchema, } from "./schema.js";
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,SAAS,GAKV,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAEL,QAAQ,EACR,gBAAgB,GAEjB,MAAM,WAAW,CAAC;AACnB,OAAO,EAEL,QAAQ,EAER,KAAK,GACN,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,OAAO,EAAE,YAAY,EAAe,MAAM,aAAa,CAAC;AACxD,OAAO,EAEL,eAAe,EACf,YAAY,EACZ,aAAa,GACd,MAAM,aAAa,CAAC"}
|
package/dist/ir.d.ts
ADDED
package/dist/ir.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ir.d.ts","sourceRoot":"","sources":["../src/ir.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAE1C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAkBxC,qFAAqF;AACrF,wBAAgB,YAAY,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,GAAG,KAAK,EAAE,CAkBlD"}
|
package/dist/ir.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const HTTP_METHODS = [
|
|
2
|
+
"get",
|
|
3
|
+
"put",
|
|
4
|
+
"post",
|
|
5
|
+
"delete",
|
|
6
|
+
"options",
|
|
7
|
+
"head",
|
|
8
|
+
"patch",
|
|
9
|
+
"trace",
|
|
10
|
+
];
|
|
11
|
+
/** `/users/{id}/posts/{postId}` → `/users/:id/posts/:postId` */
|
|
12
|
+
function specToPattern(spec) {
|
|
13
|
+
return spec.replace(/\{([^}]+)\}/g, ":$1");
|
|
14
|
+
}
|
|
15
|
+
/** Extract `Route[]` from a parsed IR — for runtime-loaded specs without codegen. */
|
|
16
|
+
export function routesFromIR(ir) {
|
|
17
|
+
const out = [];
|
|
18
|
+
const paths = ir.paths ?? {};
|
|
19
|
+
for (const [spec, pathItem] of Object.entries(paths)) {
|
|
20
|
+
if (!pathItem)
|
|
21
|
+
continue;
|
|
22
|
+
for (const method of HTTP_METHODS) {
|
|
23
|
+
const op = pathItem[method];
|
|
24
|
+
if (!op)
|
|
25
|
+
continue;
|
|
26
|
+
out.push({
|
|
27
|
+
spec,
|
|
28
|
+
pattern: specToPattern(spec),
|
|
29
|
+
method,
|
|
30
|
+
operationId: op.operationId,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=ir.js.map
|
package/dist/ir.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ir.js","sourceRoot":"","sources":["../src/ir.ts"],"names":[],"mappings":"AAIA,MAAM,YAAY,GAAG;IACnB,KAAK;IACL,KAAK;IACL,MAAM;IACN,QAAQ;IACR,SAAS;IACT,MAAM;IACN,OAAO;IACP,OAAO;CACC,CAAC;AAEX,gEAAgE;AAChE,SAAS,aAAa,CAAC,IAAY;IACjC,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;AAC7C,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,YAAY,CAAC,EAAY;IACvC,MAAM,GAAG,GAAY,EAAE,CAAC;IACxB,MAAM,KAAK,GACR,EAA0D,CAAC,KAAK,IAAI,EAAE,CAAC;IAC1E,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACrD,IAAI,CAAC,QAAQ;YAAE,SAAS;QACxB,KAAK,MAAM,MAAM,IAAI,YAAY,EAAE,CAAC;YAClC,MAAM,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAyC,CAAC;YACpE,IAAI,CAAC,EAAE;gBAAE,SAAS;YAClB,GAAG,CAAC,IAAI,CAAC;gBACP,IAAI;gBACJ,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC;gBAC5B,MAAM;gBACN,WAAW,EAAE,EAAE,CAAC,WAAW;aAC5B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/dist/load.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type NormalizeOptions } from "@ir-kit/openapi-core";
|
|
2
|
+
export type SpecInput = string | Record<string, unknown>;
|
|
3
|
+
export interface LoadSpecOptions {
|
|
4
|
+
/** File path, URL, or pre-parsed spec object. */
|
|
5
|
+
input: SpecInput;
|
|
6
|
+
/** Working directory used to resolve relative paths. Default: `process.cwd()`. */
|
|
7
|
+
cwd?: string;
|
|
8
|
+
/**
|
|
9
|
+
* Apply normalization after bundling. `true` enables the safe preset
|
|
10
|
+
* shared by every generator; pass an object for custom rules.
|
|
11
|
+
*/
|
|
12
|
+
normalize?: boolean | NormalizeOptions;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Single-source loader for every generator in the workspace.
|
|
16
|
+
* Path-vs-URL detection, `$RefParser.bundle()`, and the optional
|
|
17
|
+
* normalize step all happen here so individual generators stay focused
|
|
18
|
+
* on IR → target conversion.
|
|
19
|
+
*/
|
|
20
|
+
export declare function loadSpec(opts: LoadSpecOptions): Promise<Record<string, unknown>>;
|
|
21
|
+
/**
|
|
22
|
+
* Normalize a spec input string: URLs pass through verbatim, absolute
|
|
23
|
+
* paths pass through, relative paths resolve against `cwd`. Pre-parsed
|
|
24
|
+
* objects are returned as-is.
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveSpecInput(input: SpecInput, cwd?: string): SpecInput;
|
|
27
|
+
//# sourceMappingURL=load.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../src/load.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,gBAAgB,EAGtB,MAAM,sBAAsB,CAAC;AAE9B,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEzD,MAAM,WAAW,eAAe;IAC9B,iDAAiD;IACjD,KAAK,EAAE,SAAS,CAAC;IACjB,kFAAkF;IAClF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,gBAAgB,CAAC;CACxC;AAED;;;;;GAKG;AACH,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAclC;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,SAAS,EAChB,GAAG,GAAE,MAAsB,GAC1B,SAAS,CASX"}
|
package/dist/load.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { isAbsolute, resolve } from "node:path";
|
|
2
|
+
import { $RefParser } from "@hey-api/json-schema-ref-parser";
|
|
3
|
+
import { normalizeSpec, SAFE_NORMALIZE, } from "@ir-kit/openapi-core";
|
|
4
|
+
/**
|
|
5
|
+
* Single-source loader for every generator in the workspace.
|
|
6
|
+
* Path-vs-URL detection, `$RefParser.bundle()`, and the optional
|
|
7
|
+
* normalize step all happen here so individual generators stay focused
|
|
8
|
+
* on IR → target conversion.
|
|
9
|
+
*/
|
|
10
|
+
export async function loadSpec(opts) {
|
|
11
|
+
const parser = new $RefParser();
|
|
12
|
+
const bundled = (await parser.bundle({
|
|
13
|
+
pathOrUrlOrSchema: resolveSpecInput(opts.input, opts.cwd),
|
|
14
|
+
}));
|
|
15
|
+
if (opts.normalize) {
|
|
16
|
+
normalizeSpec(bundled, opts.normalize === true ? SAFE_NORMALIZE : opts.normalize);
|
|
17
|
+
}
|
|
18
|
+
return bundled;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Normalize a spec input string: URLs pass through verbatim, absolute
|
|
22
|
+
* paths pass through, relative paths resolve against `cwd`. Pre-parsed
|
|
23
|
+
* objects are returned as-is.
|
|
24
|
+
*/
|
|
25
|
+
export function resolveSpecInput(input, cwd = process.cwd()) {
|
|
26
|
+
if (typeof input !== "string")
|
|
27
|
+
return input;
|
|
28
|
+
const trimmed = input.trim();
|
|
29
|
+
if (trimmed === "") {
|
|
30
|
+
throw new Error("OpenAPI spec input is empty or only whitespace.");
|
|
31
|
+
}
|
|
32
|
+
if (/^https?:\/\//i.test(trimmed))
|
|
33
|
+
return trimmed;
|
|
34
|
+
if (isAbsolute(trimmed))
|
|
35
|
+
return trimmed;
|
|
36
|
+
return resolve(cwd, trimmed);
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=load.js.map
|
package/dist/load.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load.js","sourceRoot":"","sources":["../src/load.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAC7D,OAAO,EAEL,aAAa,EACb,cAAc,GACf,MAAM,sBAAsB,CAAC;AAgB9B;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,IAAqB;IAErB,MAAM,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;IAChC,MAAM,OAAO,GAAG,CAAC,MAAM,MAAM,CAAC,MAAM,CAAC;QACnC,iBAAiB,EAAE,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC;KAC1D,CAAC,CAA4B,CAAC;IAE/B,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,aAAa,CACX,OAAO,EACP,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAC1D,CAAC;IACJ,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAC9B,KAAgB,EAChB,MAAc,OAAO,CAAC,GAAG,EAAE;IAE3B,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IACD,IAAI,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAC;IAClD,IAAI,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAC;IACxC,OAAO,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AAC/B,CAAC"}
|
package/dist/match.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Route } from "./route.js";
|
|
2
|
+
/** `/users/{id}/posts/{postId}` → `{ id: string; postId: string }` (URL params are always strings). */
|
|
3
|
+
export type ExtractParams<P extends string> = P extends `${string}{${infer Key}}${infer Rest}` ? {
|
|
4
|
+
[K in Key | keyof ExtractParams<Rest>]: string;
|
|
5
|
+
} : Record<string, never>;
|
|
6
|
+
/** Discriminated union; narrow on `spec` + `method` for typed `params`. */
|
|
7
|
+
export type MatchResult<TRoute extends Route = Route> = TRoute extends Route ? {
|
|
8
|
+
spec: TRoute["spec"];
|
|
9
|
+
method: TRoute["method"];
|
|
10
|
+
params: ExtractParams<TRoute["spec"]>;
|
|
11
|
+
operationId: TRoute extends {
|
|
12
|
+
operationId: infer O;
|
|
13
|
+
} ? O : undefined;
|
|
14
|
+
} : never;
|
|
15
|
+
/** Match a request against routes. Returns `MatchResult<R>` discriminated union or `null`. */
|
|
16
|
+
export declare function match<R extends Route>(routes: readonly R[], request: Request): MatchResult<R> | null;
|
|
17
|
+
/** Boolean: does this request hit any route? */
|
|
18
|
+
export declare function isInSpec(routes: readonly Route[], request: Request): boolean;
|
|
19
|
+
export type { Route };
|
|
20
|
+
//# sourceMappingURL=match.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"match.d.ts","sourceRoot":"","sources":["../src/match.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,uGAAuG;AACvG,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,MAAM,IACxC,CAAC,SAAS,GAAG,MAAM,IAAI,MAAM,GAAG,IAAI,MAAM,IAAI,EAAE,GAC5C;KAAG,CAAC,IAAI,GAAG,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,GAAG,MAAM;CAAE,GAClD,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAE5B,2EAA2E;AAC3E,MAAM,MAAM,WAAW,CAAC,MAAM,SAAS,KAAK,GAAG,KAAK,IAAI,MAAM,SAAS,KAAK,GACxE;IACE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IACzB,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IACtC,WAAW,EAAE,MAAM,SAAS;QAAE,WAAW,EAAE,MAAM,CAAC,CAAA;KAAE,GAAG,CAAC,GAAG,SAAS,CAAC;CACtE,GACD,KAAK,CAAC;AA+BV,8FAA8F;AAC9F,wBAAgB,KAAK,CAAC,CAAC,SAAS,KAAK,EACnC,MAAM,EAAE,SAAS,CAAC,EAAE,EACpB,OAAO,EAAE,OAAO,GACf,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI,CAmBvB;AAED,gDAAgD;AAChD,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAQ5E;AAED,YAAY,EAAE,KAAK,EAAE,CAAC"}
|