shokupan 0.13.0 → 0.14.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/dist/{analyzer-BOtveWL-.cjs → analyzer-BZSVGTmP.cjs} +5 -4
- package/dist/analyzer-BZSVGTmP.cjs.map +1 -0
- package/dist/{analyzer-B0fMzeIo.js → analyzer-Faojwm7c.js} +5 -4
- package/dist/analyzer-Faojwm7c.js.map +1 -0
- package/dist/{analyzer.impl-CUDO6vpn.cjs → analyzer.impl-5aCqtook.cjs} +28 -11
- package/dist/analyzer.impl-5aCqtook.cjs.map +1 -0
- package/dist/{analyzer.impl-DmHe92Oi.js → analyzer.impl-COdN69gL.js} +28 -11
- package/dist/analyzer.impl-COdN69gL.js.map +1 -0
- package/dist/ast-analyzer-worker-C3jrQ8VR.js +184 -0
- package/dist/ast-analyzer-worker-C3jrQ8VR.js.map +1 -0
- package/dist/ast-analyzer-worker-D_uYkqmY.cjs +184 -0
- package/dist/ast-analyzer-worker-D_uYkqmY.cjs.map +1 -0
- package/dist/cli.cjs +1 -1
- package/dist/cli.js +1 -1
- package/dist/context.d.ts +39 -4
- package/dist/decorators/di.d.ts +31 -0
- package/dist/decorators/hooks.d.ts +28 -0
- package/dist/decorators/http.d.ts +60 -0
- package/dist/decorators/index.d.ts +8 -0
- package/dist/decorators/mcp.d.ts +48 -0
- package/dist/decorators/util/container.d.ts +36 -0
- package/dist/decorators/websocket.d.ts +172 -0
- package/dist/index-BP7v0Hiv.cjs +12216 -0
- package/dist/index-BP7v0Hiv.cjs.map +1 -0
- package/dist/index-CUNBeZKj.js +12176 -0
- package/dist/index-CUNBeZKj.js.map +1 -0
- package/dist/index.cjs +137 -10518
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.js +137 -10477
- package/dist/index.js.map +1 -1
- package/dist/{json-parser-COdZ0fqY.cjs → json-parser-BA0mUgMF.cjs} +3 -3
- package/dist/json-parser-BA0mUgMF.cjs.map +1 -0
- package/dist/{json-parser-B3dnQmCC.js → json-parser-BFM-SnBR.js} +3 -3
- package/dist/json-parser-BFM-SnBR.js.map +1 -0
- package/dist/knex-DDPXR-sQ.js +218 -0
- package/dist/knex-DDPXR-sQ.js.map +1 -0
- package/dist/knex-DghF-jjm.cjs +240 -0
- package/dist/knex-DghF-jjm.cjs.map +1 -0
- package/dist/level-BU87Jbus.js +184 -0
- package/dist/level-BU87Jbus.js.map +1 -0
- package/dist/level-DNFl2n-m.cjs +184 -0
- package/dist/level-DNFl2n-m.cjs.map +1 -0
- package/dist/plugins/application/api-explorer/static/explorer-client.mjs +54 -28
- package/dist/plugins/application/asyncapi/plugin.d.ts +1 -0
- package/dist/plugins/application/asyncapi/static/asyncapi-client.mjs +22 -11
- package/dist/plugins/application/dashboard/fetch-interceptor.d.ts +3 -1
- package/dist/plugins/application/dashboard/metrics-collector.d.ts +5 -3
- package/dist/plugins/application/dashboard/plugin.d.ts +36 -3
- package/dist/plugins/application/dashboard/static/requests.js +517 -53
- package/dist/plugins/application/dashboard/static/tabs.js +2 -2
- package/dist/plugins/application/error-view/index.d.ts +25 -0
- package/dist/plugins/application/error-view/reason-phrases.d.ts +1 -0
- package/dist/plugins/application/openapi/analyzer.d.ts +3 -1
- package/dist/plugins/application/openapi/analyzer.impl.d.ts +4 -2
- package/dist/router.d.ts +56 -21
- package/dist/shokupan.d.ts +25 -11
- package/dist/sqlite-CLrcTkti.js +180 -0
- package/dist/sqlite-CLrcTkti.js.map +1 -0
- package/dist/sqlite-n7FQ6Ja6.cjs +180 -0
- package/dist/sqlite-n7FQ6Ja6.cjs.map +1 -0
- package/dist/surreal-6QONU6xa.cjs +210 -0
- package/dist/surreal-6QONU6xa.cjs.map +1 -0
- package/dist/surreal-w7DeGVI-.js +188 -0
- package/dist/surreal-w7DeGVI-.js.map +1 -0
- package/dist/util/adapter/datastore/knex.d.ts +29 -0
- package/dist/util/adapter/datastore/level.d.ts +26 -0
- package/dist/util/adapter/datastore/sqlite.d.ts +24 -0
- package/dist/util/adapter/datastore/surreal.d.ts +29 -0
- package/dist/util/adapter/datastore.d.ts +59 -0
- package/dist/util/adapter/h3.d.ts +8 -0
- package/dist/util/adapter/index.d.ts +1 -0
- package/dist/util/ast-analyzer-worker.d.ts +77 -0
- package/dist/util/ast-worker-thread.d.ts +1 -0
- package/dist/util/cookie-parser.d.ts +6 -0
- package/dist/util/env-loader.d.ts +7 -0
- package/dist/util/html.d.ts +15 -0
- package/dist/util/ide.d.ts +9 -0
- package/dist/util/logger.d.ts +25 -0
- package/dist/util/query-string.d.ts +8 -0
- package/dist/util/response-transformer.d.ts +87 -0
- package/dist/util/symbol.d.ts +1 -0
- package/dist/util/types.d.ts +116 -42
- package/dist/websocket.d.ts +163 -0
- package/package.json +27 -1
- package/dist/analyzer-B0fMzeIo.js.map +0 -1
- package/dist/analyzer-BOtveWL-.cjs.map +0 -1
- package/dist/analyzer.impl-CUDO6vpn.cjs.map +0 -1
- package/dist/analyzer.impl-DmHe92Oi.js.map +0 -1
- package/dist/json-parser-B3dnQmCC.js.map +0 -1
- package/dist/json-parser-COdZ0fqY.cjs.map +0 -1
- package/dist/plugins/application/error-view/views/error.d.ts +0 -2
- package/dist/plugins/application/error-view/views/status.d.ts +0 -2
- package/dist/util/decorators.d.ts +0 -134
- package/dist/util/di.d.ts +0 -13
- /package/dist/{util → decorators/util}/metadata.d.ts +0 -0
- /package/dist/{util → decorators/util}/stack.d.ts +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
class OpenAPIAnalyzer {
|
|
4
|
-
constructor(rootDir, entrypoint) {
|
|
4
|
+
constructor(rootDir, entrypoint, logger) {
|
|
5
5
|
this.rootDir = rootDir;
|
|
6
6
|
this.entrypoint = entrypoint;
|
|
7
|
+
this.logger = logger;
|
|
7
8
|
}
|
|
8
9
|
analyzerImpl;
|
|
9
10
|
/**
|
|
@@ -11,8 +12,8 @@ class OpenAPIAnalyzer {
|
|
|
11
12
|
* Dynamically imports the implementation and runs the analysis.
|
|
12
13
|
*/
|
|
13
14
|
async analyze() {
|
|
14
|
-
const { OpenAPIAnalyzer: AnalyzerImpl } = await Promise.resolve().then(() => require("./analyzer.impl-
|
|
15
|
-
this.analyzerImpl = new AnalyzerImpl(this.rootDir, this.entrypoint);
|
|
15
|
+
const { OpenAPIAnalyzer: AnalyzerImpl } = await Promise.resolve().then(() => require("./analyzer.impl-5aCqtook.cjs"));
|
|
16
|
+
this.analyzerImpl = new AnalyzerImpl(this.rootDir, this.entrypoint, this.logger);
|
|
16
17
|
return this.analyzerImpl.analyze();
|
|
17
18
|
}
|
|
18
19
|
/**
|
|
@@ -27,4 +28,4 @@ class OpenAPIAnalyzer {
|
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
exports.OpenAPIAnalyzer = OpenAPIAnalyzer;
|
|
30
|
-
//# sourceMappingURL=analyzer-
|
|
31
|
+
//# sourceMappingURL=analyzer-BZSVGTmP.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyzer-BZSVGTmP.cjs","sources":["../src/plugins/application/openapi/analyzer.ts"],"sourcesContent":["\n// Re-export types used in public API\nexport type { ApplicationInstance, RouteInfo } from './analyzer.impl';\nimport type { Logger } from '../../../util/logger';\nimport type { ApplicationInstance } from './analyzer.impl';\n\n/**\n * OpenAPI Analyzer Wrapper.\n * \n * This class wraps the actual OpenAPIAnalyzer implementation to facilitate\n * lazy loading of the 'typescript' peer dependency. The actual implementation\n * and the 'typescript' module are only loaded when `analyze()` is called.\n */\nexport class OpenAPIAnalyzer {\n private analyzerImpl: any;\n\n constructor(private rootDir: string, private entrypoint?: string, private logger?: Logger) { }\n\n /**\n * Main analysis entry point.\n * Dynamically imports the implementation and runs the analysis.\n */\n public async analyze(): Promise<{ applications: ApplicationInstance[]; }> {\n // Dynamic import to avoid loading 'typescript' peer dependency if not needed (e.g. at runtime)\n const { OpenAPIAnalyzer: AnalyzerImpl } = await import('./analyzer.impl');\n this.analyzerImpl = new AnalyzerImpl(this.rootDir, this.entrypoint, this.logger);\n return this.analyzerImpl.analyze();\n }\n\n /**\n * Generate OpenAPI specification.\n * Must be called after analyze().\n */\n public generateOpenAPISpec(): any {\n if (!this.analyzerImpl) {\n throw new Error('Must call analyze() before generateOpenAPISpec()');\n }\n return this.analyzerImpl.generateOpenAPISpec();\n }\n}\n\n/**\n * Analyze a directory and generate OpenAPI spec\n */\nexport async function analyzeDirectory(directory: string): Promise<any> {\n const analyzer = new OpenAPIAnalyzer(directory, undefined, undefined);\n return await analyzer.analyze();\n}\n"],"names":[],"mappings":";;AAaO,MAAM,gBAAgB;AAAA,EAGzB,YAAoB,SAAyB,YAA6B,QAAiB;AAAvE,SAAA,UAAA;AAAyB,SAAA,aAAA;AAA6B,SAAA,SAAA;AAAA,EAAmB;AAAA,EAFrF;AAAA;AAAA;AAAA;AAAA;AAAA,EAQR,MAAa,UAA6D;AAEtE,UAAM,EAAE,iBAAiB,iBAAiB,MAAM,QAAA,QAAA,EAAA,KAAA,MAAA,QAAO,8BAAiB,CAAA;AACxE,SAAK,eAAe,IAAI,aAAa,KAAK,SAAS,KAAK,YAAY,KAAK,MAAM;AAC/E,WAAO,KAAK,aAAa,QAAA;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,sBAA2B;AAC9B,QAAI,CAAC,KAAK,cAAc;AACpB,YAAM,IAAI,MAAM,kDAAkD;AAAA,IACtE;AACA,WAAO,KAAK,aAAa,oBAAA;AAAA,EAC7B;AACJ;;"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
class OpenAPIAnalyzer {
|
|
2
|
-
constructor(rootDir, entrypoint) {
|
|
2
|
+
constructor(rootDir, entrypoint, logger) {
|
|
3
3
|
this.rootDir = rootDir;
|
|
4
4
|
this.entrypoint = entrypoint;
|
|
5
|
+
this.logger = logger;
|
|
5
6
|
}
|
|
6
7
|
analyzerImpl;
|
|
7
8
|
/**
|
|
@@ -9,8 +10,8 @@ class OpenAPIAnalyzer {
|
|
|
9
10
|
* Dynamically imports the implementation and runs the analysis.
|
|
10
11
|
*/
|
|
11
12
|
async analyze() {
|
|
12
|
-
const { OpenAPIAnalyzer: AnalyzerImpl } = await import("./analyzer.impl-
|
|
13
|
-
this.analyzerImpl = new AnalyzerImpl(this.rootDir, this.entrypoint);
|
|
13
|
+
const { OpenAPIAnalyzer: AnalyzerImpl } = await import("./analyzer.impl-COdN69gL.js");
|
|
14
|
+
this.analyzerImpl = new AnalyzerImpl(this.rootDir, this.entrypoint, this.logger);
|
|
14
15
|
return this.analyzerImpl.analyze();
|
|
15
16
|
}
|
|
16
17
|
/**
|
|
@@ -27,4 +28,4 @@ class OpenAPIAnalyzer {
|
|
|
27
28
|
export {
|
|
28
29
|
OpenAPIAnalyzer
|
|
29
30
|
};
|
|
30
|
-
//# sourceMappingURL=analyzer-
|
|
31
|
+
//# sourceMappingURL=analyzer-Faojwm7c.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyzer-Faojwm7c.js","sources":["../src/plugins/application/openapi/analyzer.ts"],"sourcesContent":["\n// Re-export types used in public API\nexport type { ApplicationInstance, RouteInfo } from './analyzer.impl';\nimport type { Logger } from '../../../util/logger';\nimport type { ApplicationInstance } from './analyzer.impl';\n\n/**\n * OpenAPI Analyzer Wrapper.\n * \n * This class wraps the actual OpenAPIAnalyzer implementation to facilitate\n * lazy loading of the 'typescript' peer dependency. The actual implementation\n * and the 'typescript' module are only loaded when `analyze()` is called.\n */\nexport class OpenAPIAnalyzer {\n private analyzerImpl: any;\n\n constructor(private rootDir: string, private entrypoint?: string, private logger?: Logger) { }\n\n /**\n * Main analysis entry point.\n * Dynamically imports the implementation and runs the analysis.\n */\n public async analyze(): Promise<{ applications: ApplicationInstance[]; }> {\n // Dynamic import to avoid loading 'typescript' peer dependency if not needed (e.g. at runtime)\n const { OpenAPIAnalyzer: AnalyzerImpl } = await import('./analyzer.impl');\n this.analyzerImpl = new AnalyzerImpl(this.rootDir, this.entrypoint, this.logger);\n return this.analyzerImpl.analyze();\n }\n\n /**\n * Generate OpenAPI specification.\n * Must be called after analyze().\n */\n public generateOpenAPISpec(): any {\n if (!this.analyzerImpl) {\n throw new Error('Must call analyze() before generateOpenAPISpec()');\n }\n return this.analyzerImpl.generateOpenAPISpec();\n }\n}\n\n/**\n * Analyze a directory and generate OpenAPI spec\n */\nexport async function analyzeDirectory(directory: string): Promise<any> {\n const analyzer = new OpenAPIAnalyzer(directory, undefined, undefined);\n return await analyzer.analyze();\n}\n"],"names":[],"mappings":"AAaO,MAAM,gBAAgB;AAAA,EAGzB,YAAoB,SAAyB,YAA6B,QAAiB;AAAvE,SAAA,UAAA;AAAyB,SAAA,aAAA;AAA6B,SAAA,SAAA;AAAA,EAAmB;AAAA,EAFrF;AAAA;AAAA;AAAA;AAAA;AAAA,EAQR,MAAa,UAA6D;AAEtE,UAAM,EAAE,iBAAiB,iBAAiB,MAAM,OAAO,6BAAiB;AACxE,SAAK,eAAe,IAAI,aAAa,KAAK,SAAS,KAAK,YAAY,KAAK,MAAM;AAC/E,WAAO,KAAK,aAAa,QAAA;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,sBAA2B;AAC9B,QAAI,CAAC,KAAK,cAAc;AACpB,YAAM,IAAI,MAAM,kDAAkD;AAAA,IACtE;AACA,WAAO,KAAK,aAAa,oBAAA;AAAA,EAC7B;AACJ;"}
|
|
@@ -4,8 +4,9 @@ const fs = require("node:fs");
|
|
|
4
4
|
const path = require("node:path");
|
|
5
5
|
const ts = require("typescript");
|
|
6
6
|
class OpenAPIAnalyzer {
|
|
7
|
-
constructor(rootDir, entrypoint) {
|
|
7
|
+
constructor(rootDir, entrypoint, logger) {
|
|
8
8
|
this.rootDir = rootDir;
|
|
9
|
+
this.logger = logger;
|
|
9
10
|
if (entrypoint) {
|
|
10
11
|
this.entrypoint = path.resolve(entrypoint);
|
|
11
12
|
}
|
|
@@ -66,6 +67,10 @@ class OpenAPIAnalyzer {
|
|
|
66
67
|
this.applications.length;
|
|
67
68
|
this.applications = this.applications.filter((app) => {
|
|
68
69
|
if (app.name === "GenericModule" && !reachable.has(app.filePath)) {
|
|
70
|
+
const isTest = app.filePath.includes(".spec.ts") || app.filePath.includes(".test.ts") || app.filePath.includes("/fixtures/");
|
|
71
|
+
if (isTest) {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
69
74
|
return false;
|
|
70
75
|
}
|
|
71
76
|
return true;
|
|
@@ -108,7 +113,7 @@ class OpenAPIAnalyzer {
|
|
|
108
113
|
const jsFile = jsFiles[i];
|
|
109
114
|
const mapFile = mapFiles.find((m) => m.path === jsFile.path + ".map");
|
|
110
115
|
if (mapFile && !this.files.some((f) => f.path === jsFile.path.replace(/\.js$/, ".ts"))) {
|
|
111
|
-
|
|
116
|
+
this.logger?.debug("OpenAPIAnalyzer", `Note: Found ${jsFile.path} with source map but no .ts file. Will parse JS directly.`);
|
|
112
117
|
}
|
|
113
118
|
}
|
|
114
119
|
}
|
|
@@ -168,7 +173,7 @@ class OpenAPIAnalyzer {
|
|
|
168
173
|
moduleResolution: ts.ModuleResolutionKind.Node10,
|
|
169
174
|
rootDir: this.rootDir,
|
|
170
175
|
skipLibCheck: true,
|
|
171
|
-
skipDefaultLibCheck:
|
|
176
|
+
skipDefaultLibCheck: false
|
|
172
177
|
});
|
|
173
178
|
if (this.entrypoint) {
|
|
174
179
|
this.files = this.program.getSourceFiles().filter((sf) => !sf.fileName.includes("node_modules")).map((sf) => ({ path: sf.fileName, type: sf.fileName.endsWith(".js") ? "js" : "ts" }));
|
|
@@ -262,7 +267,7 @@ class OpenAPIAnalyzer {
|
|
|
262
267
|
if (ts.isNewExpression(node.initializer)) {
|
|
263
268
|
const expr = node.initializer;
|
|
264
269
|
const className = expr.expression.getText(sourceFile);
|
|
265
|
-
if (className === "Shokupan" || className === "ShokupanRouter") {
|
|
270
|
+
if (className === "Shokupan" || className === "ShokupanRouter" || className === "ShokupanWebsocketRouter") {
|
|
266
271
|
const varName = node.name.getText(sourceFile);
|
|
267
272
|
this.applications.push({
|
|
268
273
|
name: varName,
|
|
@@ -337,7 +342,7 @@ class OpenAPIAnalyzer {
|
|
|
337
342
|
}
|
|
338
343
|
routePath = routePath.replace(/:([a-zA-Z0-9_]+)/g, "{$1}");
|
|
339
344
|
const handlerName = `${app.name}.${methodNode.name.getText(sourceFile)}`;
|
|
340
|
-
const analysis = this.analyzeHandler(methodNode, sourceFile);
|
|
345
|
+
const analysis = this.analyzeHandler(methodNode, sourceFile, httpMethod);
|
|
341
346
|
app.routes.push({
|
|
342
347
|
method: httpMethod,
|
|
343
348
|
path: routePath,
|
|
@@ -486,7 +491,7 @@ class OpenAPIAnalyzer {
|
|
|
486
491
|
}
|
|
487
492
|
}
|
|
488
493
|
const handlerArg = args[args.length - 1];
|
|
489
|
-
const handlerInfo = this.analyzeHandler(handlerArg, sourceFile);
|
|
494
|
+
const handlerInfo = this.analyzeHandler(handlerArg, sourceFile, method);
|
|
490
495
|
return {
|
|
491
496
|
method,
|
|
492
497
|
path: normalizedPath,
|
|
@@ -509,7 +514,7 @@ class OpenAPIAnalyzer {
|
|
|
509
514
|
/**
|
|
510
515
|
* Analyze a route handler to extract type information
|
|
511
516
|
*/
|
|
512
|
-
analyzeHandler(handler, sourceFile) {
|
|
517
|
+
analyzeHandler(handler, sourceFile, method) {
|
|
513
518
|
const typeChecker = this.program?.getTypeChecker();
|
|
514
519
|
const requestTypes = {};
|
|
515
520
|
let responseType;
|
|
@@ -519,12 +524,15 @@ class OpenAPIAnalyzer {
|
|
|
519
524
|
const highlights = [];
|
|
520
525
|
const scope = /* @__PURE__ */ new Map();
|
|
521
526
|
if (ts.isFunctionLike(handler)) {
|
|
522
|
-
handler.parameters.forEach((param) => {
|
|
527
|
+
handler.parameters.forEach((param, index) => {
|
|
523
528
|
if (ts.isIdentifier(param.name) && param.type) {
|
|
524
529
|
const paramName = param.name.getText(sourceFile);
|
|
525
530
|
const paramType = this.convertTypeNodeToSchema(param.type, sourceFile);
|
|
526
531
|
if (paramType) {
|
|
527
532
|
scope.set(paramName, paramType);
|
|
533
|
+
if ((method === "EVENT" || method === "ON") && index === 1) {
|
|
534
|
+
requestTypes.body = paramType;
|
|
535
|
+
}
|
|
528
536
|
}
|
|
529
537
|
}
|
|
530
538
|
});
|
|
@@ -657,6 +665,10 @@ class OpenAPIAnalyzer {
|
|
|
657
665
|
}
|
|
658
666
|
}
|
|
659
667
|
}
|
|
668
|
+
} else if (this.isCtxBodyCall(node, sourceFile)) {
|
|
669
|
+
if (!requestTypes.body) {
|
|
670
|
+
requestTypes.body = { type: "object", description: "Request Body" };
|
|
671
|
+
}
|
|
660
672
|
}
|
|
661
673
|
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression)) {
|
|
662
674
|
const objText = node.expression.expression.getText(sourceFile);
|
|
@@ -804,7 +816,12 @@ class OpenAPIAnalyzer {
|
|
|
804
816
|
if (ts.isStringLiteral(eventNameArg)) {
|
|
805
817
|
const eventName = eventNameArg.text;
|
|
806
818
|
let payload = { type: "object" };
|
|
807
|
-
if (expr.arguments
|
|
819
|
+
if (this.isCtxBodyCall(expr.arguments[1], sourceFile)) {
|
|
820
|
+
payload = { type: "object", description: "Request Body" };
|
|
821
|
+
if (!requestTypes.body) {
|
|
822
|
+
requestTypes.body = { type: "object" };
|
|
823
|
+
}
|
|
824
|
+
} else {
|
|
808
825
|
payload = this.convertExpressionToSchema(expr.arguments[1], sourceFile, scope, typeChecker);
|
|
809
826
|
}
|
|
810
827
|
const emitLoc = {
|
|
@@ -952,7 +969,7 @@ class OpenAPIAnalyzer {
|
|
|
952
969
|
return { type: "number" };
|
|
953
970
|
}
|
|
954
971
|
}
|
|
955
|
-
if (ts.isPropertyAccessExpression(node) && typeChecker) {
|
|
972
|
+
if ((ts.isPropertyAccessExpression(node) || ts.isElementAccessExpression(node)) && typeChecker) {
|
|
956
973
|
try {
|
|
957
974
|
const type = typeChecker.getTypeAtLocation(node);
|
|
958
975
|
const schema = this.convertTypeToSchema(type, typeChecker);
|
|
@@ -1626,4 +1643,4 @@ class OpenAPIAnalyzer {
|
|
|
1626
1643
|
}
|
|
1627
1644
|
}
|
|
1628
1645
|
exports.OpenAPIAnalyzer = OpenAPIAnalyzer;
|
|
1629
|
-
//# sourceMappingURL=analyzer.impl-
|
|
1646
|
+
//# sourceMappingURL=analyzer.impl-5aCqtook.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyzer.impl-5aCqtook.cjs","sources":["../src/plugins/application/openapi/analyzer.impl.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport ts from 'typescript';\nimport type { Logger } from '../../../util/logger';\n\n/**\n * File information collected during scan\n */\ninterface CollectedFile {\n path: string;\n type: 'ts' | 'tsx' | 'cts' | 'dts' | 'mts' | 'js' | 'jsx' | 'mjs' | 'cjs' | 'map';\n content?: string;\n}\n\n/**\n * Route information extracted from AST\n */\nexport interface RouteInfo {\n method: string;\n path: string;\n handlerName?: string;\n handlerSource?: string;\n requestTypes?: {\n body?: any;\n query?: Record<string, string>;\n params?: Record<string, string>;\n headers?: Record<string, string>;\n };\n responseType?: string;\n responseSchema?: any;\n hasUnknownFields?: boolean;\n summary?: string;\n description?: string;\n tags?: string[];\n operationId?: string;\n emits?: { event: string; payload?: any; location?: { startLine: number; endLine: number; }; }[];\n sourceContext?: {\n file: string;\n startLine: number;\n endLine: number;\n highlights?: { startLine: number; endLine: number; type: 'emit' | 'return-success' | 'return-warning' | 'dynamic-path'; }[];\n };\n}\n\n/**\n * Dependency information\n */\ninterface DependencyInfo {\n packageName: string;\n version?: string;\n importPath: string;\n isExternal: boolean;\n}\n\n/**\n * Application/Router instance found in code\n */\nexport interface ApplicationInstance {\n name: string;\n filePath: string;\n className: 'Shokupan' | 'ShokupanRouter' | 'Controller' | 'ShokupanWebsocketRouter';\n controllerPrefix?: string;\n routes: RouteInfo[];\n mounted: MountInfo[];\n middleware: MiddlewareInfo[]; // Middleware registered on this app/router\n}\n\ninterface MountInfo {\n prefix: string;\n target: string; // Controller/Router name or file path\n targetFilePath?: string;\n dependency?: DependencyInfo;\n sourceContext?: {\n file: string;\n startLine: number;\n endLine: number;\n };\n}\n\n/**\n * Middleware information extracted from AST\n */\nexport interface MiddlewareInfo {\n name: string;\n file: string;\n startLine: number;\n endLine: number;\n handlerSource?: string;\n responseTypes?: Record<string, any>; // e.g., { \"401\": { description: \"...\", content: {...} }, \"403\": {...} }\n headers?: string[]; // Headers set/modified by middleware\n scope: 'global' | 'router' | 'route';\n sourceContext?: {\n file: string;\n startLine: number;\n endLine: number;\n snippet?: string;\n snippetStartLine?: number;\n highlights?: { startLine: number; endLine: number; type: 'emit' | 'return-success' | 'return-warning'; }[];\n };\n}\n\n\n/**\n * Main analyzer class\n */\nexport class OpenAPIAnalyzer {\n private files: CollectedFile[] = [];\n private applications: ApplicationInstance[] = [];\n private program?: ts.Program;\n private entrypoint?: string;\n // Track imports per file: filePath -> { importedName -> { modulePath, exportName } }\n private imports: Map<string, Map<string, { modulePath: string; exportName?: string; }>> = new Map();\n\n constructor(private rootDir: string, entrypoint?: string, private logger?: Logger) {\n if (entrypoint) {\n this.entrypoint = path.resolve(entrypoint);\n }\n }\n\n /**\n * Main analysis entry point\n */\n /**\n * Main analysis entry point\n */\n private cachedResult?: { applications: ApplicationInstance[]; };\n\n /**\n * Main analysis entry point\n */\n public async analyze(): Promise<{ applications: ApplicationInstance[]; }> {\n if (this.cachedResult) {\n return this.cachedResult;\n }\n\n // console.log(`Analyzing directory: ${this.rootDir}`);\n\n // Step 1: Parse TypeScript files (which might involve scanning or using entrypoint)\n await this.parseTypeScriptFiles();\n\n // Step 2: Process source maps if needed\n await this.processSourceMaps();\n\n // Step 3: Collect imports from all files\n await this.collectImports();\n\n // Step 4: Find Shokupan applications\n await this.findApplications();\n\n // Step 5: Extract route information\n await this.extractRoutes();\n\n // Step 6: Prune unreachable GenericModules\n this.pruneApplications();\n\n this.cachedResult = { applications: this.applications };\n\n // Return the raw application data for further processing\n return this.cachedResult;\n }\n\n /**\n * Remove GenericModules that are not mounted by any Shokupan application/router\n */\n private pruneApplications(): void {\n const reachable = new Set<string>();\n const queue: ApplicationInstance[] = [];\n\n // Seed with explicit applications (Shokupan, ShokupanRouter, Controller)\n for (const app of this.applications) {\n if (app.name !== 'GenericModule') {\n reachable.add(app.filePath);\n queue.push(app);\n }\n }\n\n // BFS to find all reachable modules via mounts\n while (queue.length > 0) {\n const app = queue.shift()!;\n\n for (const mount of app.mounted) {\n if (mount.targetFilePath && !reachable.has(mount.targetFilePath)) {\n reachable.add(mount.targetFilePath);\n\n // Find the app instance for this file\n const mountedApp = this.applications.find(a => a.filePath === mount.targetFilePath);\n if (mountedApp) {\n queue.push(mountedApp);\n }\n }\n }\n }\n\n // Filter out unreachable GenericModules\n const initialCount = this.applications.length;\n this.applications = this.applications.filter(app => {\n if (app.name === 'GenericModule' && !reachable.has(app.filePath)) {\n // EXEMPTION: If file is likely a test or fixture, keep it.\n // This allows testing generated routes without mounting them to a main app\n const isTest = app.filePath.includes('.spec.ts') || app.filePath.includes('.test.ts') || app.filePath.includes('/fixtures/');\n if (isTest) {\n return true;\n }\n\n // console.log(`[Analyzer] Pruning unreachable module: ${app.filePath}`);\n return false;\n }\n return true;\n });\n\n // console.log(`[Analyzer] Pruned ${initialCount - this.applications.length} unreachable modules.`);\n }\n\n /**\n * Recursively scan directory for TypeScript/JavaScript files\n */\n private async scanDirectory(dir: string): Promise<void> {\n try {\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n const fullPath = path.join(dir, entry.name);\n\n // Skip node_modules for source files (we'll handle deps separately)\n if (entry.isDirectory()) {\n if ([\"node_modules\", \".git\", \"dist\", \".gemini\", \".vscode\", \".agent\", \"artifacts\"].includes(entry.name)) {\n continue;\n }\n await this.scanDirectory(fullPath);\n } else {\n const ext = path.extname(entry.name);\n if ([\".ts\", \".tsx\", \".cts\", \".dts\", \".mts\", \".js\", \".jsx\", \".mjs\", \".cjs\", \".map\"].includes(ext)) {\n this.files.push({ path: fullPath, type: ext.slice(1) as any });\n }\n }\n }\n } catch (error: any) {\n // Silently skip directories that don't exist or can't be read\n if (error.code !== 'ENOENT' && error.code !== 'EACCES') {\n throw error;\n }\n }\n }\n\n /**\n * Process source maps to reconstruct TypeScript\n */\n private async processSourceMaps(): Promise<void> {\n // Find JS files that have corresponding .map files\n const jsFiles = this.files.filter(f => f.type === 'js');\n const mapFiles = this.files.filter(f => f.type === 'map');\n\n for (let i = 0; i < jsFiles.length; i++) {\n const jsFile = jsFiles[i];\n const mapFile = mapFiles.find(m => m.path === jsFile.path + '.map');\n\n if (mapFile && !this.files.some(f => f.path === jsFile.path.replace(/\\.js$/, '.ts'))) {\n // We have .js + .map but no .ts file\n // For now, we'll just parse the JS file directly\n // Full source map reconstruction would require the 'source-map' library\n this.logger?.debug('OpenAPIAnalyzer', `Note: Found ${jsFile.path} with source map but no .ts file. Will parse JS directly.`);\n }\n }\n }\n\n /**\n * Collect all imports from source files for later resolution\n */\n private async collectImports(): Promise<void> {\n if (!this.program) return;\n\n for (const sourceFile of this.program.getSourceFiles()) {\n if (sourceFile.fileName.includes('node_modules')) continue;\n if (sourceFile.isDeclarationFile) continue;\n\n const fileImports = new Map<string, { modulePath: string; exportName?: string; }>();\n\n ts.forEachChild(sourceFile, (node) => {\n if (ts.isImportDeclaration(node)) {\n const moduleSpecifier = node.moduleSpecifier;\n if (ts.isStringLiteral(moduleSpecifier)) {\n const modulePath = moduleSpecifier.text;\n\n // Handle default import: import Foo from './foo'\n if (node.importClause?.name) {\n const importedName = node.importClause.name.getText(sourceFile);\n fileImports.set(importedName, { modulePath, exportName: 'default' });\n }\n\n // Handle named imports: import { Foo, Bar } from './foo'\n if (node.importClause?.namedBindings && ts.isNamedImports(node.importClause.namedBindings)) {\n for (const element of node.importClause.namedBindings.elements) {\n const importedName = element.name.getText(sourceFile);\n const exportName = element.propertyName?.getText(sourceFile) || importedName;\n fileImports.set(importedName, { modulePath, exportName });\n }\n }\n\n // Handle namespace imports: import * as foo from './foo'\n if (node.importClause?.namedBindings && ts.isNamespaceImport(node.importClause.namedBindings)) {\n const importedName = node.importClause.namedBindings.name.getText(sourceFile);\n fileImports.set(importedName, { modulePath, exportName: '*' });\n }\n }\n }\n });\n\n if (fileImports.size > 0) {\n this.imports.set(sourceFile.fileName, fileImports);\n }\n }\n }\n\n /**\n * Parse TypeScript files and create AST\n */\n private async parseTypeScriptFiles(): Promise<void> {\n let fileNames: string[] = [];\n\n if (this.entrypoint) {\n // If entrypoint is provided, let TypeScript resolve dependencies\n fileNames = [this.entrypoint];\n // console.log(`[Analyzer] Using entrypoint: ${this.entrypoint}`);\n } else {\n // Otherwise, scan the directory manually\n await this.scanDirectory(this.rootDir);\n const tsFiles = this.files.filter(f => f.type === 'ts' || f.type === 'js');\n fileNames = tsFiles.map(f => f.path);\n // console.log(`[Analyzer] Scanning directory, found ${fileNames.length} files`);\n }\n\n // Create TypeScript program\n this.program = ts.createProgram(fileNames, {\n target: ts.ScriptTarget.ESNext,\n module: ts.ModuleKind.ESNext,\n allowJs: true,\n moduleResolution: ts.ModuleResolutionKind.Node10,\n rootDir: this.rootDir,\n skipLibCheck: true,\n skipDefaultLibCheck: false,\n });\n\n // If using entrypoint, update this.files with what TS found in the project\n if (this.entrypoint) {\n this.files = this.program.getSourceFiles()\n .filter(sf => !sf.fileName.includes('node_modules'))\n .map(sf => ({ path: sf.fileName, type: sf.fileName.endsWith('.js') ? 'js' : 'ts' }));\n }\n }\n\n /**\n * Find all Shokupan/ShokupanRouter instances\n */\n private async findApplications(): Promise<void> {\n if (!this.program) return;\n\n const typeChecker = this.program.getTypeChecker();\n\n for (let i = 0; i < this.program.getSourceFiles().length; i++) {\n const sourceFile = this.program.getSourceFiles()[i];\n // Skip node_modules and declaration files/tests\n if (sourceFile.fileName.includes('node_modules')) continue;\n if (sourceFile.isDeclarationFile) continue;\n\n // Allow analyzing test files if we are pointing explicitly to a test directory (fixtures)\n // OR if the file is in a fixtures directory (used for OpenAPI spec generation from test apps)\n // OR if the file IS the entrypoint\n const isTestEnv = this.rootDir.includes('/test/') ||\n this.rootDir.includes('/tests/') ||\n this.rootDir.includes('/fixtures/') ||\n (this.entrypoint && (this.entrypoint.includes('/test/') || this.entrypoint.includes('/tests/')));\n\n const isFixtureFile = sourceFile.fileName.includes('/fixtures/');\n const isEntrypoint = this.entrypoint && sourceFile.fileName === this.entrypoint;\n\n // console.log(`[Analyzer] check ${sourceFile.fileName}: isTestEnv=${isTestEnv}, isFixture=${isFixtureFile}, isEntry=${isEntrypoint}`);\n\n if (!isTestEnv && !isFixtureFile && !isEntrypoint) {\n if (sourceFile.fileName.includes('/test/') || sourceFile.fileName.includes('/tests/')) {\n // console.log(`[Analyzer] Skipping test file: ${sourceFile.fileName}`);\n continue;\n }\n if (sourceFile.fileName.includes('/base_test/')) continue;\n if (sourceFile.fileName.includes('.test.ts') || sourceFile.fileName.includes('.spec.ts')) continue;\n }\n\n ts.forEachChild(sourceFile, (node) => {\n this.visitNode(node, sourceFile, typeChecker);\n });\n }\n }\n\n /**\n * Visit AST node to find application instances\n */\n private visitNode(node: ts.Node, sourceFile: ts.SourceFile, typeChecker: ts.TypeChecker): void {\n // Look for: class FooController ... @Controller(...)\n if (ts.isClassDeclaration(node)) {\n // Check for @Controller decorator\n let isController = false;\n let controllerPrefix: string | undefined;\n let className = node.name?.getText(sourceFile);\n\n const decorators: ts.Decorator[] = (node as any).decorators || node.modifiers?.filter((m: any) => ts.isDecorator(m));\n\n if (decorators) {\n const controllerDecorator = decorators.find((d: any) => {\n const expr = d.expression;\n if (ts.isCallExpression(expr)) {\n const identifier = expr.expression.getText(sourceFile);\n return identifier === 'Controller';\n }\n return false;\n });\n if (controllerDecorator) {\n isController = true;\n const expr = controllerDecorator.expression as ts.CallExpression;\n if (expr.arguments.length > 0 && ts.isStringLiteral(expr.arguments[0])) {\n controllerPrefix = expr.arguments[0].text;\n }\n }\n }\n\n // Fallback: Check for method decorators (@Get, @Post, etc.)\n if (!isController) {\n const hasRouteDecorators = node.members.some(m => {\n // Trust 175 as MethodDeclaration if TS matches mostly, or just check members\n if (ts.isMethodDeclaration(m) || m.kind === 175 || m.kind === 170 || m.kind === 171) {\n const decs = (m as any).decorators || (m as any).modifiers?.filter((mod: any) => ts.isDecorator(mod));\n if (decs) {\n return decs.some((d: any) => {\n const expr = d.expression;\n if (ts.isCallExpression(expr)) {\n const identifier = expr.expression.getText(sourceFile);\n return ['get', 'post', 'put', 'delete', 'patch', 'options', 'head', 'event'].includes(identifier.toLowerCase());\n }\n return false;\n });\n }\n }\n return false;\n });\n if (hasRouteDecorators) {\n isController = true;\n }\n }\n\n if (isController && className) {\n this.applications.push({\n name: className,\n filePath: sourceFile.fileName,\n className: 'Controller',\n controllerPrefix,\n routes: [],\n mounted: [],\n middleware: []\n });\n }\n }\n\n if (ts.isVariableDeclaration(node) && node.initializer) {\n if (ts.isNewExpression(node.initializer)) {\n const expr = node.initializer;\n const className = expr.expression.getText(sourceFile);\n\n if (className === 'Shokupan' || className === 'ShokupanRouter' || className === 'ShokupanWebsocketRouter') {\n const varName = node.name.getText(sourceFile);\n\n this.applications.push({\n name: varName,\n filePath: sourceFile.fileName,\n className: className as 'Shokupan' | 'ShokupanRouter' | 'ShokupanWebsocketRouter',\n routes: [],\n mounted: [],\n middleware: []\n });\n }\n }\n }\n\n // Look for standalone route calls in files that don't instantiate an app\n if (ts.isCallExpression(node)) {\n const expr = node.expression;\n if (ts.isPropertyAccessExpression(expr)) {\n const method = expr.name.getText(sourceFile);\n if (['get', 'post', 'put', 'delete', 'patch', 'options', 'head', 'event', 'on'].includes(method)) {\n const existing = this.applications.find(a => a.filePath === sourceFile.fileName);\n if (!existing) {\n this.applications.push({\n name: 'GenericModule',\n filePath: sourceFile.fileName,\n className: 'Shokupan',\n routes: [],\n mounted: [],\n middleware: []\n });\n }\n }\n }\n }\n\n // Recursively visit children\n ts.forEachChild(node, (child) => this.visitNode(child, sourceFile, typeChecker));\n }\n\n /**\n * Extract route information from applications\n */\n private async extractRoutes(): Promise<void> {\n if (!this.program) return;\n\n for (let i = 0; i < this.applications.length; i++) {\n const app = this.applications[i];\n const sourceFile = this.program.getSourceFile(app.filePath);\n if (!sourceFile) continue;\n\n this.extractRoutesFromFile(app, sourceFile);\n }\n }\n\n /**\n * Extract routes from a Controller class\n */\n private extractRoutesFromController(app: ApplicationInstance, classNode: ts.ClassDeclaration, sourceFile: ts.SourceFile): void {\n const methods = classNode.members.filter(m => ts.isMethodDeclaration(m) || m.kind === 175);\n\n for (let i = 0; i < methods.length; i++) {\n const method = methods[i];\n const methodNode = method as any; // Cast to any to access decorators in newer/older TS mix\n if (!methodNode.decorators && !methodNode.modifiers) continue;\n\n const decorators = methodNode.decorators || methodNode.modifiers?.filter((m: any) => ts.isDecorator(m));\n if (!decorators) continue;\n\n // Find route decorators: @Get, @Post, etc.\n const routeDecorator = decorators.find((d: any) => {\n const expr = d.expression;\n if (ts.isCallExpression(expr)) {\n const identifier = expr.expression.getText(sourceFile);\n return ['get', 'post', 'put', 'delete', 'patch', 'options', 'head', 'event'].includes(identifier.toLowerCase());\n }\n return false;\n });\n\n if (routeDecorator && ts.isCallExpression(routeDecorator.expression)) {\n const decoratorName = routeDecorator.expression.expression.getText(sourceFile);\n const httpMethod = decoratorName.toUpperCase();\n let routePath = '/';\n\n // Get path\n const pathArg = routeDecorator.expression.arguments[0];\n if (pathArg && ts.isStringLiteral(pathArg)) {\n routePath = pathArg.text;\n }\n\n // Normalize path params: /users/:id -> /users/{id}\n routePath = routePath.replace(/:([a-zA-Z0-9_]+)/g, '{$1}');\n\n // Handler Name (Class.method)\n const handlerName = `${app.name}.${methodNode.name.getText(sourceFile)}`;\n\n // Analyze the method body\n const analysis = this.analyzeHandler(methodNode, sourceFile, httpMethod);\n\n app.routes.push({\n method: httpMethod,\n path: routePath,\n handlerName: handlerName,\n handlerSource: methodNode.getText(sourceFile),\n requestTypes: analysis.requestTypes,\n responseType: analysis.responseType,\n responseSchema: analysis.responseSchema,\n hasUnknownFields: analysis.hasUnknownFields,\n emits: analysis.emits,\n sourceContext: {\n file: sourceFile.fileName,\n startLine: sourceFile.getLineAndCharacterOfPosition(methodNode.getStart()).line + 1,\n endLine: sourceFile.getLineAndCharacterOfPosition(methodNode.getEnd()).line + 1,\n highlights: analysis.highlights\n }\n });\n }\n }\n };\n\n /**\n * Extract routes from a specific file\n */\n private extractRoutesFromFile(app: ApplicationInstance, sourceFile: ts.SourceFile): void {\n if (app.className === 'Controller') {\n const classNode = sourceFile.statements.find(s => ts.isClassDeclaration(s) && s.name?.getText(sourceFile) === app.name) as ts.ClassDeclaration;\n if (classNode) {\n this.extractRoutesFromController(app, classNode, sourceFile);\n }\n } else {\n // Existing logic for app/router instances\n const visit = (node: ts.Node) => {\n // Look for method calls: app.get(), router.post(), etc.\n if (ts.isCallExpression(node)) {\n if (ts.isPropertyAccessExpression(node.expression)) {\n const objName = node.expression.expression.getText(sourceFile);\n const methodName = node.expression.name.getText(sourceFile);\n\n // Check if this is our application instance\n // For GenericModule, we accept any variable name as it's likely an argument (e.g. app.event)\n if (objName === app.name || (app.name === 'GenericModule' && node.arguments.length >= 2)) {\n if (['get', 'post', 'put', 'delete', 'patch', 'options', 'head', 'on', 'event'].includes(methodName.toLowerCase())) {\n // Extract route info\n const route = this.extractRouteFromCall(node, sourceFile, methodName.toUpperCase());\n if (route) {\n app.routes.push(route);\n }\n } else if (methodName === 'mount') {\n // Extract mount info\n const mount = this.extractMountFromCall(node, sourceFile);\n if (mount) {\n app.mounted.push(mount);\n }\n } else if (methodName === 'use') {\n // Extract middleware info\n const middleware = this.extractMiddlewareFromCall(node, sourceFile);\n if (middleware) {\n // If attached to root application, mark as global\n if (app.className === 'Shokupan') {\n middleware.scope = 'global';\n }\n app.middleware.push(middleware);\n }\n }\n }\n }\n }\n\n ts.forEachChild(node, visit);\n };\n\n ts.forEachChild(sourceFile, visit);\n }\n }\n\n /**\n * Resolve string value from expression (literals, concatenation, templates, constants)\n */\n private resolveStringValue(node: ts.Node, sourceFile: ts.SourceFile): string | null {\n if (ts.isStringLiteral(node)) {\n return node.text;\n }\n if (ts.isNoSubstitutionTemplateLiteral(node)) {\n return node.text;\n }\n if (ts.isTemplateExpression(node)) {\n let result = node.head.text;\n for (const span of node.templateSpans) {\n const val = this.resolveStringValue(span.expression, sourceFile);\n if (val === null) return null;\n result += val + span.literal.text;\n }\n return result;\n }\n if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.PlusToken) {\n const left = this.resolveStringValue(node.left, sourceFile);\n const right = this.resolveStringValue(node.right, sourceFile);\n if (left !== null && right !== null) {\n return left + right;\n }\n return null;\n }\n if (ts.isParenthesizedExpression(node)) {\n return this.resolveStringValue(node.expression, sourceFile);\n }\n if (ts.isIdentifier(node)) {\n if (this.program) {\n const checker = this.program.getTypeChecker();\n const symbol = checker.getSymbolAtLocation(node);\n if (symbol && symbol.valueDeclaration && ts.isVariableDeclaration(symbol.valueDeclaration) && symbol.valueDeclaration.initializer) {\n return this.resolveStringValue(symbol.valueDeclaration.initializer, sourceFile);\n }\n }\n // Fallback: Check top-level statements in same file if not using TypeChecker or finding symbol failed\n // (Only for const/let defined in the same file)\n // ... Simple scan omitted for now as program.getTypeChecker returns reliable results if program is created correctly.\n }\n\n return null;\n }\n\n /**\n * Extract route information from a route call (e.g., app.get('/path', handler))\n */\n private extractRouteFromCall(node: ts.CallExpression, sourceFile: ts.SourceFile, method: string): RouteInfo | null {\n const args = node.arguments;\n\n if (args.length < 2) return null;\n\n const pathArg = args[0];\n let routePath = this.resolveStringValue(pathArg, sourceFile);\n\n let dynamicHighlights: { startLine: number; endLine: number; type: 'dynamic-path'; }[] = [];\n\n if (!routePath) {\n if (['EVENT', 'ON'].includes(method.toUpperCase())) {\n routePath = '__DYNAMIC_EVENT__';\n } else {\n routePath = '__DYNAMIC_ROUTE__';\n }\n\n // Capture location of the dynamic expression for highlighting\n const start = sourceFile.getLineAndCharacterOfPosition(pathArg.getStart());\n const end = sourceFile.getLineAndCharacterOfPosition(pathArg.getEnd());\n\n dynamicHighlights.push({\n startLine: start.line + 1,\n endLine: end.line + 1,\n type: 'dynamic-path'\n });\n }\n\n // Normalize path params: /users/:id -> /users/{id}\n // This ensures matching with runtime-generated keys\n const normalizedPath = routePath.replace(/:([a-zA-Z0-9_]+)/g, '{$1}');\n\n let metadata: any = {};\n\n // Check for metadata argument (3 args: path, metadata, handler)\n if (args.length >= 3 && ts.isObjectLiteralExpression(args[1])) {\n const metaObj = args[1];\n // Extract summary, description, tags, etc.\n const rawMeta = this.convertExpressionToSchema(metaObj, sourceFile, new Map());\n\n // convertExpressionToSchema returns a schema-like object { type: 'object', properties: {...} }\n // But we want the actual values if they are literals.\n // convertExpressionToSchema is designed for SCHEMAS, not values.\n // We need a simpler value extractor or just parse the props directly for this specific case.\n\n for (let i = 0; i < metaObj.properties.length; i++) {\n const prop = metaObj.properties[i];\n if (ts.isPropertyAssignment(prop) && prop.name) {\n const name = prop.name.getText(sourceFile);\n const val = prop.initializer;\n\n if (ts.isStringLiteral(val)) {\n metadata[name] = val.text;\n } else if (ts.isArrayLiteralExpression(val) && name === 'tags') {\n metadata.tags = val.elements\n .filter(e => ts.isStringLiteral(e))\n .map(e => (e as ts.StringLiteral).text);\n } else if (name === 'operationId' && ts.isStringLiteral(val)) {\n metadata.operationId = val.text;\n }\n }\n }\n }\n\n // Extract handler information\n const handlerArg = args[args.length - 1];\n const handlerInfo = this.analyzeHandler(handlerArg, sourceFile, method);\n\n return {\n method,\n path: normalizedPath,\n handlerName: handlerArg.getText(sourceFile).substring(0, 50), // Truncate for display\n handlerSource: handlerArg.getText(sourceFile),\n requestTypes: handlerInfo.requestTypes,\n responseType: handlerInfo.responseType,\n responseSchema: handlerInfo.responseSchema,\n emits: handlerInfo.emits,\n ...metadata,\n sourceContext: {\n file: sourceFile.fileName,\n startLine: sourceFile.getLineAndCharacterOfPosition(handlerArg.getStart()).line + 1,\n endLine: sourceFile.getLineAndCharacterOfPosition(handlerArg.getEnd()).line + 1,\n highlights: [...(handlerInfo.highlights || []), ...dynamicHighlights]\n }\n };\n }\n\n /**\n * Analyze a route handler to extract type information\n */\n private analyzeHandler(handler: ts.Node, sourceFile: ts.SourceFile, method?: string): {\n requestTypes?: RouteInfo['requestTypes'];\n responseType?: string;\n responseSchema?: any;\n hasUnknownFields?: boolean;\n emits?: { event: string; payload?: any; location?: { startLine: number; endLine: number; }; }[];\n highlights?: { startLine: number; endLine: number; type: 'emit' | 'return-success' | 'return-warning'; }[];\n } {\n // Get TypeChecker for type resolution\n const typeChecker = this.program?.getTypeChecker();\n const requestTypes: RouteInfo['requestTypes'] = {};\n let responseType: string | undefined;\n let responseSchemas: any[] = []; // Track multiple schemas from different code paths\n let hasExplicitReturnType = false;\n const emits: { event: string; payload?: any; location?: { startLine: number; endLine: number; }; }[] = [];\n const highlights: { startLine: number; endLine: number; type: 'emit' | 'return-success' | 'return-warning'; }[] = [];\n\n // Simple scope to track variable types (name -> schema)\n const scope = new Map<string, any>();\n\n // Pre-populate scope with function parameters\n if (ts.isFunctionLike(handler)) {\n handler.parameters.forEach((param, index) => {\n if (ts.isIdentifier(param.name) && param.type) {\n const paramName = param.name.getText(sourceFile);\n // Resolving TypeReference for parameters (e.g. User) would require partial type checker or expanded scope logic\n // For now, we rely on basic types\n const paramType = this.convertTypeNodeToSchema(param.type, sourceFile);\n if (paramType) {\n scope.set(paramName, paramType);\n\n // If this is an event/on handler, the second parameter is likely the payload\n if ((method === 'EVENT' || method === 'ON') && index === 1) {\n requestTypes.body = paramType;\n }\n }\n }\n });\n\n // Check for explicit return type annotation\n if (handler.type) {\n const returnSchema = this.convertTypeNodeToSchema(handler.type, sourceFile);\n if (returnSchema) {\n responseSchemas.push(returnSchema);\n responseType = returnSchema.type;\n hasExplicitReturnType = true;\n }\n }\n }\n\n // Helper to analyze an expression that is being returned (either explicitly or implicitly)\n const analyzeReturnExpression = (expr: ts.Expression) => {\n let node = expr;\n // Unwrap await\n if (ts.isAwaitExpression(node)) {\n node = node.expression;\n }\n\n\n // Case 1: return ctx.json(...) or ctx.text(...)\n if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression)) {\n const callObj = node.expression.expression.getText(sourceFile);\n const callProp = node.expression.name.getText(sourceFile);\n\n if (callObj === 'ctx' || callObj.endsWith('.ctx')) {\n if (callProp === 'json') {\n if (node.arguments.length > 0) {\n const schema = this.convertExpressionToSchema(node.arguments[0], sourceFile, scope, typeChecker);\n responseSchemas.push(schema);\n responseType = 'object';\n }\n return;\n }\n else if (callProp === 'text') {\n responseType = 'string';\n return;\n }\n else if (callProp === 'html' || callProp === 'jsx') {\n responseType = 'html';\n return;\n }\n }\n }\n\n // Case 2: Direct object return\n // Only use this if we haven't found a better schema yet, or if it looks specific\n // And if we don't have an explicit return type\n if (!hasExplicitReturnType && responseSchemas.length === 0) {\n const schema = this.convertExpressionToSchema(node, sourceFile, scope, typeChecker);\n if (schema && (schema.type !== 'object' || Object.keys(schema.properties || {}).length > 0)) {\n responseSchemas.push(schema);\n responseType = schema.type;\n }\n }\n\n // Fallback to text matching if schema inference failed and we still don't have a type\n if (responseSchemas.length === 0 && !responseType) {\n const returnText = node.getText(sourceFile);\n if (returnText.startsWith('{')) {\n responseType = 'object';\n } else if (returnText.startsWith('[')) {\n responseType = 'array';\n } else if (returnText.startsWith('\"') || returnText.startsWith(\"'\")) {\n responseType = 'string';\n }\n }\n };\n\n // Handle arrow functions\n let body: ts.Block | undefined;\n // Also check for Kind 175 (Method/Accessor in some TS versions)\n if (ts.isArrowFunction(handler) || ts.isFunctionExpression(handler) || ts.isMethodDeclaration(handler) || handler.kind === 175) {\n // TS method has .body which is FunctionBody (Block) or undefined\n body = (handler as any).body;\n\n // Visit the handler body to find ctx usage\n const visit = (node: ts.Node) => {\n // Track variable declarations\n if (ts.isVariableDeclaration(node)) {\n if (node.initializer) {\n // Handle simple identifier: const varName = ...\n if (ts.isIdentifier(node.name)) {\n const varName = node.name.getText(sourceFile);\n\n // Check if initializer is a type assertion on ctx.body()\n let initializer = node.initializer;\n if (ts.isAsExpression(initializer)) {\n if (this.isCtxBodyCall(initializer.expression, sourceFile)) {\n const schema = this.convertTypeNodeToSchema(initializer.type, sourceFile);\n if (schema) {\n requestTypes.body = schema;\n scope.set(varName, schema);\n }\n } else {\n const schema = this.convertExpressionToSchema(initializer, sourceFile, scope, typeChecker);\n scope.set(varName, schema);\n }\n } else {\n const schema = this.convertExpressionToSchema(initializer, sourceFile, scope, typeChecker);\n scope.set(varName, schema);\n }\n }\n // Handle array destructuring: const [a, b] = ...\n else if (ts.isArrayBindingPattern(node.name)) {\n // Get the initializer schema\n const initializerSchema = this.convertExpressionToSchema(node.initializer, sourceFile, scope, typeChecker);\n\n // If the initializer is an array, try to infer element types\n if (initializerSchema?.type === 'array' && initializerSchema.items) {\n // Track each destructured element with the array's item type\n for (let i = 0; i < node.name.elements.length; i++) {\n const element = node.name.elements[i];\n if (ts.isBindingElement(element) && ts.isIdentifier(element.name)) {\n const elementName = element.name.getText(sourceFile);\n scope.set(elementName, initializerSchema.items);\n }\n }\n } else {\n // For non-array initializers or unknown types, track as unknown\n for (let i = 0; i < node.name.elements.length; i++) {\n const element = node.name.elements[i];\n if (ts.isBindingElement(element) && ts.isIdentifier(element.name)) {\n const elementName = element.name.getText(sourceFile);\n scope.set(elementName, { 'x-unknown': true });\n }\n }\n }\n }\n // Handle object destructuring: const { a, b } = ...\n else if (ts.isObjectBindingPattern(node.name)) {\n const initializerSchema = this.convertExpressionToSchema(node.initializer, sourceFile, scope, typeChecker);\n\n // If the initializer is an object with properties, extract the types\n if (initializerSchema?.type === 'object' && initializerSchema.properties) {\n for (let i = 0; i < node.name.elements.length; i++) {\n const element = node.name.elements[i];\n if (ts.isBindingElement(element) && ts.isIdentifier(element.name)) {\n const elementName = element.name.getText(sourceFile);\n const propertySchema = initializerSchema.properties[elementName];\n scope.set(elementName, propertySchema || { 'x-unknown': true });\n }\n }\n } else {\n // For non-object initializers, track as any\n for (let i = 0; i < node.name.elements.length; i++) {\n const element = node.name.elements[i];\n if (ts.isBindingElement(element) && ts.isIdentifier(element.name)) {\n const elementName = element.name.getText(sourceFile);\n scope.set(elementName, { 'x-unknown': true });\n }\n }\n }\n }\n }\n }\n\n // Check for type assertions on ctx.body()\n if (ts.isAsExpression(node)) {\n if (this.isCtxBodyCall(node.expression, sourceFile)) {\n const schema = this.convertTypeNodeToSchema(node.type, sourceFile);\n if (schema) {\n requestTypes.body = schema;\n\n // Track variables assigned to this body\n if (ts.isVariableDeclaration(node.parent)) {\n const varName = node.parent.name.getText(sourceFile);\n scope.set(varName, schema);\n }\n }\n }\n }\n // Check for untyped ctx.body() or await ctx.body() calls\n else if (this.isCtxBodyCall(node, sourceFile)) {\n if (!requestTypes.body) {\n requestTypes.body = { type: 'object', description: 'Request Body' };\n }\n }\n\n // Look for ctx calls (json, text, html, send, emit) to highlight\n if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression)) {\n const objText = node.expression.expression.getText(sourceFile);\n const propText = node.expression.name.getText(sourceFile);\n\n if (objText === 'ctx' || objText.endsWith('.ctx') || objText === 'this') {\n const startLine = sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1;\n const endLine = sourceFile.getLineAndCharacterOfPosition(node.getEnd()).line + 1;\n\n if (['text', 'html', 'jsx'].includes(propText)) {\n // text/html/jsx are always strings, so statically valid\n highlights.push({ startLine, endLine, type: 'return-success' });\n } else if (propText === 'json') {\n // Check if we can extract a schema for the argument\n let isStatic = false;\n if (node.arguments.length > 0) {\n const schema = this.convertExpressionToSchema(node.arguments[0], sourceFile, scope, typeChecker);\n // If schema is not just a bare object or any, it's static\n if (schema && (schema.type !== 'object' || (schema.properties && Object.keys(schema.properties).length > 0))) {\n isStatic = true;\n }\n }\n highlights.push({ startLine, endLine, type: isStatic ? 'return-success' : 'return-warning' });\n } else if (['send', 'emit'].includes(propText)) {\n highlights.push({ startLine, endLine, type: 'emit' });\n }\n }\n }\n\n // Look for ctx usage\n if (ts.isPropertyAccessExpression(node)) {\n const objText = node.expression.getText(sourceFile);\n const propText = node.name.getText(sourceFile);\n\n if (objText === 'ctx' || objText.endsWith('.ctx')) {\n if (propText === 'body') {\n if (!requestTypes.body) {\n requestTypes.body = { type: 'object' };\n }\n } else if (propText === 'query') {\n if (!requestTypes.query) requestTypes.query = {};\n\n let key: string | undefined;\n let parentExpr: ts.Node | undefined;\n\n if (ts.isPropertyAccessExpression(node.parent)) {\n key = node.parent.name.getText(sourceFile);\n parentExpr = node.parent;\n } else if (ts.isElementAccessExpression(node.parent)) {\n const arg = node.parent.argumentExpression;\n if (ts.isStringLiteral(arg)) {\n key = arg.text;\n parentExpr = node.parent;\n }\n }\n\n if (key && parentExpr) {\n let type = 'string';\n const parent = parentExpr.parent;\n\n if (ts.isCallExpression(parent) && ts.isIdentifier(parent.expression)) {\n const fnName = parent.expression.getText(sourceFile);\n if (fnName === 'parseInt') type = 'integer'; // Explicit integer\n else if (fnName === 'parseFloat' || fnName === 'Number') type = 'number';\n else if (fnName === 'Boolean') type = 'boolean';\n }\n // Check for Unary Expression: +ctx.query.page (number) or !ctx.query.flag (boolean)\n else if (ts.isPrefixUnaryExpression(parent)) {\n if (parent.operator === ts.SyntaxKind.PlusToken) type = 'number';\n else if (parent.operator === ts.SyntaxKind.ExclamationToken) type = 'boolean';\n }\n\n if (!requestTypes.query[key] || requestTypes.query[key] === 'string') {\n requestTypes.query[key] = type;\n }\n }\n } else if (propText === 'params') {\n if (!requestTypes.params) requestTypes.params = {};\n\n let key: string | undefined;\n let parentExpr: ts.Node | undefined;\n\n if (ts.isPropertyAccessExpression(node.parent)) {\n key = node.parent.name.getText(sourceFile);\n parentExpr = node.parent;\n } else if (ts.isElementAccessExpression(node.parent)) {\n const arg = node.parent.argumentExpression;\n if (ts.isStringLiteral(arg)) {\n key = arg.text;\n parentExpr = node.parent;\n }\n }\n\n if (key && parentExpr) {\n let type = 'string';\n const parent = parentExpr.parent;\n\n if (ts.isCallExpression(parent) && ts.isIdentifier(parent.expression)) {\n const fnName = parent.expression.getText(sourceFile);\n if (fnName === 'parseInt') type = 'integer'; // Integer\n else if (fnName === 'parseFloat' || fnName === 'Number') type = 'number';\n else if (fnName === 'Boolean') type = 'boolean';\n }\n else if (ts.isPrefixUnaryExpression(parent)) {\n if (parent.operator === ts.SyntaxKind.PlusToken) type = 'number';\n else if (parent.operator === ts.SyntaxKind.ExclamationToken) type = 'boolean';\n }\n\n if (!requestTypes.params[key] || requestTypes.params[key] === 'string') {\n requestTypes.params[key] = type;\n }\n }\n } else if (propText === 'headers') {\n if (!requestTypes.headers) requestTypes.headers = {};\n\n let key: string | undefined;\n if (ts.isPropertyAccessExpression(node.parent)) {\n key = node.parent.name.getText(sourceFile);\n } else if (ts.isElementAccessExpression(node.parent)) {\n const arg = node.parent.argumentExpression;\n if (ts.isStringLiteral(arg)) {\n key = arg.text;\n }\n }\n\n if (key && !requestTypes.headers[key]) {\n requestTypes.headers[key] = 'string';\n }\n }\n }\n }\n\n // Explicit Return\n if (ts.isReturnStatement(node)) {\n const startLine = sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1;\n const endLine = sourceFile.getLineAndCharacterOfPosition(node.getEnd()).line + 1;\n\n let isStatic = false;\n if (node.expression) {\n const schemasBeforeReturn = responseSchemas.length;\n analyzeReturnExpression(node.expression);\n // If analyzeReturnExpression added schemas, it's static\n if (responseSchemas.length > schemasBeforeReturn) {\n isStatic = true;\n }\n } else if (hasExplicitReturnType) {\n // void return or similar\n isStatic = true;\n }\n\n highlights.push({ startLine, endLine, type: isStatic ? 'return-success' : 'return-warning' });\n }\n\n // Implicit Return (Concise Arrow Function)\n // e.g. (ctx) => ctx.json(...) or .then(res => ctx.json(res))\n if (ts.isArrowFunction(node) && !ts.isBlock(node.body)) {\n // For concise arrow function, the body IS the return value\n const startLine = sourceFile.getLineAndCharacterOfPosition(node.body.getStart()).line + 1;\n const endLine = sourceFile.getLineAndCharacterOfPosition(node.body.getEnd()).line + 1;\n\n const schemasBeforeReturn = responseSchemas.length;\n analyzeReturnExpression(node.body as ts.Expression);\n\n let isStatic = false;\n if (responseSchemas.length > schemasBeforeReturn) {\n isStatic = true;\n }\n\n highlights.push({ startLine, endLine, type: isStatic ? 'return-success' : 'return-warning' });\n }\n\n // Implicit Return call (e.g. ctx.json(...) as a statement without return)\n if (ts.isExpressionStatement(node)) {\n analyzeReturnExpression(node.expression);\n\n // Check for ctx.emit() or this.emit()\n if (ts.isCallExpression(node.expression)) {\n const expr = node.expression;\n if (ts.isPropertyAccessExpression(expr.expression)) {\n const objText = expr.expression.expression.getText(sourceFile);\n const propText = expr.expression.name.getText(sourceFile);\n\n if (((objText === 'ctx' || objText.endsWith('.ctx')) || (objText === 'this' || objText.endsWith('.this'))) && propText === 'emit') {\n if (expr.arguments.length >= 1) {\n const eventNameArg = expr.arguments[0];\n if (ts.isStringLiteral(eventNameArg)) {\n const eventName = eventNameArg.text;\n let payload: Record<string, unknown> = { type: 'object' };\n\n // Special case: If the argument is `await ctx.body()`, we know it's the request body\n // Even if untyped, we should treat it as \"body payload\" rather than \"unknown inference failure\"\n if (this.isCtxBodyCall(expr.arguments[1], sourceFile)) {\n payload = { type: 'object', description: 'Request Body' };\n // If requestTypes.body is not set, set it to generic object so generator picks it up\n if (!requestTypes.body) {\n requestTypes.body = { type: 'object' };\n }\n } else {\n payload = this.convertExpressionToSchema(expr.arguments[1], sourceFile, scope, typeChecker);\n }\n\n const emitLoc = {\n startLine: sourceFile.getLineAndCharacterOfPosition(expr.getStart()).line + 1,\n endLine: sourceFile.getLineAndCharacterOfPosition(expr.getEnd()).line + 1\n };\n emits.push({ event: eventName, payload, location: emitLoc });\n } else {\n const emitLoc = {\n startLine: sourceFile.getLineAndCharacterOfPosition(expr.getStart()).line + 1,\n endLine: sourceFile.getLineAndCharacterOfPosition(expr.getEnd()).line + 1\n };\n emits.push({ event: '__DYNAMIC_EMIT__', payload: { type: 'object' }, location: emitLoc });\n }\n }\n }\n }\n }\n }\n\n ts.forEachChild(node, visit);\n };\n\n if (ts.isBlock(body)) {\n ts.forEachChild(body, visit);\n } else {\n // Main handler is an implicit return: app.get('/', (ctx) => ctx.json(...))\n analyzeReturnExpression(body);\n // Also verify children (e.g. if body is a CallExpression, verify args??)\n // analyzeReturnExpression analyzes the expression itself.\n // But we ALSO want to visit children to find other usages (request types)\n // or nested arrow functions in a call chain (e.g. chaining .then())\n ts.forEachChild(body, visit);\n }\n }\n\n // Merge multiple response schemas using oneOf if there are multiple distinct schemas\n let finalResponseSchema: any | undefined;\n if (responseSchemas.length > 1) {\n // Check if all schemas are identical - if so, just use one\n const uniqueSchemas = this.deduplicateSchemas(responseSchemas);\n if (uniqueSchemas.length === 1) {\n finalResponseSchema = uniqueSchemas[0];\n } else {\n // Multiple different schemas - use oneOf\n finalResponseSchema = {\n oneOf: uniqueSchemas\n };\n }\n } else if (responseSchemas.length === 1) {\n finalResponseSchema = responseSchemas[0];\n }\n\n return {\n requestTypes,\n responseType,\n responseSchema: finalResponseSchema,\n hasUnknownFields: finalResponseSchema ? this.hasUnknownFields(finalResponseSchema) : false,\n emits,\n highlights\n };\n }\n\n /**\n * Convert an Expression node to an OpenAPI schema (best effort)\n */\n private convertExpressionToSchema(node: ts.Expression, sourceFile: ts.SourceFile, scope: Map<string, any>, typeChecker?: ts.TypeChecker): any {\n\n // Object Literal: { a: 1, b: \"text\" }\n if (ts.isObjectLiteralExpression(node)) {\n const schema: any = {\n type: 'object',\n properties: {},\n required: []\n };\n\n for (let i = 0; i < node.properties.length; i++) {\n const prop = node.properties[i];\n if (ts.isPropertyAssignment(prop)) {\n const name = prop.name.getText(sourceFile);\n const valueSchema = this.convertExpressionToSchema(prop.initializer, sourceFile, scope, typeChecker);\n\n schema.properties[name] = valueSchema;\n schema.required.push(name); // Properties in literal return are required\n }\n else if (ts.isShorthandPropertyAssignment(prop)) {\n const name = prop.name.getText(sourceFile);\n // Check scope for variable\n const scopedSchema = scope.get(name);\n schema.properties[name] = scopedSchema || { type: 'object' };\n schema.required.push(name);\n }\n }\n if (schema.required.length === 0) {\n delete schema.required;\n }\n return schema;\n }\n\n // Array Literal: [1, 2]\n if (ts.isArrayLiteralExpression(node)) {\n const schema: any = { type: 'array' };\n if (node.elements.length > 0) {\n // Infer item type from first element\n schema.items = this.convertExpressionToSchema(node.elements[0], sourceFile, scope, typeChecker);\n } else {\n schema.items = {};\n }\n return schema;\n }\n\n // Conditional (Ternary) Expression: cond ? trueVal : falseVal\n if (ts.isConditionalExpression(node)) {\n const trueSchema = this.convertExpressionToSchema(node.whenTrue, sourceFile, scope, typeChecker);\n // const falseSchema = this.convertExpressionToSchema(node.whenFalse, sourceFile, scope);\n\n // Simplified: return true branch schema. Ideally we'd do oneOf\n return trueSchema;\n }\n\n // Template Expression: `Hello ${name}`\n if (ts.isTemplateExpression(node)) {\n return { type: 'string' };\n }\n\n // Await Expression: await somePromise\n if (ts.isAwaitExpression(node)) {\n // Unwrap the await and analyze the underlying expression\n return this.convertExpressionToSchema(node.expression, sourceFile, scope, typeChecker);\n }\n\n // Call Expression: Date.now(), Math.random(), etc.\n if (ts.isCallExpression(node)) {\n const callText = node.getText(sourceFile);\n\n // Common numeric-returning functions\n if (callText.startsWith('Date.now()') ||\n callText.startsWith('Math.') ||\n callText.startsWith('Number(') ||\n callText.startsWith('parseInt(') ||\n callText.startsWith('parseFloat(')) {\n return { type: 'number' };\n }\n\n // String-returning functions\n if (callText.startsWith('String(') ||\n callText.endsWith('.toString()') ||\n callText.endsWith('.join(')) {\n return { type: 'string' };\n }\n\n // Boolean-returning functions\n if (callText.startsWith('Boolean(')) {\n return { type: 'boolean' };\n }\n\n // Array-returning functions\n if (callText.endsWith('.split(') ||\n callText.endsWith('.map(') ||\n callText.endsWith('.filter(')) {\n return { type: 'array', items: {} };\n }\n\n // For unknown function calls, default to any (empty schema)\n return { 'x-unknown': true };\n }\n\n // Binary Expression: a + b, a - b, etc.\n if (ts.isBinaryExpression(node)) {\n const operator = node.operatorToken.kind;\n\n // Arithmetic operators return number\n if (operator === ts.SyntaxKind.PlusToken ||\n operator === ts.SyntaxKind.MinusToken ||\n operator === ts.SyntaxKind.AsteriskToken ||\n operator === ts.SyntaxKind.SlashToken ||\n operator === ts.SyntaxKind.PercentToken ||\n operator === ts.SyntaxKind.AsteriskAsteriskToken) {\n\n // Special case: + with strings is concatenation\n if (operator === ts.SyntaxKind.PlusToken) {\n const leftSchema = this.convertExpressionToSchema(node.left, sourceFile, scope, typeChecker);\n const rightSchema = this.convertExpressionToSchema(node.right, sourceFile, scope, typeChecker);\n\n // If either operand is a string, result is string\n if (leftSchema.type === 'string' || rightSchema.type === 'string') {\n return { type: 'string' };\n }\n }\n\n return { type: 'number' };\n }\n\n // Comparison operators return boolean\n if (operator === ts.SyntaxKind.GreaterThanToken ||\n operator === ts.SyntaxKind.LessThanToken ||\n operator === ts.SyntaxKind.GreaterThanEqualsToken ||\n operator === ts.SyntaxKind.LessThanEqualsToken ||\n operator === ts.SyntaxKind.EqualsEqualsToken ||\n operator === ts.SyntaxKind.EqualsEqualsEqualsToken ||\n operator === ts.SyntaxKind.ExclamationEqualsToken ||\n operator === ts.SyntaxKind.ExclamationEqualsEqualsToken) {\n return { type: 'boolean' };\n }\n\n // Logical operators - infer from operands\n if (operator === ts.SyntaxKind.AmpersandAmpersandToken ||\n operator === ts.SyntaxKind.BarBarToken) {\n const leftSchema = this.convertExpressionToSchema(node.left, sourceFile, scope, typeChecker);\n const rightSchema = this.convertExpressionToSchema(node.right, sourceFile, scope, typeChecker);\n\n // For ||, if right is a string literal (common fallback pattern), result is string\n if (operator === ts.SyntaxKind.BarBarToken && rightSchema.type === 'string') {\n return { type: 'string' };\n }\n\n // Return the non-boolean schema if available, otherwise boolean\n if (leftSchema.type && leftSchema.type !== 'boolean') {\n return leftSchema;\n }\n if (rightSchema.type && rightSchema.type !== 'boolean') {\n return rightSchema;\n }\n return { type: 'boolean' };\n }\n\n // Bitwise operators return number\n if (operator === ts.SyntaxKind.AmpersandToken ||\n operator === ts.SyntaxKind.BarToken ||\n operator === ts.SyntaxKind.CaretToken ||\n operator === ts.SyntaxKind.LessThanLessThanToken ||\n operator === ts.SyntaxKind.GreaterThanGreaterThanToken ||\n operator === ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken) {\n return { type: 'number' };\n }\n }\n\n // PropertyAccessExpression (e.g., process.env, performance.now)\n if ((ts.isPropertyAccessExpression(node) || ts.isElementAccessExpression(node)) && typeChecker) {\n try {\n const type = typeChecker.getTypeAtLocation(node);\n const schema = this.convertTypeToSchema(type, typeChecker);\n // Only return if we got a meaningful schema\n if (schema && (schema.type !== 'object' || schema.properties)) {\n return schema;\n }\n } catch (e) {\n // Type resolution failed, fall through to default handling\n }\n }\n\n // Identifier (Variable reference)\n if (ts.isIdentifier(node)) {\n const name = node.getText(sourceFile);\n const scopedSchema = scope.get(name);\n if (scopedSchema) return scopedSchema;\n\n // Try to resolve type using TypeChecker for built-ins and globals\n if (typeChecker) {\n try {\n const type = typeChecker.getTypeAtLocation(node);\n const schema = this.convertTypeToSchema(type, typeChecker);\n // Only return if we got a meaningful schema\n if (schema && (schema.type !== 'object' || schema.properties)) {\n return schema;\n }\n } catch (e) {\n // Type resolution failed, fall through to unknown\n }\n }\n\n return { type: 'object', 'x-unknown': true }; // Unknown reference\n }\n\n // Literals\n if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return { type: 'string' };\n if (ts.isNumericLiteral(node)) return { type: 'number' };\n if (node.kind === ts.SyntaxKind.TrueKeyword || node.kind === ts.SyntaxKind.FalseKeyword) return { type: 'boolean' };\n\n // Unknown\n return { type: 'object', 'x-unknown': true };\n }\n\n /**\n * Deduplicate schemas by comparing their JSON representations\n */\n private deduplicateSchemas(schemas: any[]): any[] {\n const seen = new Map<string, any>();\n for (const schema of schemas) {\n const key = JSON.stringify(schema);\n if (!seen.has(key)) {\n seen.set(key, schema);\n }\n }\n return Array.from(seen.values());\n }\n\n /**\n * Check if a schema contains fields with unknown types\n */\n private hasUnknownFields(schema: any): boolean {\n if (!schema) return false;\n if (schema['x-unknown']) return true;\n\n if (schema.type === 'object' && schema.properties) {\n return Object.values(schema.properties).some((prop: any) =>\n this.hasUnknownFields(prop)\n );\n }\n\n if (schema.type === 'array' && schema.items) {\n return this.hasUnknownFields(schema.items);\n }\n\n return false;\n }\n\n /**\n * Check if an expression is a call to ctx.body()\n */\n private isCtxBodyCall(node: ts.Node, sourceFile: ts.SourceFile): boolean {\n // Handle await ctx.body()\n if (ts.isAwaitExpression(node)) {\n return this.isCtxBodyCall(node.expression, sourceFile);\n }\n\n // Handle ctx.body()\n if (ts.isCallExpression(node)) {\n // Check expression: ctx.body\n if (ts.isPropertyAccessExpression(node.expression)) {\n const objText = node.expression.expression.getText(sourceFile);\n const propText = node.expression.name.getText(sourceFile);\n return (objText === 'ctx' || objText.endsWith('.ctx')) && propText === 'body';\n }\n }\n\n return false;\n }\n\n /**\n * Convert a TypeScript TypeNode to an OpenAPI schema\n */\n private convertTypeNodeToSchema(typeNode: ts.TypeNode, sourceFile: ts.SourceFile): any {\n switch (typeNode.kind) {\n case ts.SyntaxKind.StringKeyword:\n return { type: 'string' };\n case ts.SyntaxKind.NumberKeyword:\n return { type: 'number' };\n case ts.SyntaxKind.BooleanKeyword:\n return { type: 'boolean' };\n case ts.SyntaxKind.AnyKeyword:\n case ts.SyntaxKind.UnknownKeyword:\n return {}; // Any/Unknown -> empty schema (accepts anything)\n\n case ts.SyntaxKind.TypeLiteral: {\n const literal = typeNode as ts.TypeLiteralNode;\n const schema: any = {\n type: 'object',\n properties: {},\n required: []\n };\n\n for (let i = 0; i < literal.members.length; i++) {\n const member = literal.members[i];\n if (ts.isPropertySignature(member) && member.type) {\n const name = member.name.getText(sourceFile);\n const propSchema = this.convertTypeNodeToSchema(member.type, sourceFile);\n\n schema.properties[name] = propSchema;\n\n // Property is required unless it has a question token\n if (!member.questionToken) {\n schema.required.push(name);\n }\n }\n }\n\n if (schema.required.length === 0) {\n delete schema.required;\n }\n\n return schema;\n }\n\n case ts.SyntaxKind.ArrayType: {\n const arrayType = typeNode as ts.ArrayTypeNode;\n return {\n type: 'array',\n items: this.convertTypeNodeToSchema(arrayType.elementType, sourceFile)\n };\n }\n\n // Handle Type References (e.g. Array<string>)\n case ts.SyntaxKind.TypeReference: {\n const typeRef = typeNode as ts.TypeReferenceNode;\n const typeName = typeRef.typeName.getText(sourceFile);\n\n if (typeName === 'Array' && typeRef.typeArguments?.length > 0) {\n return {\n type: 'array',\n items: this.convertTypeNodeToSchema(typeRef.typeArguments[0], sourceFile)\n };\n }\n\n if (typeName === 'Promise' && typeRef.typeArguments?.length > 0) {\n return this.convertTypeNodeToSchema(typeRef.typeArguments[0], sourceFile);\n }\n\n // For other references, we default to string or object as fallback\n // A fuller implementation would resolve the reference\n return { type: 'object', description: `Ref: ${typeName}` };\n }\n\n default:\n return { type: 'object' };\n }\n }\n\n /**\n * Convert a TypeScript Type (from type checker) to an OpenAPI schema\n */\n private convertTypeToSchema(type: ts.Type, typeChecker: ts.TypeChecker, depth: number = 0): any {\n // Prevent infinite recursion on circular types\n if (depth > 5) {\n return { type: 'object', description: 'Complex type (max depth reached)' };\n }\n\n // Handle primitive types\n if (type.flags & ts.TypeFlags.String) return { type: 'string' };\n if (type.flags & ts.TypeFlags.Number) return { type: 'number' };\n if (type.flags & ts.TypeFlags.Boolean) return { type: 'boolean' };\n if (type.flags & ts.TypeFlags.Null) return { type: 'null' };\n if (type.flags & ts.TypeFlags.Undefined) return { type: 'object', nullable: true };\n if (type.flags & ts.TypeFlags.Any || type.flags & ts.TypeFlags.Unknown) return {};\n\n // Handle literal types\n if (type.flags & ts.TypeFlags.StringLiteral) {\n const literalType = type as ts.StringLiteralType;\n return { type: 'string', enum: [literalType.value] };\n }\n if (type.flags & ts.TypeFlags.NumberLiteral) {\n const literalType = type as ts.NumberLiteralType;\n return { type: 'number', enum: [literalType.value] };\n }\n if (type.flags & ts.TypeFlags.BooleanLiteral) {\n // TypeScript represents true/false as separate types\n const intrinsicName = (type as any).intrinsicName;\n return { type: 'boolean', enum: [intrinsicName === 'true'] };\n }\n\n // Handle union types\n if (type.flags & ts.TypeFlags.Union) {\n const unionType = type as ts.UnionType;\n const schemas = unionType.types.map(t => this.convertTypeToSchema(t, typeChecker, depth + 1));\n\n // If all schemas are the same primitive type, just use one\n const uniqueTypes = new Set(schemas.map(s => s.type));\n if (uniqueTypes.size === 1 && schemas[0].type !== 'object') {\n return schemas[0];\n }\n\n return { oneOf: schemas };\n }\n\n // Handle array types\n if (typeChecker.isArrayType(type)) {\n const typeArgs = (type as any).typeArguments || (type as any).resolvedTypeArguments;\n if (typeArgs && typeArgs.length > 0) {\n return {\n type: 'array',\n items: this.convertTypeToSchema(typeArgs[0], typeChecker, depth + 1)\n };\n }\n return { type: 'array', items: {} };\n }\n\n // Handle object types\n if (type.flags & ts.TypeFlags.Object) {\n const properties: Record<string, any> = {};\n const required: string[] = [];\n\n // Get properties from the type\n const props = typeChecker.getPropertiesOfType(type);\n\n // Limit number of properties to prevent huge schemas\n const maxProps = 50;\n const propsToProcess = props.slice(0, maxProps);\n\n for (const prop of propsToProcess) {\n const propName = prop.getName();\n const propType = typeChecker.getTypeOfSymbol(prop);\n\n // Skip function properties to keep schema clean\n const signatures = propType.getCallSignatures();\n if (signatures && signatures.length > 0) {\n continue;\n }\n\n properties[propName] = this.convertTypeToSchema(propType, typeChecker, depth + 1);\n\n // Check if property is optional\n if (!(prop.flags & ts.SymbolFlags.Optional)) {\n required.push(propName);\n }\n }\n\n const schema: any = { type: 'object' };\n\n if (Object.keys(properties).length > 0) {\n schema.properties = properties;\n if (required.length > 0) {\n schema.required = required;\n }\n }\n\n // Add note if we truncated properties\n if (props.length > maxProps) {\n schema.description = `Type with ${props.length} properties (showing ${maxProps})`;\n }\n\n return schema;\n }\n\n // Fallback for unhandled types\n return { type: 'object', description: 'Complex type' };\n }\n\n /**\n * Extract mount information from mount call\n */\n private extractMountFromCall(node: ts.CallExpression, sourceFile: ts.SourceFile): MountInfo | null {\n const args = node.arguments;\n\n if (args.length < 2) return null;\n\n const pathArg = args[0];\n const targetArg = args[1];\n\n let prefix = '/';\n if (ts.isStringLiteral(pathArg)) {\n prefix = pathArg.text;\n }\n\n const target = targetArg.getText(sourceFile);\n\n // Check if target is from node_modules\n const dependency = this.checkIfExternalDependency(target, sourceFile);\n let targetFilePath: string | undefined;\n\n if (!dependency) {\n // Check for internal import\n let modulePath: string | undefined;\n ts.forEachChild(sourceFile, (node) => {\n if (targetFilePath || modulePath) return; // Found\n\n if (ts.isImportDeclaration(node)) {\n const specifier = node.moduleSpecifier;\n if (ts.isStringLiteral(specifier)) {\n const path = specifier.text;\n if (path.startsWith('.')) {\n // Check default import: import target from './...'\n if (node.importClause?.name?.getText(sourceFile) === target) {\n modulePath = path;\n }\n // Check named imports: import { target } from './...'\n else if (node.importClause?.namedBindings && ts.isNamedImports(node.importClause.namedBindings)) {\n for (const element of node.importClause.namedBindings.elements) {\n if (element.name.getText(sourceFile) === target) {\n modulePath = path;\n break;\n }\n }\n }\n }\n }\n }\n });\n\n if (modulePath) {\n const dir = path.dirname(sourceFile.fileName);\n const absolutePath = path.resolve(dir, modulePath);\n\n // Try to resolve extension\n const extensions = ['.ts', '.js', '.tsx', '.jsx', '/index.ts', '/index.js'];\n for (const ext of extensions) {\n if (fs.existsSync(absolutePath + ext)) {\n targetFilePath = absolutePath + ext;\n break;\n }\n // If absolutePath ends in /index (implicit)\n // Or if modulePath points to directory\n }\n // Try straight (if user included extension)\n if (!targetFilePath && fs.existsSync(absolutePath)) {\n targetFilePath = absolutePath;\n }\n // Try directory index\n if (!targetFilePath && fs.existsSync(path.join(absolutePath, 'index.ts'))) {\n targetFilePath = path.join(absolutePath, 'index.ts');\n }\n\n // Normalize result?\n }\n }\n\n return {\n prefix,\n target,\n targetFilePath,\n dependency,\n sourceContext: {\n file: sourceFile.fileName,\n startLine: sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1,\n endLine: sourceFile.getLineAndCharacterOfPosition(node.getEnd()).line + 1\n }\n };\n }\n\n /**\n * Extract middleware information from .use() call\n */\n private extractMiddlewareFromCall(node: ts.CallExpression, sourceFile: ts.SourceFile): MiddlewareInfo | null {\n const args = node.arguments;\n\n if (args.length < 1) return null;\n\n const middlewareArg = args[0];\n\n // Get middleware name from the function/identifier\n let middlewareName = 'anonymous';\n let isImportedIdentifier = false;\n\n if (ts.isIdentifier(middlewareArg)) {\n middlewareName = middlewareArg.getText(sourceFile);\n isImportedIdentifier = true;\n } else if (ts.isCallExpression(middlewareArg) && ts.isIdentifier(middlewareArg.expression)) {\n // Middleware factory pattern: app.use(RateLimitMiddleware({...}))\n middlewareName = middlewareArg.expression.getText(sourceFile);\n isImportedIdentifier = true;\n } else if (ts.isFunctionExpression(middlewareArg) || ts.isArrowFunction(middlewareArg)) {\n middlewareName = 'inline-middleware';\n }\n\n // Analyze middleware for response types and headers\n let analysis = this.analyzeMiddleware(middlewareArg, sourceFile);\n\n // If this is an imported identifier, try to resolve and analyze the definition\n if (isImportedIdentifier) {\n const resolvedAnalysis = this.resolveImportedMiddlewareDefinition(middlewareName, sourceFile);\n // Merge resolved analysis with local analysis\n if (resolvedAnalysis.responseTypes) {\n analysis.responseTypes = { ...resolvedAnalysis.responseTypes, ...analysis.responseTypes };\n }\n if (resolvedAnalysis.headers) {\n analysis.headers = [...(resolvedAnalysis.headers || []), ...(analysis.headers || [])];\n // Deduplicate headers\n analysis.headers = Array.from(new Set(analysis.headers));\n }\n }\n\n return {\n name: middlewareName,\n file: sourceFile.fileName,\n startLine: sourceFile.getLineAndCharacterOfPosition(middlewareArg.getStart()).line + 1,\n endLine: sourceFile.getLineAndCharacterOfPosition(middlewareArg.getEnd()).line + 1,\n handlerSource: middlewareArg.getText(sourceFile),\n responseTypes: analysis.responseTypes,\n headers: analysis.headers,\n scope: 'router', // Will be updated during collection based on context\n sourceContext: {\n file: sourceFile.fileName,\n startLine: sourceFile.getLineAndCharacterOfPosition(middlewareArg.getStart()).line + 1,\n endLine: sourceFile.getLineAndCharacterOfPosition(middlewareArg.getEnd()).line + 1,\n snippet: middlewareArg.getText(sourceFile),\n highlights: analysis.highlights\n }\n };\n }\n\n /**\n * Analyze middleware function to extract response types and headers\n */\n private analyzeMiddleware(middleware: ts.Node, sourceFile: ts.SourceFile): {\n responseTypes?: Record<string, any>;\n headers?: string[];\n highlights?: { startLine: number; endLine: number; type: 'emit' | 'return-success' | 'return-warning'; }[];\n } {\n const responseTypes: Record<string, any> = {};\n const headers: string[] = [];\n const highlights: { startLine: number; endLine: number; type: 'emit' | 'return-success' | 'return-warning'; }[] = [];\n\n // Track variables and their values (simple tracking for numeric literals)\n const variableValues = new Map<string, number | string>();\n\n // Walk the AST to find variable declarations and response calls\n const visit = (node: ts.Node) => {\n // Track variable declarations: const statusCode = 429\n if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {\n const varName = node.name.getText(sourceFile);\n if (node.initializer) {\n // Check if initializer is a numeric literal\n if (ts.isNumericLiteral(node.initializer)) {\n const value = parseInt(node.initializer.text);\n if (!isNaN(value)) {\n variableValues.set(varName, value);\n }\n }\n // Check for: const statusCode = options.statusCode || 429\n else if (ts.isBinaryExpression(node.initializer) && node.initializer.operatorToken.kind === ts.SyntaxKind.BarBarToken) {\n // Get the right side (default value)\n if (ts.isNumericLiteral(node.initializer.right)) {\n const value = parseInt(node.initializer.right.text);\n if (!isNaN(value)) {\n variableValues.set(varName, value);\n }\n }\n }\n }\n }\n\n // Detect response calls: ctx.json(..., statusCode) or ctx.json(..., 429)\n if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression)) {\n const obj = node.expression.expression.getText(sourceFile);\n const prop = node.expression.name.getText(sourceFile);\n\n if (obj === 'ctx' && ['json', 'text', 'html', 'jsx'].includes(prop)) {\n // Check if there's a second argument (status code)\n if (node.arguments.length >= 2) {\n const statusArg = node.arguments[1];\n let statusCode: number | undefined;\n\n // Case 1: Literal number: ctx.json(..., 429)\n if (ts.isNumericLiteral(statusArg)) {\n statusCode = parseInt(statusArg.text);\n }\n // Case 2: Variable reference: ctx.json(..., statusCode)\n else if (ts.isIdentifier(statusArg)) {\n const varName = statusArg.getText(sourceFile);\n const value = variableValues.get(varName);\n if (typeof value === 'number') {\n statusCode = value;\n }\n }\n\n if (statusCode && statusCode >= 100 && statusCode < 600) {\n const statusStr = String(statusCode);\n if (!responseTypes[statusStr]) {\n let description = `Error response (${statusCode})`;\n if (statusCode === 401) description = 'Unauthorized';\n else if (statusCode === 403) description = 'Forbidden';\n else if (statusCode === 429) description = 'Too Many Requests';\n else if (statusCode === 500) description = 'Internal Server Error';\n\n const content: Record<string, any> = {};\n if (prop === 'json') {\n content['application/json'] = { schema: { type: 'object' } };\n } else if (prop === 'text') {\n content['text/plain'] = { schema: { type: 'string' } };\n } else if (prop === 'html' || prop === 'jsx') {\n content['text/html'] = { schema: { type: 'string' } };\n }\n\n responseTypes[statusStr] = {\n description,\n ...(Object.keys(content).length > 0 ? { content } : {})\n };\n }\n }\n }\n }\n\n // Detect header setting: ctx.set(\"Header-Name\", ...), res.headers.set(\"Header-Name\", ...)\n if (['set', 'header'].includes(prop)) {\n if (node.arguments.length >= 1 && ts.isStringLiteral(node.arguments[0])) {\n const headerName = node.arguments[0].text;\n if (headerName && !headers.includes(headerName)) {\n headers.push(headerName);\n }\n }\n }\n }\n\n // Recursively visit child nodes\n ts.forEachChild(node, visit);\n };\n\n // Start traversal\n visit(middleware);\n\n // Detect common rate-limit specific headers (fallback regex check on source string)\n const middlewareSource = middleware.getText(sourceFile);\n if (middlewareSource.includes('X-RateLimit')) {\n const rateLimitHeaders = ['X-RateLimit-Limit', 'X-RateLimit-Remaining', 'X-RateLimit-Reset', 'Retry-After'];\n for (const header of rateLimitHeaders) {\n if (middlewareSource.includes(header) && !headers.includes(header)) {\n headers.push(header);\n }\n }\n }\n\n // TODO: Add highlighting for response code locations in the future\n // For now, we'll skip this to keep implementation simpler\n\n return {\n responseTypes: Object.keys(responseTypes).length > 0 ? responseTypes : undefined,\n headers: headers.length > 0 ? headers : undefined,\n highlights: highlights.length > 0 ? highlights : undefined\n };\n }\n\n /**\n * Resolve an imported middleware identifier and analyze its definition\n */\n private resolveImportedMiddlewareDefinition(middlewareName: string, sourceFile: ts.SourceFile): {\n responseTypes?: Record<string, any>;\n headers?: string[];\n } {\n // Check if this middleware is imported\n const fileImports = this.imports.get(sourceFile.fileName);\n if (!fileImports || !fileImports.has(middlewareName)) {\n return {};\n }\n\n const importInfo = fileImports.get(middlewareName)!;\n const modulePath = importInfo.modulePath;\n\n // Skip external/node_modules imports for now\n if (!modulePath.startsWith('.')) {\n return {};\n }\n\n // Resolve the absolute path\n const dir = path.dirname(sourceFile.fileName);\n let absolutePath = path.resolve(dir, modulePath);\n\n // Try to find the file with different extensions\n const extensions = ['.ts', '.js', '.tsx', '.jsx', '/index.ts', '/index.js'];\n let resolvedPath: string | undefined;\n\n for (const ext of extensions) {\n const testPath = absolutePath + ext;\n if (fs.existsSync(testPath)) {\n resolvedPath = testPath;\n break;\n }\n }\n\n if (!resolvedPath && fs.existsSync(absolutePath)) {\n resolvedPath = absolutePath;\n }\n\n if (!resolvedPath) {\n return {};\n }\n\n // Get the source file for the imported module\n const importedSourceFile = this.program?.getSourceFile(resolvedPath);\n if (!importedSourceFile) {\n return {};\n }\n\n // Find the exported function/variable that matches our import\n let middlewareNode: ts.Node | undefined;\n\n const exportName = importInfo.exportName || middlewareName;\n\n ts.forEachChild(importedSourceFile, (node) => {\n // Handle: export function RateLimitMiddleware(...) { ... }\n if (ts.isFunctionDeclaration(node) && node.name?.getText(importedSourceFile) === exportName) {\n const modifiers = node.modifiers;\n if (modifiers?.some(m => m.kind === ts.SyntaxKind.ExportKeyword)) {\n middlewareNode = node;\n }\n }\n\n // Handle: export const RateLimitMiddleware = (...) => { ... }\n if (ts.isVariableStatement(node)) {\n const modifiers = node.modifiers;\n if (modifiers?.some(m => m.kind === ts.SyntaxKind.ExportKeyword)) {\n for (const declaration of node.declarationList.declarations) {\n if (ts.isIdentifier(declaration.name) && declaration.name.getText(importedSourceFile) === exportName) {\n middlewareNode = declaration.initializer;\n }\n }\n }\n }\n });\n\n if (!middlewareNode) {\n return {};\n }\n\n // Analyze the middleware definition\n return this.analyzeMiddleware(middlewareNode, importedSourceFile);\n }\n\n /**\n * Check if a reference is to an external dependency\n */\n private checkIfExternalDependency(identifier: string, sourceFile: ts.SourceFile): DependencyInfo | undefined {\n // This is a simplified check - in a full implementation, \n // we'd track imports and resolve them\n\n // For now, check if there's an import statement for this identifier\n const imports: ts.ImportDeclaration[] = [];\n\n ts.forEachChild(sourceFile, (node) => {\n if (ts.isImportDeclaration(node)) {\n imports.push(node);\n }\n });\n\n for (let i = 0; i < imports.length; i++) {\n const imp = imports[i];\n const moduleSpecifier = imp.moduleSpecifier;\n if (ts.isStringLiteral(moduleSpecifier)) {\n const modulePath = moduleSpecifier.text;\n\n // Check if it's a node_modules import (no relative path)\n if (!modulePath.startsWith('.') && !modulePath.startsWith('/')) {\n const namedBindings = imp.importClause?.namedBindings;\n\n if (namedBindings && ts.isNamedImports(namedBindings)) {\n for (let j = 0; j < namedBindings.elements.length; j++) {\n const element = namedBindings.elements[j];\n if (element.name.text === identifier) {\n // Try to read package version\n const version = this.getPackageVersion(modulePath);\n\n return {\n packageName: modulePath,\n version,\n importPath: modulePath,\n isExternal: true\n };\n }\n }\n }\n }\n }\n }\n\n return undefined;\n }\n\n /**\n * Get package version from package.json\n */\n private getPackageVersion(packageName: string): string | undefined {\n try {\n const packageJsonPath = path.join(this.rootDir, 'node_modules', packageName, 'package.json');\n if (fs.existsSync(packageJsonPath)) {\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));\n return packageJson.version;\n }\n } catch (e) {\n // Ignore\n }\n return undefined;\n }\n\n /**\n * Generate OpenAPI specification\n */\n public generateOpenAPISpec(): any {\n const paths: Record<string, any> = {};\n\n const collectRoutes = (app: ApplicationInstance, prefix: string = '') => {\n // Add direct routes\n for (let i = 0; i < app.routes.length; i++) {\n const route = app.routes[i];\n // Ensure prefix handles slashes correctly\n const cleanPrefix = prefix.endsWith('/') ? prefix.slice(0, -1) : prefix;\n const cleanPath = route.path.startsWith('/') ? route.path : '/' + route.path;\n const fullPath = (cleanPrefix + cleanPath) || '/';\n\n // Normalization is already done in extractRouteFromCall, but double check\n const pathKey = fullPath.replace(/:([a-zA-Z0-9_]+)/g, '{$1}');\n\n if (!paths[pathKey]) {\n paths[pathKey] = {};\n }\n\n const method = route.method.toLowerCase();\n const operation: any = {\n summary: route.summary || `${route.method.toUpperCase()} ${pathKey}`,\n description: route.description,\n tags: route.tags,\n operationId: route.operationId,\n responses: {\n '200': {\n description: 'Successful response'\n }\n }\n };\n\n // Clean up undefined\n if (!operation.description) delete operation.description;\n if (!operation.tags) delete operation.tags;\n if (!operation.operationId) delete operation.operationId;\n\n // Add inferred response schema\n if (route.responseSchema) {\n operation.responses['200'].content = {\n 'application/json': {\n schema: route.responseSchema\n }\n };\n } else if (route.responseType) {\n // Fallback to basic type\n const contentType = route.responseType === 'string' ? 'text/plain' : 'application/json';\n operation.responses['200'].content = {\n [contentType]: {\n schema: { type: route.responseType }\n }\n };\n } else {\n // Default object\n operation.responses['200'].content = {\n 'application/json': {\n schema: { type: 'object' }\n }\n };\n }\n\n // Add request body schema if available\n if (route.requestTypes?.body) {\n operation.requestBody = {\n content: {\n 'application/json': {\n schema: route.requestTypes.body\n }\n }\n };\n }\n\n // Add query/path parameters\n const parameters: any[] = [];\n\n if (route.requestTypes?.query) {\n const entries = Object.entries(route.requestTypes.query);\n for (let i = 0; i < entries.length; i++) {\n const [key] = entries[i];\n parameters.push({\n name: key,\n in: 'query',\n schema: { type: 'string' }\n });\n }\n }\n\n if (route.requestTypes?.params) {\n // Also check for path params implied by the URL {param}\n // But assume extractRouteFromCall handled explicit ones?\n // Let's just trust requestTypes for now\n const entries = Object.entries(route.requestTypes.params);\n for (let i = 0; i < entries.length; i++) {\n const [key] = entries[i];\n parameters.push({\n name: key,\n in: 'path',\n required: true,\n schema: { type: 'string' }\n });\n }\n }\n\n // Extract params from path if not explicitly typed but present in URL\n // This backfills untyped params so they appear in spec\n const pathParams = pathKey.match(/{([^}]+)}/g);\n if (pathParams) {\n pathParams.forEach(p => {\n const name = p.slice(1, -1);\n if (!parameters.some(param => param.name === name && param.in === 'path')) {\n parameters.push({\n name,\n in: 'path',\n required: true,\n schema: { type: 'string' } // Default to string\n });\n }\n });\n }\n\n if (parameters.length > 0) {\n operation.parameters = parameters;\n }\n\n paths[pathKey][method] = operation;\n }\n\n // Recurse into mounted apps\n for (let i = 0; i < app.mounted.length; i++) {\n const mount = app.mounted[i];\n // We need to resolve the ApplicationInstance for the target\n // The 'mounted' array currently only stores { prefix, target, dependency }\n // We need to find the AppInstance that matches 'target' class name\n\n // Note: This simple matching by class name might be brittle if multiple files have same class name\n // In a full implementation we would resolve the file path.\n const mountedApp = this.applications.find(a => a.name === mount.target || a.className === mount.target);\n\n if (mountedApp) {\n // Prevent infinite recursion\n if (mountedApp === app) continue;\n\n const cleanPrefix = prefix.endsWith('/') ? prefix.slice(0, -1) : prefix;\n const mountPrefix = mount.prefix.startsWith('/') ? mount.prefix : '/' + mount.prefix;\n const nextPrefix = cleanPrefix + mountPrefix;\n\n collectRoutes(mountedApp, nextPrefix);\n }\n }\n };\n\n for (let i = 0; i < this.applications.length; i++) {\n const app = this.applications[i];\n // We only want to start collection from \"root\" apps? \n // Or just collect everything? \n // If we collect everything, we might duplicate routes if they are mounted.\n // Current findApplications finds ALL instances.\n\n // Heuristic: If this app is mounted by another app, don't collect it as root.\n // But we don't have back-references easily.\n // Simplified: Just collect everything for now, but realize that un-mounted routers might show up as root.\n // Ideally we need to find the \"Main\" app (root).\n\n // For now, let's collect all, but we might have duplicates if we traverse mounts.\n // Let's rely on the user to only have one Main entrypoint usually.\n // Or we can try to detect if it is mounted.\n\n const isMounted = this.applications.some(parent =>\n parent.mounted.some(m => m.target === app.name || m.target === app.className)\n );\n\n if (!isMounted) {\n collectRoutes(app);\n }\n }\n\n return {\n openapi: '3.1.0',\n info: {\n title: 'Shokupan API',\n version: '1.0.0',\n description: 'Auto-generated from Shokupan application analysis'\n },\n paths,\n components: {\n schemas: {}\n }\n };\n }\n}\n\n/**\n * Analyze a directory and generate OpenAPI spec\n */\nexport async function analyzeDirectory(directory: string): Promise<any> {\n const analyzer = new OpenAPIAnalyzer(directory);\n return await analyzer.analyze();\n}\n"],"names":["node","path","i"],"mappings":";;;;;AAyGO,MAAM,gBAAgB;AAAA,EAQzB,YAAoB,SAAiB,YAA6B,QAAiB;AAA/D,SAAA,UAAA;AAA8C,SAAA,SAAA;AAC9D,QAAI,YAAY;AACZ,WAAK,aAAa,KAAK,QAAQ,UAAU;AAAA,IAC7C;AAAA,EACJ;AAAA,EAXQ,QAAyB,CAAA;AAAA,EACzB,eAAsC,CAAA;AAAA,EACtC;AAAA,EACA;AAAA;AAAA,EAEA,8BAAsF,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EActF;AAAA;AAAA;AAAA;AAAA,EAKR,MAAa,UAA6D;AACtE,QAAI,KAAK,cAAc;AACnB,aAAO,KAAK;AAAA,IAChB;AAKA,UAAM,KAAK,qBAAA;AAGX,UAAM,KAAK,kBAAA;AAGX,UAAM,KAAK,eAAA;AAGX,UAAM,KAAK,iBAAA;AAGX,UAAM,KAAK,cAAA;AAGX,SAAK,kBAAA;AAEL,SAAK,eAAe,EAAE,cAAc,KAAK,aAAA;AAGzC,WAAO,KAAK;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKQ,oBAA0B;AAC9B,UAAM,gCAAgB,IAAA;AACtB,UAAM,QAA+B,CAAA;AAGrC,eAAW,OAAO,KAAK,cAAc;AACjC,UAAI,IAAI,SAAS,iBAAiB;AAC9B,kBAAU,IAAI,IAAI,QAAQ;AAC1B,cAAM,KAAK,GAAG;AAAA,MAClB;AAAA,IACJ;AAGA,WAAO,MAAM,SAAS,GAAG;AACrB,YAAM,MAAM,MAAM,MAAA;AAElB,iBAAW,SAAS,IAAI,SAAS;AAC7B,YAAI,MAAM,kBAAkB,CAAC,UAAU,IAAI,MAAM,cAAc,GAAG;AAC9D,oBAAU,IAAI,MAAM,cAAc;AAGlC,gBAAM,aAAa,KAAK,aAAa,KAAK,OAAK,EAAE,aAAa,MAAM,cAAc;AAClF,cAAI,YAAY;AACZ,kBAAM,KAAK,UAAU;AAAA,UACzB;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAGqB,SAAK,aAAa;AACvC,SAAK,eAAe,KAAK,aAAa,OAAO,CAAA,QAAO;AAChD,UAAI,IAAI,SAAS,mBAAmB,CAAC,UAAU,IAAI,IAAI,QAAQ,GAAG;AAG9D,cAAM,SAAS,IAAI,SAAS,SAAS,UAAU,KAAK,IAAI,SAAS,SAAS,UAAU,KAAK,IAAI,SAAS,SAAS,YAAY;AAC3H,YAAI,QAAQ;AACR,iBAAO;AAAA,QACX;AAGA,eAAO;AAAA,MACX;AACA,aAAO;AAAA,IACX,CAAC;AAAA,EAGL;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,cAAc,KAA4B;AACpD,QAAI;AACA,YAAM,UAAU,GAAG,YAAY,KAAK,EAAE,eAAe,MAAM;AAE3D,eAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACrC,cAAM,QAAQ,QAAQ,CAAC;AACvB,cAAM,WAAW,KAAK,KAAK,KAAK,MAAM,IAAI;AAG1C,YAAI,MAAM,eAAe;AACrB,cAAI,CAAC,gBAAgB,QAAQ,QAAQ,WAAW,WAAW,UAAU,WAAW,EAAE,SAAS,MAAM,IAAI,GAAG;AACpG;AAAA,UACJ;AACA,gBAAM,KAAK,cAAc,QAAQ;AAAA,QACrC,OAAO;AACH,gBAAM,MAAM,KAAK,QAAQ,MAAM,IAAI;AACnC,cAAI,CAAC,OAAO,QAAQ,QAAQ,QAAQ,QAAQ,OAAO,QAAQ,QAAQ,QAAQ,MAAM,EAAE,SAAS,GAAG,GAAG;AAC9F,iBAAK,MAAM,KAAK,EAAE,MAAM,UAAU,MAAM,IAAI,MAAM,CAAC,GAAU;AAAA,UACjE;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ,SAAS,OAAY;AAEjB,UAAI,MAAM,SAAS,YAAY,MAAM,SAAS,UAAU;AACpD,cAAM;AAAA,MACV;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,oBAAmC;AAE7C,UAAM,UAAU,KAAK,MAAM,OAAO,CAAA,MAAK,EAAE,SAAS,IAAI;AACtD,UAAM,WAAW,KAAK,MAAM,OAAO,CAAA,MAAK,EAAE,SAAS,KAAK;AAExD,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACrC,YAAM,SAAS,QAAQ,CAAC;AACxB,YAAM,UAAU,SAAS,KAAK,CAAA,MAAK,EAAE,SAAS,OAAO,OAAO,MAAM;AAElE,UAAI,WAAW,CAAC,KAAK,MAAM,KAAK,CAAA,MAAK,EAAE,SAAS,OAAO,KAAK,QAAQ,SAAS,KAAK,CAAC,GAAG;AAIlF,aAAK,QAAQ,MAAM,mBAAmB,eAAe,OAAO,IAAI,2DAA2D;AAAA,MAC/H;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,iBAAgC;AAC1C,QAAI,CAAC,KAAK,QAAS;AAEnB,eAAW,cAAc,KAAK,QAAQ,eAAA,GAAkB;AACpD,UAAI,WAAW,SAAS,SAAS,cAAc,EAAG;AAClD,UAAI,WAAW,kBAAmB;AAElC,YAAM,kCAAkB,IAAA;AAExB,SAAG,aAAa,YAAY,CAAC,SAAS;AAClC,YAAI,GAAG,oBAAoB,IAAI,GAAG;AAC9B,gBAAM,kBAAkB,KAAK;AAC7B,cAAI,GAAG,gBAAgB,eAAe,GAAG;AACrC,kBAAM,aAAa,gBAAgB;AAGnC,gBAAI,KAAK,cAAc,MAAM;AACzB,oBAAM,eAAe,KAAK,aAAa,KAAK,QAAQ,UAAU;AAC9D,0BAAY,IAAI,cAAc,EAAE,YAAY,YAAY,WAAW;AAAA,YACvE;AAGA,gBAAI,KAAK,cAAc,iBAAiB,GAAG,eAAe,KAAK,aAAa,aAAa,GAAG;AACxF,yBAAW,WAAW,KAAK,aAAa,cAAc,UAAU;AAC5D,sBAAM,eAAe,QAAQ,KAAK,QAAQ,UAAU;AACpD,sBAAM,aAAa,QAAQ,cAAc,QAAQ,UAAU,KAAK;AAChE,4BAAY,IAAI,cAAc,EAAE,YAAY,YAAY;AAAA,cAC5D;AAAA,YACJ;AAGA,gBAAI,KAAK,cAAc,iBAAiB,GAAG,kBAAkB,KAAK,aAAa,aAAa,GAAG;AAC3F,oBAAM,eAAe,KAAK,aAAa,cAAc,KAAK,QAAQ,UAAU;AAC5E,0BAAY,IAAI,cAAc,EAAE,YAAY,YAAY,KAAK;AAAA,YACjE;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ,CAAC;AAED,UAAI,YAAY,OAAO,GAAG;AACtB,aAAK,QAAQ,IAAI,WAAW,UAAU,WAAW;AAAA,MACrD;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,uBAAsC;AAChD,QAAI,YAAsB,CAAA;AAE1B,QAAI,KAAK,YAAY;AAEjB,kBAAY,CAAC,KAAK,UAAU;AAAA,IAEhC,OAAO;AAEH,YAAM,KAAK,cAAc,KAAK,OAAO;AACrC,YAAM,UAAU,KAAK,MAAM,OAAO,CAAA,MAAK,EAAE,SAAS,QAAQ,EAAE,SAAS,IAAI;AACzE,kBAAY,QAAQ,IAAI,CAAA,MAAK,EAAE,IAAI;AAAA,IAEvC;AAGA,SAAK,UAAU,GAAG,cAAc,WAAW;AAAA,MACvC,QAAQ,GAAG,aAAa;AAAA,MACxB,QAAQ,GAAG,WAAW;AAAA,MACtB,SAAS;AAAA,MACT,kBAAkB,GAAG,qBAAqB;AAAA,MAC1C,SAAS,KAAK;AAAA,MACd,cAAc;AAAA,MACd,qBAAqB;AAAA,IAAA,CACxB;AAGD,QAAI,KAAK,YAAY;AACjB,WAAK,QAAQ,KAAK,QAAQ,eAAA,EACrB,OAAO,CAAA,OAAM,CAAC,GAAG,SAAS,SAAS,cAAc,CAAC,EAClD,IAAI,CAAA,QAAO,EAAE,MAAM,GAAG,UAAU,MAAM,GAAG,SAAS,SAAS,KAAK,IAAI,OAAO,KAAA,EAAO;AAAA,IAC3F;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,mBAAkC;AAC5C,QAAI,CAAC,KAAK,QAAS;AAEnB,UAAM,cAAc,KAAK,QAAQ,eAAA;AAEjC,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,eAAA,EAAiB,QAAQ,KAAK;AAC3D,YAAM,aAAa,KAAK,QAAQ,eAAA,EAAiB,CAAC;AAElD,UAAI,WAAW,SAAS,SAAS,cAAc,EAAG;AAClD,UAAI,WAAW,kBAAmB;AAKlC,YAAM,YAAY,KAAK,QAAQ,SAAS,QAAQ,KAC5C,KAAK,QAAQ,SAAS,SAAS,KAC/B,KAAK,QAAQ,SAAS,YAAY,KACjC,KAAK,eAAe,KAAK,WAAW,SAAS,QAAQ,KAAK,KAAK,WAAW,SAAS,SAAS;AAEjG,YAAM,gBAAgB,WAAW,SAAS,SAAS,YAAY;AAC/D,YAAM,eAAe,KAAK,cAAc,WAAW,aAAa,KAAK;AAIrE,UAAI,CAAC,aAAa,CAAC,iBAAiB,CAAC,cAAc;AAC/C,YAAI,WAAW,SAAS,SAAS,QAAQ,KAAK,WAAW,SAAS,SAAS,SAAS,GAAG;AAEnF;AAAA,QACJ;AACA,YAAI,WAAW,SAAS,SAAS,aAAa,EAAG;AACjD,YAAI,WAAW,SAAS,SAAS,UAAU,KAAK,WAAW,SAAS,SAAS,UAAU,EAAG;AAAA,MAC9F;AAEA,SAAG,aAAa,YAAY,CAAC,SAAS;AAClC,aAAK,UAAU,MAAM,YAAY,WAAW;AAAA,MAChD,CAAC;AAAA,IACL;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKQ,UAAU,MAAe,YAA2B,aAAmC;AAE3F,QAAI,GAAG,mBAAmB,IAAI,GAAG;AAE7B,UAAI,eAAe;AACnB,UAAI;AACJ,UAAI,YAAY,KAAK,MAAM,QAAQ,UAAU;AAE7C,YAAM,aAA8B,KAAa,cAAc,KAAK,WAAW,OAAO,CAAC,MAAW,GAAG,YAAY,CAAC,CAAC;AAEnH,UAAI,YAAY;AACZ,cAAM,sBAAsB,WAAW,KAAK,CAAC,MAAW;AACpD,gBAAM,OAAO,EAAE;AACf,cAAI,GAAG,iBAAiB,IAAI,GAAG;AAC3B,kBAAM,aAAa,KAAK,WAAW,QAAQ,UAAU;AACrD,mBAAO,eAAe;AAAA,UAC1B;AACA,iBAAO;AAAA,QACX,CAAC;AACD,YAAI,qBAAqB;AACrB,yBAAe;AACf,gBAAM,OAAO,oBAAoB;AACjC,cAAI,KAAK,UAAU,SAAS,KAAK,GAAG,gBAAgB,KAAK,UAAU,CAAC,CAAC,GAAG;AACpE,+BAAmB,KAAK,UAAU,CAAC,EAAE;AAAA,UACzC;AAAA,QACJ;AAAA,MACJ;AAGA,UAAI,CAAC,cAAc;AACf,cAAM,qBAAqB,KAAK,QAAQ,KAAK,CAAA,MAAK;AAE9C,cAAI,GAAG,oBAAoB,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,SAAS,OAAO,EAAE,SAAS,KAAK;AACjF,kBAAM,OAAQ,EAAU,cAAe,EAAU,WAAW,OAAO,CAAC,QAAa,GAAG,YAAY,GAAG,CAAC;AACpG,gBAAI,MAAM;AACN,qBAAO,KAAK,KAAK,CAAC,MAAW;AACzB,sBAAM,OAAO,EAAE;AACf,oBAAI,GAAG,iBAAiB,IAAI,GAAG;AAC3B,wBAAM,aAAa,KAAK,WAAW,QAAQ,UAAU;AACrD,yBAAO,CAAC,OAAO,QAAQ,OAAO,UAAU,SAAS,WAAW,QAAQ,OAAO,EAAE,SAAS,WAAW,aAAa;AAAA,gBAClH;AACA,uBAAO;AAAA,cACX,CAAC;AAAA,YACL;AAAA,UACJ;AACA,iBAAO;AAAA,QACX,CAAC;AACD,YAAI,oBAAoB;AACpB,yBAAe;AAAA,QACnB;AAAA,MACJ;AAEA,UAAI,gBAAgB,WAAW;AAC3B,aAAK,aAAa,KAAK;AAAA,UACnB,MAAM;AAAA,UACN,UAAU,WAAW;AAAA,UACrB,WAAW;AAAA,UACX;AAAA,UACA,QAAQ,CAAA;AAAA,UACR,SAAS,CAAA;AAAA,UACT,YAAY,CAAA;AAAA,QAAC,CAChB;AAAA,MACL;AAAA,IACJ;AAEA,QAAI,GAAG,sBAAsB,IAAI,KAAK,KAAK,aAAa;AACpD,UAAI,GAAG,gBAAgB,KAAK,WAAW,GAAG;AACtC,cAAM,OAAO,KAAK;AAClB,cAAM,YAAY,KAAK,WAAW,QAAQ,UAAU;AAEpD,YAAI,cAAc,cAAc,cAAc,oBAAoB,cAAc,2BAA2B;AACvG,gBAAM,UAAU,KAAK,KAAK,QAAQ,UAAU;AAE5C,eAAK,aAAa,KAAK;AAAA,YACnB,MAAM;AAAA,YACN,UAAU,WAAW;AAAA,YACrB;AAAA,YACA,QAAQ,CAAA;AAAA,YACR,SAAS,CAAA;AAAA,YACT,YAAY,CAAA;AAAA,UAAC,CAChB;AAAA,QACL;AAAA,MACJ;AAAA,IACJ;AAGA,QAAI,GAAG,iBAAiB,IAAI,GAAG;AAC3B,YAAM,OAAO,KAAK;AAClB,UAAI,GAAG,2BAA2B,IAAI,GAAG;AACrC,cAAM,SAAS,KAAK,KAAK,QAAQ,UAAU;AAC3C,YAAI,CAAC,OAAO,QAAQ,OAAO,UAAU,SAAS,WAAW,QAAQ,SAAS,IAAI,EAAE,SAAS,MAAM,GAAG;AAC9F,gBAAM,WAAW,KAAK,aAAa,KAAK,OAAK,EAAE,aAAa,WAAW,QAAQ;AAC/E,cAAI,CAAC,UAAU;AACX,iBAAK,aAAa,KAAK;AAAA,cACnB,MAAM;AAAA,cACN,UAAU,WAAW;AAAA,cACrB,WAAW;AAAA,cACX,QAAQ,CAAA;AAAA,cACR,SAAS,CAAA;AAAA,cACT,YAAY,CAAA;AAAA,YAAC,CAChB;AAAA,UACL;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAGA,OAAG,aAAa,MAAM,CAAC,UAAU,KAAK,UAAU,OAAO,YAAY,WAAW,CAAC;AAAA,EACnF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,gBAA+B;AACzC,QAAI,CAAC,KAAK,QAAS;AAEnB,aAAS,IAAI,GAAG,IAAI,KAAK,aAAa,QAAQ,KAAK;AAC/C,YAAM,MAAM,KAAK,aAAa,CAAC;AAC/B,YAAM,aAAa,KAAK,QAAQ,cAAc,IAAI,QAAQ;AAC1D,UAAI,CAAC,WAAY;AAEjB,WAAK,sBAAsB,KAAK,UAAU;AAAA,IAC9C;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKQ,4BAA4B,KAA0B,WAAgC,YAAiC;AAC3H,UAAM,UAAU,UAAU,QAAQ,OAAO,CAAA,MAAK,GAAG,oBAAoB,CAAC,KAAK,EAAE,SAAS,GAAG;AAEzF,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACrC,YAAM,SAAS,QAAQ,CAAC;AACxB,YAAM,aAAa;AACnB,UAAI,CAAC,WAAW,cAAc,CAAC,WAAW,UAAW;AAErD,YAAM,aAAa,WAAW,cAAc,WAAW,WAAW,OAAO,CAAC,MAAW,GAAG,YAAY,CAAC,CAAC;AACtG,UAAI,CAAC,WAAY;AAGjB,YAAM,iBAAiB,WAAW,KAAK,CAAC,MAAW;AAC/C,cAAM,OAAO,EAAE;AACf,YAAI,GAAG,iBAAiB,IAAI,GAAG;AAC3B,gBAAM,aAAa,KAAK,WAAW,QAAQ,UAAU;AACrD,iBAAO,CAAC,OAAO,QAAQ,OAAO,UAAU,SAAS,WAAW,QAAQ,OAAO,EAAE,SAAS,WAAW,aAAa;AAAA,QAClH;AACA,eAAO;AAAA,MACX,CAAC;AAED,UAAI,kBAAkB,GAAG,iBAAiB,eAAe,UAAU,GAAG;AAClE,cAAM,gBAAgB,eAAe,WAAW,WAAW,QAAQ,UAAU;AAC7E,cAAM,aAAa,cAAc,YAAA;AACjC,YAAI,YAAY;AAGhB,cAAM,UAAU,eAAe,WAAW,UAAU,CAAC;AACrD,YAAI,WAAW,GAAG,gBAAgB,OAAO,GAAG;AACxC,sBAAY,QAAQ;AAAA,QACxB;AAGA,oBAAY,UAAU,QAAQ,qBAAqB,MAAM;AAGzD,cAAM,cAAc,GAAG,IAAI,IAAI,IAAI,WAAW,KAAK,QAAQ,UAAU,CAAC;AAGtE,cAAM,WAAW,KAAK,eAAe,YAAY,YAAY,UAAU;AAEvE,YAAI,OAAO,KAAK;AAAA,UACZ,QAAQ;AAAA,UACR,MAAM;AAAA,UACN;AAAA,UACA,eAAe,WAAW,QAAQ,UAAU;AAAA,UAC5C,cAAc,SAAS;AAAA,UACvB,cAAc,SAAS;AAAA,UACvB,gBAAgB,SAAS;AAAA,UACzB,kBAAkB,SAAS;AAAA,UAC3B,OAAO,SAAS;AAAA,UAChB,eAAe;AAAA,YACX,MAAM,WAAW;AAAA,YACjB,WAAW,WAAW,8BAA8B,WAAW,SAAA,CAAU,EAAE,OAAO;AAAA,YAClF,SAAS,WAAW,8BAA8B,WAAW,OAAA,CAAQ,EAAE,OAAO;AAAA,YAC9E,YAAY,SAAS;AAAA,UAAA;AAAA,QACzB,CACH;AAAA,MACL;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKQ,sBAAsB,KAA0B,YAAiC;AACrF,QAAI,IAAI,cAAc,cAAc;AAChC,YAAM,YAAY,WAAW,WAAW,KAAK,OAAK,GAAG,mBAAmB,CAAC,KAAK,EAAE,MAAM,QAAQ,UAAU,MAAM,IAAI,IAAI;AACtH,UAAI,WAAW;AACX,aAAK,4BAA4B,KAAK,WAAW,UAAU;AAAA,MAC/D;AAAA,IACJ,OAAO;AAEH,YAAM,QAAQ,CAAC,SAAkB;AAE7B,YAAI,GAAG,iBAAiB,IAAI,GAAG;AAC3B,cAAI,GAAG,2BAA2B,KAAK,UAAU,GAAG;AAChD,kBAAM,UAAU,KAAK,WAAW,WAAW,QAAQ,UAAU;AAC7D,kBAAM,aAAa,KAAK,WAAW,KAAK,QAAQ,UAAU;AAI1D,gBAAI,YAAY,IAAI,QAAS,IAAI,SAAS,mBAAmB,KAAK,UAAU,UAAU,GAAI;AACtF,kBAAI,CAAC,OAAO,QAAQ,OAAO,UAAU,SAAS,WAAW,QAAQ,MAAM,OAAO,EAAE,SAAS,WAAW,YAAA,CAAa,GAAG;AAEhH,sBAAM,QAAQ,KAAK,qBAAqB,MAAM,YAAY,WAAW,aAAa;AAClF,oBAAI,OAAO;AACP,sBAAI,OAAO,KAAK,KAAK;AAAA,gBACzB;AAAA,cACJ,WAAW,eAAe,SAAS;AAE/B,sBAAM,QAAQ,KAAK,qBAAqB,MAAM,UAAU;AACxD,oBAAI,OAAO;AACP,sBAAI,QAAQ,KAAK,KAAK;AAAA,gBAC1B;AAAA,cACJ,WAAW,eAAe,OAAO;AAE7B,sBAAM,aAAa,KAAK,0BAA0B,MAAM,UAAU;AAClE,oBAAI,YAAY;AAEZ,sBAAI,IAAI,cAAc,YAAY;AAC9B,+BAAW,QAAQ;AAAA,kBACvB;AACA,sBAAI,WAAW,KAAK,UAAU;AAAA,gBAClC;AAAA,cACJ;AAAA,YACJ;AAAA,UACJ;AAAA,QACJ;AAEA,WAAG,aAAa,MAAM,KAAK;AAAA,MAC/B;AAEA,SAAG,aAAa,YAAY,KAAK;AAAA,IACrC;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKQ,mBAAmB,MAAe,YAA0C;AAChF,QAAI,GAAG,gBAAgB,IAAI,GAAG;AAC1B,aAAO,KAAK;AAAA,IAChB;AACA,QAAI,GAAG,gCAAgC,IAAI,GAAG;AAC1C,aAAO,KAAK;AAAA,IAChB;AACA,QAAI,GAAG,qBAAqB,IAAI,GAAG;AAC/B,UAAI,SAAS,KAAK,KAAK;AACvB,iBAAW,QAAQ,KAAK,eAAe;AACnC,cAAM,MAAM,KAAK,mBAAmB,KAAK,YAAY,UAAU;AAC/D,YAAI,QAAQ,KAAM,QAAO;AACzB,kBAAU,MAAM,KAAK,QAAQ;AAAA,MACjC;AACA,aAAO;AAAA,IACX;AACA,QAAI,GAAG,mBAAmB,IAAI,KAAK,KAAK,cAAc,SAAS,GAAG,WAAW,WAAW;AACpF,YAAM,OAAO,KAAK,mBAAmB,KAAK,MAAM,UAAU;AAC1D,YAAM,QAAQ,KAAK,mBAAmB,KAAK,OAAO,UAAU;AAC5D,UAAI,SAAS,QAAQ,UAAU,MAAM;AACjC,eAAO,OAAO;AAAA,MAClB;AACA,aAAO;AAAA,IACX;AACA,QAAI,GAAG,0BAA0B,IAAI,GAAG;AACpC,aAAO,KAAK,mBAAmB,KAAK,YAAY,UAAU;AAAA,IAC9D;AACA,QAAI,GAAG,aAAa,IAAI,GAAG;AACvB,UAAI,KAAK,SAAS;AACd,cAAM,UAAU,KAAK,QAAQ,eAAA;AAC7B,cAAM,SAAS,QAAQ,oBAAoB,IAAI;AAC/C,YAAI,UAAU,OAAO,oBAAoB,GAAG,sBAAsB,OAAO,gBAAgB,KAAK,OAAO,iBAAiB,aAAa;AAC/H,iBAAO,KAAK,mBAAmB,OAAO,iBAAiB,aAAa,UAAU;AAAA,QAClF;AAAA,MACJ;AAAA,IAIJ;AAEA,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKQ,qBAAqB,MAAyB,YAA2B,QAAkC;AAC/G,UAAM,OAAO,KAAK;AAElB,QAAI,KAAK,SAAS,EAAG,QAAO;AAE5B,UAAM,UAAU,KAAK,CAAC;AACtB,QAAI,YAAY,KAAK,mBAAmB,SAAS,UAAU;AAE3D,QAAI,oBAAqF,CAAA;AAEzF,QAAI,CAAC,WAAW;AACZ,UAAI,CAAC,SAAS,IAAI,EAAE,SAAS,OAAO,YAAA,CAAa,GAAG;AAChD,oBAAY;AAAA,MAChB,OAAO;AACH,oBAAY;AAAA,MAChB;AAGA,YAAM,QAAQ,WAAW,8BAA8B,QAAQ,UAAU;AACzE,YAAM,MAAM,WAAW,8BAA8B,QAAQ,QAAQ;AAErE,wBAAkB,KAAK;AAAA,QACnB,WAAW,MAAM,OAAO;AAAA,QACxB,SAAS,IAAI,OAAO;AAAA,QACpB,MAAM;AAAA,MAAA,CACT;AAAA,IACL;AAIA,UAAM,iBAAiB,UAAU,QAAQ,qBAAqB,MAAM;AAEpE,QAAI,WAAgB,CAAA;AAGpB,QAAI,KAAK,UAAU,KAAK,GAAG,0BAA0B,KAAK,CAAC,CAAC,GAAG;AAC3D,YAAM,UAAU,KAAK,CAAC;AAEN,WAAK,0BAA0B,SAAS,YAAY,oBAAI,KAAK;AAO7E,eAAS,IAAI,GAAG,IAAI,QAAQ,WAAW,QAAQ,KAAK;AAChD,cAAM,OAAO,QAAQ,WAAW,CAAC;AACjC,YAAI,GAAG,qBAAqB,IAAI,KAAK,KAAK,MAAM;AAC5C,gBAAM,OAAO,KAAK,KAAK,QAAQ,UAAU;AACzC,gBAAM,MAAM,KAAK;AAEjB,cAAI,GAAG,gBAAgB,GAAG,GAAG;AACzB,qBAAS,IAAI,IAAI,IAAI;AAAA,UACzB,WAAW,GAAG,yBAAyB,GAAG,KAAK,SAAS,QAAQ;AAC5D,qBAAS,OAAO,IAAI,SACf,OAAO,CAAA,MAAK,GAAG,gBAAgB,CAAC,CAAC,EACjC,IAAI,CAAA,MAAM,EAAuB,IAAI;AAAA,UAC9C,WAAW,SAAS,iBAAiB,GAAG,gBAAgB,GAAG,GAAG;AAC1D,qBAAS,cAAc,IAAI;AAAA,UAC/B;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAGA,UAAM,aAAa,KAAK,KAAK,SAAS,CAAC;AACvC,UAAM,cAAc,KAAK,eAAe,YAAY,YAAY,MAAM;AAEtE,WAAO;AAAA,MACH;AAAA,MACA,MAAM;AAAA,MACN,aAAa,WAAW,QAAQ,UAAU,EAAE,UAAU,GAAG,EAAE;AAAA;AAAA,MAC3D,eAAe,WAAW,QAAQ,UAAU;AAAA,MAC5C,cAAc,YAAY;AAAA,MAC1B,cAAc,YAAY;AAAA,MAC1B,gBAAgB,YAAY;AAAA,MAC5B,OAAO,YAAY;AAAA,MACnB,GAAG;AAAA,MACH,eAAe;AAAA,QACX,MAAM,WAAW;AAAA,QACjB,WAAW,WAAW,8BAA8B,WAAW,SAAA,CAAU,EAAE,OAAO;AAAA,QAClF,SAAS,WAAW,8BAA8B,WAAW,OAAA,CAAQ,EAAE,OAAO;AAAA,QAC9E,YAAY,CAAC,GAAI,YAAY,cAAc,CAAA,GAAK,GAAG,iBAAiB;AAAA,MAAA;AAAA,IACxE;AAAA,EAER;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAe,SAAkB,YAA2B,QAOlE;AAEE,UAAM,cAAc,KAAK,SAAS,eAAA;AAClC,UAAM,eAA0C,CAAA;AAChD,QAAI;AACJ,QAAI,kBAAyB,CAAA;AAC7B,QAAI,wBAAwB;AAC5B,UAAM,QAAiG,CAAA;AACvG,UAAM,aAA4G,CAAA;AAGlH,UAAM,4BAAY,IAAA;AAGlB,QAAI,GAAG,eAAe,OAAO,GAAG;AAC5B,cAAQ,WAAW,QAAQ,CAAC,OAAO,UAAU;AACzC,YAAI,GAAG,aAAa,MAAM,IAAI,KAAK,MAAM,MAAM;AAC3C,gBAAM,YAAY,MAAM,KAAK,QAAQ,UAAU;AAG/C,gBAAM,YAAY,KAAK,wBAAwB,MAAM,MAAM,UAAU;AACrE,cAAI,WAAW;AACX,kBAAM,IAAI,WAAW,SAAS;AAG9B,iBAAK,WAAW,WAAW,WAAW,SAAS,UAAU,GAAG;AACxD,2BAAa,OAAO;AAAA,YACxB;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ,CAAC;AAGD,UAAI,QAAQ,MAAM;AACd,cAAM,eAAe,KAAK,wBAAwB,QAAQ,MAAM,UAAU;AAC1E,YAAI,cAAc;AACd,0BAAgB,KAAK,YAAY;AACjC,yBAAe,aAAa;AAC5B,kCAAwB;AAAA,QAC5B;AAAA,MACJ;AAAA,IACJ;AAGA,UAAM,0BAA0B,CAAC,SAAwB;AACrD,UAAI,OAAO;AAEX,UAAI,GAAG,kBAAkB,IAAI,GAAG;AAC5B,eAAO,KAAK;AAAA,MAChB;AAIA,UAAI,GAAG,iBAAiB,IAAI,KAAK,GAAG,2BAA2B,KAAK,UAAU,GAAG;AAC7E,cAAM,UAAU,KAAK,WAAW,WAAW,QAAQ,UAAU;AAC7D,cAAM,WAAW,KAAK,WAAW,KAAK,QAAQ,UAAU;AAExD,YAAI,YAAY,SAAS,QAAQ,SAAS,MAAM,GAAG;AAC/C,cAAI,aAAa,QAAQ;AACrB,gBAAI,KAAK,UAAU,SAAS,GAAG;AAC3B,oBAAM,SAAS,KAAK,0BAA0B,KAAK,UAAU,CAAC,GAAG,YAAY,OAAO,WAAW;AAC/F,8BAAgB,KAAK,MAAM;AAC3B,6BAAe;AAAA,YACnB;AACA;AAAA,UACJ,WACS,aAAa,QAAQ;AAC1B,2BAAe;AACf;AAAA,UACJ,WACS,aAAa,UAAU,aAAa,OAAO;AAChD,2BAAe;AACf;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ;AAKA,UAAI,CAAC,yBAAyB,gBAAgB,WAAW,GAAG;AACxD,cAAM,SAAS,KAAK,0BAA0B,MAAM,YAAY,OAAO,WAAW;AAClF,YAAI,WAAW,OAAO,SAAS,YAAY,OAAO,KAAK,OAAO,cAAc,CAAA,CAAE,EAAE,SAAS,IAAI;AACzF,0BAAgB,KAAK,MAAM;AAC3B,yBAAe,OAAO;AAAA,QAC1B;AAAA,MACJ;AAGA,UAAI,gBAAgB,WAAW,KAAK,CAAC,cAAc;AAC/C,cAAM,aAAa,KAAK,QAAQ,UAAU;AAC1C,YAAI,WAAW,WAAW,GAAG,GAAG;AAC5B,yBAAe;AAAA,QACnB,WAAW,WAAW,WAAW,GAAG,GAAG;AACnC,yBAAe;AAAA,QACnB,WAAW,WAAW,WAAW,GAAG,KAAK,WAAW,WAAW,GAAG,GAAG;AACjE,yBAAe;AAAA,QACnB;AAAA,MACJ;AAAA,IACJ;AAGA,QAAI;AAEJ,QAAI,GAAG,gBAAgB,OAAO,KAAK,GAAG,qBAAqB,OAAO,KAAK,GAAG,oBAAoB,OAAO,KAAK,QAAQ,SAAS,KAAK;AAE5H,aAAQ,QAAgB;AAGxB,YAAM,QAAQ,CAAC,SAAkB;AAE7B,YAAI,GAAG,sBAAsB,IAAI,GAAG;AAChC,cAAI,KAAK,aAAa;AAElB,gBAAI,GAAG,aAAa,KAAK,IAAI,GAAG;AAC5B,oBAAM,UAAU,KAAK,KAAK,QAAQ,UAAU;AAG5C,kBAAI,cAAc,KAAK;AACvB,kBAAI,GAAG,eAAe,WAAW,GAAG;AAChC,oBAAI,KAAK,cAAc,YAAY,YAAY,UAAU,GAAG;AACxD,wBAAM,SAAS,KAAK,wBAAwB,YAAY,MAAM,UAAU;AACxE,sBAAI,QAAQ;AACR,iCAAa,OAAO;AACpB,0BAAM,IAAI,SAAS,MAAM;AAAA,kBAC7B;AAAA,gBACJ,OAAO;AACH,wBAAM,SAAS,KAAK,0BAA0B,aAAa,YAAY,OAAO,WAAW;AACzF,wBAAM,IAAI,SAAS,MAAM;AAAA,gBAC7B;AAAA,cACJ,OAAO;AACH,sBAAM,SAAS,KAAK,0BAA0B,aAAa,YAAY,OAAO,WAAW;AACzF,sBAAM,IAAI,SAAS,MAAM;AAAA,cAC7B;AAAA,YACJ,WAES,GAAG,sBAAsB,KAAK,IAAI,GAAG;AAE1C,oBAAM,oBAAoB,KAAK,0BAA0B,KAAK,aAAa,YAAY,OAAO,WAAW;AAGzG,kBAAI,mBAAmB,SAAS,WAAW,kBAAkB,OAAO;AAEhE,yBAAS,IAAI,GAAG,IAAI,KAAK,KAAK,SAAS,QAAQ,KAAK;AAChD,wBAAM,UAAU,KAAK,KAAK,SAAS,CAAC;AACpC,sBAAI,GAAG,iBAAiB,OAAO,KAAK,GAAG,aAAa,QAAQ,IAAI,GAAG;AAC/D,0BAAM,cAAc,QAAQ,KAAK,QAAQ,UAAU;AACnD,0BAAM,IAAI,aAAa,kBAAkB,KAAK;AAAA,kBAClD;AAAA,gBACJ;AAAA,cACJ,OAAO;AAEH,yBAAS,IAAI,GAAG,IAAI,KAAK,KAAK,SAAS,QAAQ,KAAK;AAChD,wBAAM,UAAU,KAAK,KAAK,SAAS,CAAC;AACpC,sBAAI,GAAG,iBAAiB,OAAO,KAAK,GAAG,aAAa,QAAQ,IAAI,GAAG;AAC/D,0BAAM,cAAc,QAAQ,KAAK,QAAQ,UAAU;AACnD,0BAAM,IAAI,aAAa,EAAE,aAAa,MAAM;AAAA,kBAChD;AAAA,gBACJ;AAAA,cACJ;AAAA,YACJ,WAES,GAAG,uBAAuB,KAAK,IAAI,GAAG;AAC3C,oBAAM,oBAAoB,KAAK,0BAA0B,KAAK,aAAa,YAAY,OAAO,WAAW;AAGzG,kBAAI,mBAAmB,SAAS,YAAY,kBAAkB,YAAY;AACtE,yBAAS,IAAI,GAAG,IAAI,KAAK,KAAK,SAAS,QAAQ,KAAK;AAChD,wBAAM,UAAU,KAAK,KAAK,SAAS,CAAC;AACpC,sBAAI,GAAG,iBAAiB,OAAO,KAAK,GAAG,aAAa,QAAQ,IAAI,GAAG;AAC/D,0BAAM,cAAc,QAAQ,KAAK,QAAQ,UAAU;AACnD,0BAAM,iBAAiB,kBAAkB,WAAW,WAAW;AAC/D,0BAAM,IAAI,aAAa,kBAAkB,EAAE,aAAa,MAAM;AAAA,kBAClE;AAAA,gBACJ;AAAA,cACJ,OAAO;AAEH,yBAAS,IAAI,GAAG,IAAI,KAAK,KAAK,SAAS,QAAQ,KAAK;AAChD,wBAAM,UAAU,KAAK,KAAK,SAAS,CAAC;AACpC,sBAAI,GAAG,iBAAiB,OAAO,KAAK,GAAG,aAAa,QAAQ,IAAI,GAAG;AAC/D,0BAAM,cAAc,QAAQ,KAAK,QAAQ,UAAU;AACnD,0BAAM,IAAI,aAAa,EAAE,aAAa,MAAM;AAAA,kBAChD;AAAA,gBACJ;AAAA,cACJ;AAAA,YACJ;AAAA,UACJ;AAAA,QACJ;AAGA,YAAI,GAAG,eAAe,IAAI,GAAG;AACzB,cAAI,KAAK,cAAc,KAAK,YAAY,UAAU,GAAG;AACjD,kBAAM,SAAS,KAAK,wBAAwB,KAAK,MAAM,UAAU;AACjE,gBAAI,QAAQ;AACR,2BAAa,OAAO;AAGpB,kBAAI,GAAG,sBAAsB,KAAK,MAAM,GAAG;AACvC,sBAAM,UAAU,KAAK,OAAO,KAAK,QAAQ,UAAU;AACnD,sBAAM,IAAI,SAAS,MAAM;AAAA,cAC7B;AAAA,YACJ;AAAA,UACJ;AAAA,QACJ,WAES,KAAK,cAAc,MAAM,UAAU,GAAG;AAC3C,cAAI,CAAC,aAAa,MAAM;AACpB,yBAAa,OAAO,EAAE,MAAM,UAAU,aAAa,eAAA;AAAA,UACvD;AAAA,QACJ;AAGA,YAAI,GAAG,iBAAiB,IAAI,KAAK,GAAG,2BAA2B,KAAK,UAAU,GAAG;AAC7E,gBAAM,UAAU,KAAK,WAAW,WAAW,QAAQ,UAAU;AAC7D,gBAAM,WAAW,KAAK,WAAW,KAAK,QAAQ,UAAU;AAExD,cAAI,YAAY,SAAS,QAAQ,SAAS,MAAM,KAAK,YAAY,QAAQ;AACrE,kBAAM,YAAY,WAAW,8BAA8B,KAAK,SAAA,CAAU,EAAE,OAAO;AACnF,kBAAM,UAAU,WAAW,8BAA8B,KAAK,OAAA,CAAQ,EAAE,OAAO;AAE/E,gBAAI,CAAC,QAAQ,QAAQ,KAAK,EAAE,SAAS,QAAQ,GAAG;AAE5C,yBAAW,KAAK,EAAE,WAAW,SAAS,MAAM,kBAAkB;AAAA,YAClE,WAAW,aAAa,QAAQ;AAE5B,kBAAI,WAAW;AACf,kBAAI,KAAK,UAAU,SAAS,GAAG;AAC3B,sBAAM,SAAS,KAAK,0BAA0B,KAAK,UAAU,CAAC,GAAG,YAAY,OAAO,WAAW;AAE/F,oBAAI,WAAW,OAAO,SAAS,YAAa,OAAO,cAAc,OAAO,KAAK,OAAO,UAAU,EAAE,SAAS,IAAK;AAC1G,6BAAW;AAAA,gBACf;AAAA,cACJ;AACA,yBAAW,KAAK,EAAE,WAAW,SAAS,MAAM,WAAW,mBAAmB,kBAAkB;AAAA,YAChG,WAAW,CAAC,QAAQ,MAAM,EAAE,SAAS,QAAQ,GAAG;AAC5C,yBAAW,KAAK,EAAE,WAAW,SAAS,MAAM,QAAQ;AAAA,YACxD;AAAA,UACJ;AAAA,QACJ;AAGA,YAAI,GAAG,2BAA2B,IAAI,GAAG;AACrC,gBAAM,UAAU,KAAK,WAAW,QAAQ,UAAU;AAClD,gBAAM,WAAW,KAAK,KAAK,QAAQ,UAAU;AAE7C,cAAI,YAAY,SAAS,QAAQ,SAAS,MAAM,GAAG;AAC/C,gBAAI,aAAa,QAAQ;AACrB,kBAAI,CAAC,aAAa,MAAM;AACpB,6BAAa,OAAO,EAAE,MAAM,SAAA;AAAA,cAChC;AAAA,YACJ,WAAW,aAAa,SAAS;AAC7B,kBAAI,CAAC,aAAa,MAAO,cAAa,QAAQ,CAAA;AAE9C,kBAAI;AACJ,kBAAI;AAEJ,kBAAI,GAAG,2BAA2B,KAAK,MAAM,GAAG;AAC5C,sBAAM,KAAK,OAAO,KAAK,QAAQ,UAAU;AACzC,6BAAa,KAAK;AAAA,cACtB,WAAW,GAAG,0BAA0B,KAAK,MAAM,GAAG;AAClD,sBAAM,MAAM,KAAK,OAAO;AACxB,oBAAI,GAAG,gBAAgB,GAAG,GAAG;AACzB,wBAAM,IAAI;AACV,+BAAa,KAAK;AAAA,gBACtB;AAAA,cACJ;AAEA,kBAAI,OAAO,YAAY;AACnB,oBAAI,OAAO;AACX,sBAAM,SAAS,WAAW;AAE1B,oBAAI,GAAG,iBAAiB,MAAM,KAAK,GAAG,aAAa,OAAO,UAAU,GAAG;AACnE,wBAAM,SAAS,OAAO,WAAW,QAAQ,UAAU;AACnD,sBAAI,WAAW,WAAY,QAAO;AAAA,2BACzB,WAAW,gBAAgB,WAAW,SAAU,QAAO;AAAA,2BACvD,WAAW,UAAW,QAAO;AAAA,gBAC1C,WAES,GAAG,wBAAwB,MAAM,GAAG;AACzC,sBAAI,OAAO,aAAa,GAAG,WAAW,UAAW,QAAO;AAAA,2BAC/C,OAAO,aAAa,GAAG,WAAW,iBAAkB,QAAO;AAAA,gBACxE;AAEA,oBAAI,CAAC,aAAa,MAAM,GAAG,KAAK,aAAa,MAAM,GAAG,MAAM,UAAU;AAClE,+BAAa,MAAM,GAAG,IAAI;AAAA,gBAC9B;AAAA,cACJ;AAAA,YACJ,WAAW,aAAa,UAAU;AAC9B,kBAAI,CAAC,aAAa,OAAQ,cAAa,SAAS,CAAA;AAEhD,kBAAI;AACJ,kBAAI;AAEJ,kBAAI,GAAG,2BAA2B,KAAK,MAAM,GAAG;AAC5C,sBAAM,KAAK,OAAO,KAAK,QAAQ,UAAU;AACzC,6BAAa,KAAK;AAAA,cACtB,WAAW,GAAG,0BAA0B,KAAK,MAAM,GAAG;AAClD,sBAAM,MAAM,KAAK,OAAO;AACxB,oBAAI,GAAG,gBAAgB,GAAG,GAAG;AACzB,wBAAM,IAAI;AACV,+BAAa,KAAK;AAAA,gBACtB;AAAA,cACJ;AAEA,kBAAI,OAAO,YAAY;AACnB,oBAAI,OAAO;AACX,sBAAM,SAAS,WAAW;AAE1B,oBAAI,GAAG,iBAAiB,MAAM,KAAK,GAAG,aAAa,OAAO,UAAU,GAAG;AACnE,wBAAM,SAAS,OAAO,WAAW,QAAQ,UAAU;AACnD,sBAAI,WAAW,WAAY,QAAO;AAAA,2BACzB,WAAW,gBAAgB,WAAW,SAAU,QAAO;AAAA,2BACvD,WAAW,UAAW,QAAO;AAAA,gBAC1C,WACS,GAAG,wBAAwB,MAAM,GAAG;AACzC,sBAAI,OAAO,aAAa,GAAG,WAAW,UAAW,QAAO;AAAA,2BAC/C,OAAO,aAAa,GAAG,WAAW,iBAAkB,QAAO;AAAA,gBACxE;AAEA,oBAAI,CAAC,aAAa,OAAO,GAAG,KAAK,aAAa,OAAO,GAAG,MAAM,UAAU;AACpE,+BAAa,OAAO,GAAG,IAAI;AAAA,gBAC/B;AAAA,cACJ;AAAA,YACJ,WAAW,aAAa,WAAW;AAC/B,kBAAI,CAAC,aAAa,QAAS,cAAa,UAAU,CAAA;AAElD,kBAAI;AACJ,kBAAI,GAAG,2BAA2B,KAAK,MAAM,GAAG;AAC5C,sBAAM,KAAK,OAAO,KAAK,QAAQ,UAAU;AAAA,cAC7C,WAAW,GAAG,0BAA0B,KAAK,MAAM,GAAG;AAClD,sBAAM,MAAM,KAAK,OAAO;AACxB,oBAAI,GAAG,gBAAgB,GAAG,GAAG;AACzB,wBAAM,IAAI;AAAA,gBACd;AAAA,cACJ;AAEA,kBAAI,OAAO,CAAC,aAAa,QAAQ,GAAG,GAAG;AACnC,6BAAa,QAAQ,GAAG,IAAI;AAAA,cAChC;AAAA,YACJ;AAAA,UACJ;AAAA,QACJ;AAGA,YAAI,GAAG,kBAAkB,IAAI,GAAG;AAC5B,gBAAM,YAAY,WAAW,8BAA8B,KAAK,SAAA,CAAU,EAAE,OAAO;AACnF,gBAAM,UAAU,WAAW,8BAA8B,KAAK,OAAA,CAAQ,EAAE,OAAO;AAE/E,cAAI,WAAW;AACf,cAAI,KAAK,YAAY;AACjB,kBAAM,sBAAsB,gBAAgB;AAC5C,oCAAwB,KAAK,UAAU;AAEvC,gBAAI,gBAAgB,SAAS,qBAAqB;AAC9C,yBAAW;AAAA,YACf;AAAA,UACJ,WAAW,uBAAuB;AAE9B,uBAAW;AAAA,UACf;AAEA,qBAAW,KAAK,EAAE,WAAW,SAAS,MAAM,WAAW,mBAAmB,kBAAkB;AAAA,QAChG;AAIA,YAAI,GAAG,gBAAgB,IAAI,KAAK,CAAC,GAAG,QAAQ,KAAK,IAAI,GAAG;AAEpD,gBAAM,YAAY,WAAW,8BAA8B,KAAK,KAAK,SAAA,CAAU,EAAE,OAAO;AACxF,gBAAM,UAAU,WAAW,8BAA8B,KAAK,KAAK,OAAA,CAAQ,EAAE,OAAO;AAEpF,gBAAM,sBAAsB,gBAAgB;AAC5C,kCAAwB,KAAK,IAAqB;AAElD,cAAI,WAAW;AACf,cAAI,gBAAgB,SAAS,qBAAqB;AAC9C,uBAAW;AAAA,UACf;AAEA,qBAAW,KAAK,EAAE,WAAW,SAAS,MAAM,WAAW,mBAAmB,kBAAkB;AAAA,QAChG;AAGA,YAAI,GAAG,sBAAsB,IAAI,GAAG;AAChC,kCAAwB,KAAK,UAAU;AAGvC,cAAI,GAAG,iBAAiB,KAAK,UAAU,GAAG;AACtC,kBAAM,OAAO,KAAK;AAClB,gBAAI,GAAG,2BAA2B,KAAK,UAAU,GAAG;AAChD,oBAAM,UAAU,KAAK,WAAW,WAAW,QAAQ,UAAU;AAC7D,oBAAM,WAAW,KAAK,WAAW,KAAK,QAAQ,UAAU;AAExD,mBAAM,YAAY,SAAS,QAAQ,SAAS,MAAM,MAAO,YAAY,UAAU,QAAQ,SAAS,OAAO,OAAO,aAAa,QAAQ;AAC/H,oBAAI,KAAK,UAAU,UAAU,GAAG;AAC5B,wBAAM,eAAe,KAAK,UAAU,CAAC;AACrC,sBAAI,GAAG,gBAAgB,YAAY,GAAG;AAClC,0BAAM,YAAY,aAAa;AAC/B,wBAAI,UAAmC,EAAE,MAAM,SAAA;AAI/C,wBAAI,KAAK,cAAc,KAAK,UAAU,CAAC,GAAG,UAAU,GAAG;AACnD,gCAAU,EAAE,MAAM,UAAU,aAAa,eAAA;AAEzC,0BAAI,CAAC,aAAa,MAAM;AACpB,qCAAa,OAAO,EAAE,MAAM,SAAA;AAAA,sBAChC;AAAA,oBACJ,OAAO;AACH,gCAAU,KAAK,0BAA0B,KAAK,UAAU,CAAC,GAAG,YAAY,OAAO,WAAW;AAAA,oBAC9F;AAEA,0BAAM,UAAU;AAAA,sBACZ,WAAW,WAAW,8BAA8B,KAAK,SAAA,CAAU,EAAE,OAAO;AAAA,sBAC5E,SAAS,WAAW,8BAA8B,KAAK,OAAA,CAAQ,EAAE,OAAO;AAAA,oBAAA;AAE5E,0BAAM,KAAK,EAAE,OAAO,WAAW,SAAS,UAAU,SAAS;AAAA,kBAC/D,OAAO;AACH,0BAAM,UAAU;AAAA,sBACZ,WAAW,WAAW,8BAA8B,KAAK,SAAA,CAAU,EAAE,OAAO;AAAA,sBAC5E,SAAS,WAAW,8BAA8B,KAAK,OAAA,CAAQ,EAAE,OAAO;AAAA,oBAAA;AAE5E,0BAAM,KAAK,EAAE,OAAO,oBAAoB,SAAS,EAAE,MAAM,SAAA,GAAY,UAAU,QAAA,CAAS;AAAA,kBAC5F;AAAA,gBACJ;AAAA,cACJ;AAAA,YACJ;AAAA,UACJ;AAAA,QACJ;AAEA,WAAG,aAAa,MAAM,KAAK;AAAA,MAC/B;AAEA,UAAI,GAAG,QAAQ,IAAI,GAAG;AAClB,WAAG,aAAa,MAAM,KAAK;AAAA,MAC/B,OAAO;AAEH,gCAAwB,IAAI;AAK5B,WAAG,aAAa,MAAM,KAAK;AAAA,MAC/B;AAAA,IACJ;AAGA,QAAI;AACJ,QAAI,gBAAgB,SAAS,GAAG;AAE5B,YAAM,gBAAgB,KAAK,mBAAmB,eAAe;AAC7D,UAAI,cAAc,WAAW,GAAG;AAC5B,8BAAsB,cAAc,CAAC;AAAA,MACzC,OAAO;AAEH,8BAAsB;AAAA,UAClB,OAAO;AAAA,QAAA;AAAA,MAEf;AAAA,IACJ,WAAW,gBAAgB,WAAW,GAAG;AACrC,4BAAsB,gBAAgB,CAAC;AAAA,IAC3C;AAEA,WAAO;AAAA,MACH;AAAA,MACA;AAAA,MACA,gBAAgB;AAAA,MAChB,kBAAkB,sBAAsB,KAAK,iBAAiB,mBAAmB,IAAI;AAAA,MACrF;AAAA,MACA;AAAA,IAAA;AAAA,EAER;AAAA;AAAA;AAAA;AAAA,EAKQ,0BAA0B,MAAqB,YAA2B,OAAyB,aAAmC;AAG1I,QAAI,GAAG,0BAA0B,IAAI,GAAG;AACpC,YAAM,SAAc;AAAA,QAChB,MAAM;AAAA,QACN,YAAY,CAAA;AAAA,QACZ,UAAU,CAAA;AAAA,MAAC;AAGf,eAAS,IAAI,GAAG,IAAI,KAAK,WAAW,QAAQ,KAAK;AAC7C,cAAM,OAAO,KAAK,WAAW,CAAC;AAC9B,YAAI,GAAG,qBAAqB,IAAI,GAAG;AAC/B,gBAAM,OAAO,KAAK,KAAK,QAAQ,UAAU;AACzC,gBAAM,cAAc,KAAK,0BAA0B,KAAK,aAAa,YAAY,OAAO,WAAW;AAEnG,iBAAO,WAAW,IAAI,IAAI;AAC1B,iBAAO,SAAS,KAAK,IAAI;AAAA,QAC7B,WACS,GAAG,8BAA8B,IAAI,GAAG;AAC7C,gBAAM,OAAO,KAAK,KAAK,QAAQ,UAAU;AAEzC,gBAAM,eAAe,MAAM,IAAI,IAAI;AACnC,iBAAO,WAAW,IAAI,IAAI,gBAAgB,EAAE,MAAM,SAAA;AAClD,iBAAO,SAAS,KAAK,IAAI;AAAA,QAC7B;AAAA,MACJ;AACA,UAAI,OAAO,SAAS,WAAW,GAAG;AAC9B,eAAO,OAAO;AAAA,MAClB;AACA,aAAO;AAAA,IACX;AAGA,QAAI,GAAG,yBAAyB,IAAI,GAAG;AACnC,YAAM,SAAc,EAAE,MAAM,QAAA;AAC5B,UAAI,KAAK,SAAS,SAAS,GAAG;AAE1B,eAAO,QAAQ,KAAK,0BAA0B,KAAK,SAAS,CAAC,GAAG,YAAY,OAAO,WAAW;AAAA,MAClG,OAAO;AACH,eAAO,QAAQ,CAAA;AAAA,MACnB;AACA,aAAO;AAAA,IACX;AAGA,QAAI,GAAG,wBAAwB,IAAI,GAAG;AAClC,YAAM,aAAa,KAAK,0BAA0B,KAAK,UAAU,YAAY,OAAO,WAAW;AAI/F,aAAO;AAAA,IACX;AAGA,QAAI,GAAG,qBAAqB,IAAI,GAAG;AAC/B,aAAO,EAAE,MAAM,SAAA;AAAA,IACnB;AAGA,QAAI,GAAG,kBAAkB,IAAI,GAAG;AAE5B,aAAO,KAAK,0BAA0B,KAAK,YAAY,YAAY,OAAO,WAAW;AAAA,IACzF;AAGA,QAAI,GAAG,iBAAiB,IAAI,GAAG;AAC3B,YAAM,WAAW,KAAK,QAAQ,UAAU;AAGxC,UAAI,SAAS,WAAW,YAAY,KAChC,SAAS,WAAW,OAAO,KAC3B,SAAS,WAAW,SAAS,KAC7B,SAAS,WAAW,WAAW,KAC/B,SAAS,WAAW,aAAa,GAAG;AACpC,eAAO,EAAE,MAAM,SAAA;AAAA,MACnB;AAGA,UAAI,SAAS,WAAW,SAAS,KAC7B,SAAS,SAAS,aAAa,KAC/B,SAAS,SAAS,QAAQ,GAAG;AAC7B,eAAO,EAAE,MAAM,SAAA;AAAA,MACnB;AAGA,UAAI,SAAS,WAAW,UAAU,GAAG;AACjC,eAAO,EAAE,MAAM,UAAA;AAAA,MACnB;AAGA,UAAI,SAAS,SAAS,SAAS,KAC3B,SAAS,SAAS,OAAO,KACzB,SAAS,SAAS,UAAU,GAAG;AAC/B,eAAO,EAAE,MAAM,SAAS,OAAO,CAAA,EAAC;AAAA,MACpC;AAGA,aAAO,EAAE,aAAa,KAAA;AAAA,IAC1B;AAGA,QAAI,GAAG,mBAAmB,IAAI,GAAG;AAC7B,YAAM,WAAW,KAAK,cAAc;AAGpC,UAAI,aAAa,GAAG,WAAW,aAC3B,aAAa,GAAG,WAAW,cAC3B,aAAa,GAAG,WAAW,iBAC3B,aAAa,GAAG,WAAW,cAC3B,aAAa,GAAG,WAAW,gBAC3B,aAAa,GAAG,WAAW,uBAAuB;AAGlD,YAAI,aAAa,GAAG,WAAW,WAAW;AACtC,gBAAM,aAAa,KAAK,0BAA0B,KAAK,MAAM,YAAY,OAAO,WAAW;AAC3F,gBAAM,cAAc,KAAK,0BAA0B,KAAK,OAAO,YAAY,OAAO,WAAW;AAG7F,cAAI,WAAW,SAAS,YAAY,YAAY,SAAS,UAAU;AAC/D,mBAAO,EAAE,MAAM,SAAA;AAAA,UACnB;AAAA,QACJ;AAEA,eAAO,EAAE,MAAM,SAAA;AAAA,MACnB;AAGA,UAAI,aAAa,GAAG,WAAW,oBAC3B,aAAa,GAAG,WAAW,iBAC3B,aAAa,GAAG,WAAW,0BAC3B,aAAa,GAAG,WAAW,uBAC3B,aAAa,GAAG,WAAW,qBAC3B,aAAa,GAAG,WAAW,2BAC3B,aAAa,GAAG,WAAW,0BAC3B,aAAa,GAAG,WAAW,8BAA8B;AACzD,eAAO,EAAE,MAAM,UAAA;AAAA,MACnB;AAGA,UAAI,aAAa,GAAG,WAAW,2BAC3B,aAAa,GAAG,WAAW,aAAa;AACxC,cAAM,aAAa,KAAK,0BAA0B,KAAK,MAAM,YAAY,OAAO,WAAW;AAC3F,cAAM,cAAc,KAAK,0BAA0B,KAAK,OAAO,YAAY,OAAO,WAAW;AAG7F,YAAI,aAAa,GAAG,WAAW,eAAe,YAAY,SAAS,UAAU;AACzE,iBAAO,EAAE,MAAM,SAAA;AAAA,QACnB;AAGA,YAAI,WAAW,QAAQ,WAAW,SAAS,WAAW;AAClD,iBAAO;AAAA,QACX;AACA,YAAI,YAAY,QAAQ,YAAY,SAAS,WAAW;AACpD,iBAAO;AAAA,QACX;AACA,eAAO,EAAE,MAAM,UAAA;AAAA,MACnB;AAGA,UAAI,aAAa,GAAG,WAAW,kBAC3B,aAAa,GAAG,WAAW,YAC3B,aAAa,GAAG,WAAW,cAC3B,aAAa,GAAG,WAAW,yBAC3B,aAAa,GAAG,WAAW,+BAC3B,aAAa,GAAG,WAAW,wCAAwC;AACnE,eAAO,EAAE,MAAM,SAAA;AAAA,MACnB;AAAA,IACJ;AAGA,SAAK,GAAG,2BAA2B,IAAI,KAAK,GAAG,0BAA0B,IAAI,MAAM,aAAa;AAC5F,UAAI;AACA,cAAM,OAAO,YAAY,kBAAkB,IAAI;AAC/C,cAAM,SAAS,KAAK,oBAAoB,MAAM,WAAW;AAEzD,YAAI,WAAW,OAAO,SAAS,YAAY,OAAO,aAAa;AAC3D,iBAAO;AAAA,QACX;AAAA,MACJ,SAAS,GAAG;AAAA,MAEZ;AAAA,IACJ;AAGA,QAAI,GAAG,aAAa,IAAI,GAAG;AACvB,YAAM,OAAO,KAAK,QAAQ,UAAU;AACpC,YAAM,eAAe,MAAM,IAAI,IAAI;AACnC,UAAI,aAAc,QAAO;AAGzB,UAAI,aAAa;AACb,YAAI;AACA,gBAAM,OAAO,YAAY,kBAAkB,IAAI;AAC/C,gBAAM,SAAS,KAAK,oBAAoB,MAAM,WAAW;AAEzD,cAAI,WAAW,OAAO,SAAS,YAAY,OAAO,aAAa;AAC3D,mBAAO;AAAA,UACX;AAAA,QACJ,SAAS,GAAG;AAAA,QAEZ;AAAA,MACJ;AAEA,aAAO,EAAE,MAAM,UAAU,aAAa,KAAA;AAAA,IAC1C;AAGA,QAAI,GAAG,gBAAgB,IAAI,KAAK,GAAG,gCAAgC,IAAI,EAAG,QAAO,EAAE,MAAM,SAAA;AACzF,QAAI,GAAG,iBAAiB,IAAI,EAAG,QAAO,EAAE,MAAM,SAAA;AAC9C,QAAI,KAAK,SAAS,GAAG,WAAW,eAAe,KAAK,SAAS,GAAG,WAAW,aAAc,QAAO,EAAE,MAAM,UAAA;AAGxG,WAAO,EAAE,MAAM,UAAU,aAAa,KAAA;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKQ,mBAAmB,SAAuB;AAC9C,UAAM,2BAAW,IAAA;AACjB,eAAW,UAAU,SAAS;AAC1B,YAAM,MAAM,KAAK,UAAU,MAAM;AACjC,UAAI,CAAC,KAAK,IAAI,GAAG,GAAG;AAChB,aAAK,IAAI,KAAK,MAAM;AAAA,MACxB;AAAA,IACJ;AACA,WAAO,MAAM,KAAK,KAAK,OAAA,CAAQ;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAiB,QAAsB;AAC3C,QAAI,CAAC,OAAQ,QAAO;AACpB,QAAI,OAAO,WAAW,EAAG,QAAO;AAEhC,QAAI,OAAO,SAAS,YAAY,OAAO,YAAY;AAC/C,aAAO,OAAO,OAAO,OAAO,UAAU,EAAE;AAAA,QAAK,CAAC,SAC1C,KAAK,iBAAiB,IAAI;AAAA,MAAA;AAAA,IAElC;AAEA,QAAI,OAAO,SAAS,WAAW,OAAO,OAAO;AACzC,aAAO,KAAK,iBAAiB,OAAO,KAAK;AAAA,IAC7C;AAEA,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAc,MAAe,YAAoC;AAErE,QAAI,GAAG,kBAAkB,IAAI,GAAG;AAC5B,aAAO,KAAK,cAAc,KAAK,YAAY,UAAU;AAAA,IACzD;AAGA,QAAI,GAAG,iBAAiB,IAAI,GAAG;AAE3B,UAAI,GAAG,2BAA2B,KAAK,UAAU,GAAG;AAChD,cAAM,UAAU,KAAK,WAAW,WAAW,QAAQ,UAAU;AAC7D,cAAM,WAAW,KAAK,WAAW,KAAK,QAAQ,UAAU;AACxD,gBAAQ,YAAY,SAAS,QAAQ,SAAS,MAAM,MAAM,aAAa;AAAA,MAC3E;AAAA,IACJ;AAEA,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKQ,wBAAwB,UAAuB,YAAgC;AACnF,YAAQ,SAAS,MAAA;AAAA,MACb,KAAK,GAAG,WAAW;AACf,eAAO,EAAE,MAAM,SAAA;AAAA,MACnB,KAAK,GAAG,WAAW;AACf,eAAO,EAAE,MAAM,SAAA;AAAA,MACnB,KAAK,GAAG,WAAW;AACf,eAAO,EAAE,MAAM,UAAA;AAAA,MACnB,KAAK,GAAG,WAAW;AAAA,MACnB,KAAK,GAAG,WAAW;AACf,eAAO,CAAA;AAAA;AAAA,MAEX,KAAK,GAAG,WAAW,aAAa;AAC5B,cAAM,UAAU;AAChB,cAAM,SAAc;AAAA,UAChB,MAAM;AAAA,UACN,YAAY,CAAA;AAAA,UACZ,UAAU,CAAA;AAAA,QAAC;AAGf,iBAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,QAAQ,KAAK;AAC7C,gBAAM,SAAS,QAAQ,QAAQ,CAAC;AAChC,cAAI,GAAG,oBAAoB,MAAM,KAAK,OAAO,MAAM;AAC/C,kBAAM,OAAO,OAAO,KAAK,QAAQ,UAAU;AAC3C,kBAAM,aAAa,KAAK,wBAAwB,OAAO,MAAM,UAAU;AAEvE,mBAAO,WAAW,IAAI,IAAI;AAG1B,gBAAI,CAAC,OAAO,eAAe;AACvB,qBAAO,SAAS,KAAK,IAAI;AAAA,YAC7B;AAAA,UACJ;AAAA,QACJ;AAEA,YAAI,OAAO,SAAS,WAAW,GAAG;AAC9B,iBAAO,OAAO;AAAA,QAClB;AAEA,eAAO;AAAA,MACX;AAAA,MAEA,KAAK,GAAG,WAAW,WAAW;AAC1B,cAAM,YAAY;AAClB,eAAO;AAAA,UACH,MAAM;AAAA,UACN,OAAO,KAAK,wBAAwB,UAAU,aAAa,UAAU;AAAA,QAAA;AAAA,MAE7E;AAAA;AAAA,MAGA,KAAK,GAAG,WAAW,eAAe;AAC9B,cAAM,UAAU;AAChB,cAAM,WAAW,QAAQ,SAAS,QAAQ,UAAU;AAEpD,YAAI,aAAa,WAAW,QAAQ,eAAe,SAAS,GAAG;AAC3D,iBAAO;AAAA,YACH,MAAM;AAAA,YACN,OAAO,KAAK,wBAAwB,QAAQ,cAAc,CAAC,GAAG,UAAU;AAAA,UAAA;AAAA,QAEhF;AAEA,YAAI,aAAa,aAAa,QAAQ,eAAe,SAAS,GAAG;AAC7D,iBAAO,KAAK,wBAAwB,QAAQ,cAAc,CAAC,GAAG,UAAU;AAAA,QAC5E;AAIA,eAAO,EAAE,MAAM,UAAU,aAAa,QAAQ,QAAQ,GAAA;AAAA,MAC1D;AAAA,MAEA;AACI,eAAO,EAAE,MAAM,SAAA;AAAA,IAAS;AAAA,EAEpC;AAAA;AAAA;AAAA;AAAA,EAKQ,oBAAoB,MAAe,aAA6B,QAAgB,GAAQ;AAE5F,QAAI,QAAQ,GAAG;AACX,aAAO,EAAE,MAAM,UAAU,aAAa,mCAAA;AAAA,IAC1C;AAGA,QAAI,KAAK,QAAQ,GAAG,UAAU,OAAQ,QAAO,EAAE,MAAM,SAAA;AACrD,QAAI,KAAK,QAAQ,GAAG,UAAU,OAAQ,QAAO,EAAE,MAAM,SAAA;AACrD,QAAI,KAAK,QAAQ,GAAG,UAAU,QAAS,QAAO,EAAE,MAAM,UAAA;AACtD,QAAI,KAAK,QAAQ,GAAG,UAAU,KAAM,QAAO,EAAE,MAAM,OAAA;AACnD,QAAI,KAAK,QAAQ,GAAG,UAAU,kBAAkB,EAAE,MAAM,UAAU,UAAU,KAAA;AAC5E,QAAI,KAAK,QAAQ,GAAG,UAAU,OAAO,KAAK,QAAQ,GAAG,UAAU,QAAS,QAAO,CAAA;AAG/E,QAAI,KAAK,QAAQ,GAAG,UAAU,eAAe;AACzC,YAAM,cAAc;AACpB,aAAO,EAAE,MAAM,UAAU,MAAM,CAAC,YAAY,KAAK,EAAA;AAAA,IACrD;AACA,QAAI,KAAK,QAAQ,GAAG,UAAU,eAAe;AACzC,YAAM,cAAc;AACpB,aAAO,EAAE,MAAM,UAAU,MAAM,CAAC,YAAY,KAAK,EAAA;AAAA,IACrD;AACA,QAAI,KAAK,QAAQ,GAAG,UAAU,gBAAgB;AAE1C,YAAM,gBAAiB,KAAa;AACpC,aAAO,EAAE,MAAM,WAAW,MAAM,CAAC,kBAAkB,MAAM,EAAA;AAAA,IAC7D;AAGA,QAAI,KAAK,QAAQ,GAAG,UAAU,OAAO;AACjC,YAAM,YAAY;AAClB,YAAM,UAAU,UAAU,MAAM,IAAI,CAAA,MAAK,KAAK,oBAAoB,GAAG,aAAa,QAAQ,CAAC,CAAC;AAG5F,YAAM,cAAc,IAAI,IAAI,QAAQ,IAAI,CAAA,MAAK,EAAE,IAAI,CAAC;AACpD,UAAI,YAAY,SAAS,KAAK,QAAQ,CAAC,EAAE,SAAS,UAAU;AACxD,eAAO,QAAQ,CAAC;AAAA,MACpB;AAEA,aAAO,EAAE,OAAO,QAAA;AAAA,IACpB;AAGA,QAAI,YAAY,YAAY,IAAI,GAAG;AAC/B,YAAM,WAAY,KAAa,iBAAkB,KAAa;AAC9D,UAAI,YAAY,SAAS,SAAS,GAAG;AACjC,eAAO;AAAA,UACH,MAAM;AAAA,UACN,OAAO,KAAK,oBAAoB,SAAS,CAAC,GAAG,aAAa,QAAQ,CAAC;AAAA,QAAA;AAAA,MAE3E;AACA,aAAO,EAAE,MAAM,SAAS,OAAO,CAAA,EAAC;AAAA,IACpC;AAGA,QAAI,KAAK,QAAQ,GAAG,UAAU,QAAQ;AAClC,YAAM,aAAkC,CAAA;AACxC,YAAM,WAAqB,CAAA;AAG3B,YAAM,QAAQ,YAAY,oBAAoB,IAAI;AAGlD,YAAM,WAAW;AACjB,YAAM,iBAAiB,MAAM,MAAM,GAAG,QAAQ;AAE9C,iBAAW,QAAQ,gBAAgB;AAC/B,cAAM,WAAW,KAAK,QAAA;AACtB,cAAM,WAAW,YAAY,gBAAgB,IAAI;AAGjD,cAAM,aAAa,SAAS,kBAAA;AAC5B,YAAI,cAAc,WAAW,SAAS,GAAG;AACrC;AAAA,QACJ;AAEA,mBAAW,QAAQ,IAAI,KAAK,oBAAoB,UAAU,aAAa,QAAQ,CAAC;AAGhF,YAAI,EAAE,KAAK,QAAQ,GAAG,YAAY,WAAW;AACzC,mBAAS,KAAK,QAAQ;AAAA,QAC1B;AAAA,MACJ;AAEA,YAAM,SAAc,EAAE,MAAM,SAAA;AAE5B,UAAI,OAAO,KAAK,UAAU,EAAE,SAAS,GAAG;AACpC,eAAO,aAAa;AACpB,YAAI,SAAS,SAAS,GAAG;AACrB,iBAAO,WAAW;AAAA,QACtB;AAAA,MACJ;AAGA,UAAI,MAAM,SAAS,UAAU;AACzB,eAAO,cAAc,aAAa,MAAM,MAAM,wBAAwB,QAAQ;AAAA,MAClF;AAEA,aAAO;AAAA,IACX;AAGA,WAAO,EAAE,MAAM,UAAU,aAAa,eAAA;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKQ,qBAAqB,MAAyB,YAA6C;AAC/F,UAAM,OAAO,KAAK;AAElB,QAAI,KAAK,SAAS,EAAG,QAAO;AAE5B,UAAM,UAAU,KAAK,CAAC;AACtB,UAAM,YAAY,KAAK,CAAC;AAExB,QAAI,SAAS;AACb,QAAI,GAAG,gBAAgB,OAAO,GAAG;AAC7B,eAAS,QAAQ;AAAA,IACrB;AAEA,UAAM,SAAS,UAAU,QAAQ,UAAU;AAG3C,UAAM,aAAa,KAAK,0BAA0B,QAAQ,UAAU;AACpE,QAAI;AAEJ,QAAI,CAAC,YAAY;AAEb,UAAI;AACJ,SAAG,aAAa,YAAY,CAACA,UAAS;AAClC,YAAI,kBAAkB,WAAY;AAElC,YAAI,GAAG,oBAAoBA,KAAI,GAAG;AAC9B,gBAAM,YAAYA,MAAK;AACvB,cAAI,GAAG,gBAAgB,SAAS,GAAG;AAC/B,kBAAMC,QAAO,UAAU;AACvB,gBAAIA,MAAK,WAAW,GAAG,GAAG;AAEtB,kBAAID,MAAK,cAAc,MAAM,QAAQ,UAAU,MAAM,QAAQ;AACzD,6BAAaC;AAAAA,cACjB,WAESD,MAAK,cAAc,iBAAiB,GAAG,eAAeA,MAAK,aAAa,aAAa,GAAG;AAC7F,2BAAW,WAAWA,MAAK,aAAa,cAAc,UAAU;AAC5D,sBAAI,QAAQ,KAAK,QAAQ,UAAU,MAAM,QAAQ;AAC7C,iCAAaC;AACb;AAAA,kBACJ;AAAA,gBACJ;AAAA,cACJ;AAAA,YACJ;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ,CAAC;AAED,UAAI,YAAY;AACZ,cAAM,MAAM,KAAK,QAAQ,WAAW,QAAQ;AAC5C,cAAM,eAAe,KAAK,QAAQ,KAAK,UAAU;AAGjD,cAAM,aAAa,CAAC,OAAO,OAAO,QAAQ,QAAQ,aAAa,WAAW;AAC1E,mBAAW,OAAO,YAAY;AAC1B,cAAI,GAAG,WAAW,eAAe,GAAG,GAAG;AACnC,6BAAiB,eAAe;AAChC;AAAA,UACJ;AAAA,QAGJ;AAEA,YAAI,CAAC,kBAAkB,GAAG,WAAW,YAAY,GAAG;AAChD,2BAAiB;AAAA,QACrB;AAEA,YAAI,CAAC,kBAAkB,GAAG,WAAW,KAAK,KAAK,cAAc,UAAU,CAAC,GAAG;AACvE,2BAAiB,KAAK,KAAK,cAAc,UAAU;AAAA,QACvD;AAAA,MAGJ;AAAA,IACJ;AAEA,WAAO;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,eAAe;AAAA,QACX,MAAM,WAAW;AAAA,QACjB,WAAW,WAAW,8BAA8B,KAAK,SAAA,CAAU,EAAE,OAAO;AAAA,QAC5E,SAAS,WAAW,8BAA8B,KAAK,OAAA,CAAQ,EAAE,OAAO;AAAA,MAAA;AAAA,IAC5E;AAAA,EAER;AAAA;AAAA;AAAA;AAAA,EAKQ,0BAA0B,MAAyB,YAAkD;AACzG,UAAM,OAAO,KAAK;AAElB,QAAI,KAAK,SAAS,EAAG,QAAO;AAE5B,UAAM,gBAAgB,KAAK,CAAC;AAG5B,QAAI,iBAAiB;AACrB,QAAI,uBAAuB;AAE3B,QAAI,GAAG,aAAa,aAAa,GAAG;AAChC,uBAAiB,cAAc,QAAQ,UAAU;AACjD,6BAAuB;AAAA,IAC3B,WAAW,GAAG,iBAAiB,aAAa,KAAK,GAAG,aAAa,cAAc,UAAU,GAAG;AAExF,uBAAiB,cAAc,WAAW,QAAQ,UAAU;AAC5D,6BAAuB;AAAA,IAC3B,WAAW,GAAG,qBAAqB,aAAa,KAAK,GAAG,gBAAgB,aAAa,GAAG;AACpF,uBAAiB;AAAA,IACrB;AAGA,QAAI,WAAW,KAAK,kBAAkB,eAAe,UAAU;AAG/D,QAAI,sBAAsB;AACtB,YAAM,mBAAmB,KAAK,oCAAoC,gBAAgB,UAAU;AAE5F,UAAI,iBAAiB,eAAe;AAChC,iBAAS,gBAAgB,EAAE,GAAG,iBAAiB,eAAe,GAAG,SAAS,cAAA;AAAA,MAC9E;AACA,UAAI,iBAAiB,SAAS;AAC1B,iBAAS,UAAU,CAAC,GAAI,iBAAiB,WAAW,CAAA,GAAK,GAAI,SAAS,WAAW,EAAG;AAEpF,iBAAS,UAAU,MAAM,KAAK,IAAI,IAAI,SAAS,OAAO,CAAC;AAAA,MAC3D;AAAA,IACJ;AAEA,WAAO;AAAA,MACH,MAAM;AAAA,MACN,MAAM,WAAW;AAAA,MACjB,WAAW,WAAW,8BAA8B,cAAc,SAAA,CAAU,EAAE,OAAO;AAAA,MACrF,SAAS,WAAW,8BAA8B,cAAc,OAAA,CAAQ,EAAE,OAAO;AAAA,MACjF,eAAe,cAAc,QAAQ,UAAU;AAAA,MAC/C,eAAe,SAAS;AAAA,MACxB,SAAS,SAAS;AAAA,MAClB,OAAO;AAAA;AAAA,MACP,eAAe;AAAA,QACX,MAAM,WAAW;AAAA,QACjB,WAAW,WAAW,8BAA8B,cAAc,SAAA,CAAU,EAAE,OAAO;AAAA,QACrF,SAAS,WAAW,8BAA8B,cAAc,OAAA,CAAQ,EAAE,OAAO;AAAA,QACjF,SAAS,cAAc,QAAQ,UAAU;AAAA,QACzC,YAAY,SAAS;AAAA,MAAA;AAAA,IACzB;AAAA,EAER;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAkB,YAAqB,YAI7C;AACE,UAAM,gBAAqC,CAAA;AAC3C,UAAM,UAAoB,CAAA;AAC1B,UAAM,aAA4G,CAAA;AAGlH,UAAM,qCAAqB,IAAA;AAG3B,UAAM,QAAQ,CAAC,SAAkB;AAE7B,UAAI,GAAG,sBAAsB,IAAI,KAAK,GAAG,aAAa,KAAK,IAAI,GAAG;AAC9D,cAAM,UAAU,KAAK,KAAK,QAAQ,UAAU;AAC5C,YAAI,KAAK,aAAa;AAElB,cAAI,GAAG,iBAAiB,KAAK,WAAW,GAAG;AACvC,kBAAM,QAAQ,SAAS,KAAK,YAAY,IAAI;AAC5C,gBAAI,CAAC,MAAM,KAAK,GAAG;AACf,6BAAe,IAAI,SAAS,KAAK;AAAA,YACrC;AAAA,UACJ,WAES,GAAG,mBAAmB,KAAK,WAAW,KAAK,KAAK,YAAY,cAAc,SAAS,GAAG,WAAW,aAAa;AAEnH,gBAAI,GAAG,iBAAiB,KAAK,YAAY,KAAK,GAAG;AAC7C,oBAAM,QAAQ,SAAS,KAAK,YAAY,MAAM,IAAI;AAClD,kBAAI,CAAC,MAAM,KAAK,GAAG;AACf,+BAAe,IAAI,SAAS,KAAK;AAAA,cACrC;AAAA,YACJ;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ;AAGA,UAAI,GAAG,iBAAiB,IAAI,KAAK,GAAG,2BAA2B,KAAK,UAAU,GAAG;AAC7E,cAAM,MAAM,KAAK,WAAW,WAAW,QAAQ,UAAU;AACzD,cAAM,OAAO,KAAK,WAAW,KAAK,QAAQ,UAAU;AAEpD,YAAI,QAAQ,SAAS,CAAC,QAAQ,QAAQ,QAAQ,KAAK,EAAE,SAAS,IAAI,GAAG;AAEjE,cAAI,KAAK,UAAU,UAAU,GAAG;AAC5B,kBAAM,YAAY,KAAK,UAAU,CAAC;AAClC,gBAAI;AAGJ,gBAAI,GAAG,iBAAiB,SAAS,GAAG;AAChC,2BAAa,SAAS,UAAU,IAAI;AAAA,YACxC,WAES,GAAG,aAAa,SAAS,GAAG;AACjC,oBAAM,UAAU,UAAU,QAAQ,UAAU;AAC5C,oBAAM,QAAQ,eAAe,IAAI,OAAO;AACxC,kBAAI,OAAO,UAAU,UAAU;AAC3B,6BAAa;AAAA,cACjB;AAAA,YACJ;AAEA,gBAAI,cAAc,cAAc,OAAO,aAAa,KAAK;AACrD,oBAAM,YAAY,OAAO,UAAU;AACnC,kBAAI,CAAC,cAAc,SAAS,GAAG;AAC3B,oBAAI,cAAc,mBAAmB,UAAU;AAC/C,oBAAI,eAAe,IAAK,eAAc;AAAA,yBAC7B,eAAe,IAAK,eAAc;AAAA,yBAClC,eAAe,IAAK,eAAc;AAAA,yBAClC,eAAe,IAAK,eAAc;AAE3C,sBAAM,UAA+B,CAAA;AACrC,oBAAI,SAAS,QAAQ;AACjB,0BAAQ,kBAAkB,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAS;AAAA,gBAC7D,WAAW,SAAS,QAAQ;AACxB,0BAAQ,YAAY,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAS;AAAA,gBACvD,WAAW,SAAS,UAAU,SAAS,OAAO;AAC1C,0BAAQ,WAAW,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAS;AAAA,gBACtD;AAEA,8BAAc,SAAS,IAAI;AAAA,kBACvB;AAAA,kBACA,GAAI,OAAO,KAAK,OAAO,EAAE,SAAS,IAAI,EAAE,YAAY,CAAA;AAAA,gBAAC;AAAA,cAE7D;AAAA,YACJ;AAAA,UACJ;AAAA,QACJ;AAGA,YAAI,CAAC,OAAO,QAAQ,EAAE,SAAS,IAAI,GAAG;AAClC,cAAI,KAAK,UAAU,UAAU,KAAK,GAAG,gBAAgB,KAAK,UAAU,CAAC,CAAC,GAAG;AACrE,kBAAM,aAAa,KAAK,UAAU,CAAC,EAAE;AACrC,gBAAI,cAAc,CAAC,QAAQ,SAAS,UAAU,GAAG;AAC7C,sBAAQ,KAAK,UAAU;AAAA,YAC3B;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ;AAGA,SAAG,aAAa,MAAM,KAAK;AAAA,IAC/B;AAGA,UAAM,UAAU;AAGhB,UAAM,mBAAmB,WAAW,QAAQ,UAAU;AACtD,QAAI,iBAAiB,SAAS,aAAa,GAAG;AAC1C,YAAM,mBAAmB,CAAC,qBAAqB,yBAAyB,qBAAqB,aAAa;AAC1G,iBAAW,UAAU,kBAAkB;AACnC,YAAI,iBAAiB,SAAS,MAAM,KAAK,CAAC,QAAQ,SAAS,MAAM,GAAG;AAChE,kBAAQ,KAAK,MAAM;AAAA,QACvB;AAAA,MACJ;AAAA,IACJ;AAKA,WAAO;AAAA,MACH,eAAe,OAAO,KAAK,aAAa,EAAE,SAAS,IAAI,gBAAgB;AAAA,MACvE,SAAS,QAAQ,SAAS,IAAI,UAAU;AAAA,MACxC,YAAY,WAAW,SAAS,IAAI,aAAa;AAAA,IAAA;AAAA,EAEzD;AAAA;AAAA;AAAA;AAAA,EAKQ,oCAAoC,gBAAwB,YAGlE;AAEE,UAAM,cAAc,KAAK,QAAQ,IAAI,WAAW,QAAQ;AACxD,QAAI,CAAC,eAAe,CAAC,YAAY,IAAI,cAAc,GAAG;AAClD,aAAO,CAAA;AAAA,IACX;AAEA,UAAM,aAAa,YAAY,IAAI,cAAc;AACjD,UAAM,aAAa,WAAW;AAG9B,QAAI,CAAC,WAAW,WAAW,GAAG,GAAG;AAC7B,aAAO,CAAA;AAAA,IACX;AAGA,UAAM,MAAM,KAAK,QAAQ,WAAW,QAAQ;AAC5C,QAAI,eAAe,KAAK,QAAQ,KAAK,UAAU;AAG/C,UAAM,aAAa,CAAC,OAAO,OAAO,QAAQ,QAAQ,aAAa,WAAW;AAC1E,QAAI;AAEJ,eAAW,OAAO,YAAY;AAC1B,YAAM,WAAW,eAAe;AAChC,UAAI,GAAG,WAAW,QAAQ,GAAG;AACzB,uBAAe;AACf;AAAA,MACJ;AAAA,IACJ;AAEA,QAAI,CAAC,gBAAgB,GAAG,WAAW,YAAY,GAAG;AAC9C,qBAAe;AAAA,IACnB;AAEA,QAAI,CAAC,cAAc;AACf,aAAO,CAAA;AAAA,IACX;AAGA,UAAM,qBAAqB,KAAK,SAAS,cAAc,YAAY;AACnE,QAAI,CAAC,oBAAoB;AACrB,aAAO,CAAA;AAAA,IACX;AAGA,QAAI;AAEJ,UAAM,aAAa,WAAW,cAAc;AAE5C,OAAG,aAAa,oBAAoB,CAAC,SAAS;AAE1C,UAAI,GAAG,sBAAsB,IAAI,KAAK,KAAK,MAAM,QAAQ,kBAAkB,MAAM,YAAY;AACzF,cAAM,YAAY,KAAK;AACvB,YAAI,WAAW,KAAK,CAAA,MAAK,EAAE,SAAS,GAAG,WAAW,aAAa,GAAG;AAC9D,2BAAiB;AAAA,QACrB;AAAA,MACJ;AAGA,UAAI,GAAG,oBAAoB,IAAI,GAAG;AAC9B,cAAM,YAAY,KAAK;AACvB,YAAI,WAAW,KAAK,CAAA,MAAK,EAAE,SAAS,GAAG,WAAW,aAAa,GAAG;AAC9D,qBAAW,eAAe,KAAK,gBAAgB,cAAc;AACzD,gBAAI,GAAG,aAAa,YAAY,IAAI,KAAK,YAAY,KAAK,QAAQ,kBAAkB,MAAM,YAAY;AAClG,+BAAiB,YAAY;AAAA,YACjC;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ,CAAC;AAED,QAAI,CAAC,gBAAgB;AACjB,aAAO,CAAA;AAAA,IACX;AAGA,WAAO,KAAK,kBAAkB,gBAAgB,kBAAkB;AAAA,EACpE;AAAA;AAAA;AAAA;AAAA,EAKQ,0BAA0B,YAAoB,YAAuD;AAKzG,UAAM,UAAkC,CAAA;AAExC,OAAG,aAAa,YAAY,CAAC,SAAS;AAClC,UAAI,GAAG,oBAAoB,IAAI,GAAG;AAC9B,gBAAQ,KAAK,IAAI;AAAA,MACrB;AAAA,IACJ,CAAC;AAED,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACrC,YAAM,MAAM,QAAQ,CAAC;AACrB,YAAM,kBAAkB,IAAI;AAC5B,UAAI,GAAG,gBAAgB,eAAe,GAAG;AACrC,cAAM,aAAa,gBAAgB;AAGnC,YAAI,CAAC,WAAW,WAAW,GAAG,KAAK,CAAC,WAAW,WAAW,GAAG,GAAG;AAC5D,gBAAM,gBAAgB,IAAI,cAAc;AAExC,cAAI,iBAAiB,GAAG,eAAe,aAAa,GAAG;AACnD,qBAAS,IAAI,GAAG,IAAI,cAAc,SAAS,QAAQ,KAAK;AACpD,oBAAM,UAAU,cAAc,SAAS,CAAC;AACxC,kBAAI,QAAQ,KAAK,SAAS,YAAY;AAElC,sBAAM,UAAU,KAAK,kBAAkB,UAAU;AAEjD,uBAAO;AAAA,kBACH,aAAa;AAAA,kBACb;AAAA,kBACA,YAAY;AAAA,kBACZ,YAAY;AAAA,gBAAA;AAAA,cAEpB;AAAA,YACJ;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAEA,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAkB,aAAyC;AAC/D,QAAI;AACA,YAAM,kBAAkB,KAAK,KAAK,KAAK,SAAS,gBAAgB,aAAa,cAAc;AAC3F,UAAI,GAAG,WAAW,eAAe,GAAG;AAChC,cAAM,cAAc,KAAK,MAAM,GAAG,aAAa,iBAAiB,OAAO,CAAC;AACxE,eAAO,YAAY;AAAA,MACvB;AAAA,IACJ,SAAS,GAAG;AAAA,IAEZ;AACA,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKO,sBAA2B;AAC9B,UAAM,QAA6B,CAAA;AAEnC,UAAM,gBAAgB,CAAC,KAA0B,SAAiB,OAAO;AAErE,eAAS,IAAI,GAAG,IAAI,IAAI,OAAO,QAAQ,KAAK;AACxC,cAAM,QAAQ,IAAI,OAAO,CAAC;AAE1B,cAAM,cAAc,OAAO,SAAS,GAAG,IAAI,OAAO,MAAM,GAAG,EAAE,IAAI;AACjE,cAAM,YAAY,MAAM,KAAK,WAAW,GAAG,IAAI,MAAM,OAAO,MAAM,MAAM;AACxE,cAAM,WAAY,cAAc,aAAc;AAG9C,cAAM,UAAU,SAAS,QAAQ,qBAAqB,MAAM;AAE5D,YAAI,CAAC,MAAM,OAAO,GAAG;AACjB,gBAAM,OAAO,IAAI,CAAA;AAAA,QACrB;AAEA,cAAM,SAAS,MAAM,OAAO,YAAA;AAC5B,cAAM,YAAiB;AAAA,UACnB,SAAS,MAAM,WAAW,GAAG,MAAM,OAAO,YAAA,CAAa,IAAI,OAAO;AAAA,UAClE,aAAa,MAAM;AAAA,UACnB,MAAM,MAAM;AAAA,UACZ,aAAa,MAAM;AAAA,UACnB,WAAW;AAAA,YACP,OAAO;AAAA,cACH,aAAa;AAAA,YAAA;AAAA,UACjB;AAAA,QACJ;AAIJ,YAAI,CAAC,UAAU,YAAa,QAAO,UAAU;AAC7C,YAAI,CAAC,UAAU,KAAM,QAAO,UAAU;AACtC,YAAI,CAAC,UAAU,YAAa,QAAO,UAAU;AAG7C,YAAI,MAAM,gBAAgB;AACtB,oBAAU,UAAU,KAAK,EAAE,UAAU;AAAA,YACjC,oBAAoB;AAAA,cAChB,QAAQ,MAAM;AAAA,YAAA;AAAA,UAClB;AAAA,QAER,WAAW,MAAM,cAAc;AAE3B,gBAAM,cAAc,MAAM,iBAAiB,WAAW,eAAe;AACrE,oBAAU,UAAU,KAAK,EAAE,UAAU;AAAA,YACjC,CAAC,WAAW,GAAG;AAAA,cACX,QAAQ,EAAE,MAAM,MAAM,aAAA;AAAA,YAAa;AAAA,UACvC;AAAA,QAER,OAAO;AAEH,oBAAU,UAAU,KAAK,EAAE,UAAU;AAAA,YACjC,oBAAoB;AAAA,cAChB,QAAQ,EAAE,MAAM,SAAA;AAAA,YAAS;AAAA,UAC7B;AAAA,QAER;AAGA,YAAI,MAAM,cAAc,MAAM;AAC1B,oBAAU,cAAc;AAAA,YACpB,SAAS;AAAA,cACL,oBAAoB;AAAA,gBAChB,QAAQ,MAAM,aAAa;AAAA,cAAA;AAAA,YAC/B;AAAA,UACJ;AAAA,QAER;AAGA,cAAM,aAAoB,CAAA;AAE1B,YAAI,MAAM,cAAc,OAAO;AAC3B,gBAAM,UAAU,OAAO,QAAQ,MAAM,aAAa,KAAK;AACvD,mBAASC,KAAI,GAAGA,KAAI,QAAQ,QAAQA,MAAK;AACrC,kBAAM,CAAC,GAAG,IAAI,QAAQA,EAAC;AACvB,uBAAW,KAAK;AAAA,cACZ,MAAM;AAAA,cACN,IAAI;AAAA,cACJ,QAAQ,EAAE,MAAM,SAAA;AAAA,YAAS,CAC5B;AAAA,UACL;AAAA,QACJ;AAEA,YAAI,MAAM,cAAc,QAAQ;AAI5B,gBAAM,UAAU,OAAO,QAAQ,MAAM,aAAa,MAAM;AACxD,mBAASA,KAAI,GAAGA,KAAI,QAAQ,QAAQA,MAAK;AACrC,kBAAM,CAAC,GAAG,IAAI,QAAQA,EAAC;AACvB,uBAAW,KAAK;AAAA,cACZ,MAAM;AAAA,cACN,IAAI;AAAA,cACJ,UAAU;AAAA,cACV,QAAQ,EAAE,MAAM,SAAA;AAAA,YAAS,CAC5B;AAAA,UACL;AAAA,QACJ;AAIA,cAAM,aAAa,QAAQ,MAAM,YAAY;AAC7C,YAAI,YAAY;AACZ,qBAAW,QAAQ,CAAA,MAAK;AACpB,kBAAM,OAAO,EAAE,MAAM,GAAG,EAAE;AAC1B,gBAAI,CAAC,WAAW,KAAK,CAAA,UAAS,MAAM,SAAS,QAAQ,MAAM,OAAO,MAAM,GAAG;AACvE,yBAAW,KAAK;AAAA,gBACZ;AAAA,gBACA,IAAI;AAAA,gBACJ,UAAU;AAAA,gBACV,QAAQ,EAAE,MAAM,SAAA;AAAA;AAAA,cAAS,CAC5B;AAAA,YACL;AAAA,UACJ,CAAC;AAAA,QACL;AAEA,YAAI,WAAW,SAAS,GAAG;AACvB,oBAAU,aAAa;AAAA,QAC3B;AAEA,cAAM,OAAO,EAAE,MAAM,IAAI;AAAA,MAC7B;AAGA,eAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,QAAQ,KAAK;AACzC,cAAM,QAAQ,IAAI,QAAQ,CAAC;AAO3B,cAAM,aAAa,KAAK,aAAa,KAAK,CAAA,MAAK,EAAE,SAAS,MAAM,UAAU,EAAE,cAAc,MAAM,MAAM;AAEtG,YAAI,YAAY;AAEZ,cAAI,eAAe,IAAK;AAExB,gBAAM,cAAc,OAAO,SAAS,GAAG,IAAI,OAAO,MAAM,GAAG,EAAE,IAAI;AACjE,gBAAM,cAAc,MAAM,OAAO,WAAW,GAAG,IAAI,MAAM,SAAS,MAAM,MAAM;AAC9E,gBAAM,aAAa,cAAc;AAEjC,wBAAc,YAAY,UAAU;AAAA,QACxC;AAAA,MACJ;AAAA,IACJ;AAEA,aAAS,IAAI,GAAG,IAAI,KAAK,aAAa,QAAQ,KAAK;AAC/C,YAAM,MAAM,KAAK,aAAa,CAAC;AAe/B,YAAM,YAAY,KAAK,aAAa;AAAA,QAAK,CAAA,WACrC,OAAO,QAAQ,KAAK,CAAA,MAAK,EAAE,WAAW,IAAI,QAAQ,EAAE,WAAW,IAAI,SAAS;AAAA,MAAA;AAGhF,UAAI,CAAC,WAAW;AACZ,sBAAc,GAAG;AAAA,MACrB;AAAA,IACJ;AAEA,WAAO;AAAA,MACH,SAAS;AAAA,MACT,MAAM;AAAA,QACF,OAAO;AAAA,QACP,SAAS;AAAA,QACT,aAAa;AAAA,MAAA;AAAA,MAEjB;AAAA,MACA,YAAY;AAAA,QACR,SAAS,CAAA;AAAA,MAAC;AAAA,IACd;AAAA,EAER;AACJ;;"}
|