@luma-layered-ts/eslint-plugin 1.5.0 → 1.6.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/lib/index.d.ts +76 -12
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +28 -0
- package/lib/index.js.map +1 -1
- package/lib/layers.d.ts +11 -0
- package/lib/layers.d.ts.map +1 -1
- package/lib/layers.js +152 -3
- package/lib/layers.js.map +1 -1
- package/lib/rules/codec-placement.d.ts +7 -0
- package/lib/rules/codec-placement.d.ts.map +1 -0
- package/lib/rules/codec-placement.js +151 -0
- package/lib/rules/codec-placement.js.map +1 -0
- package/lib/rules/next.d.ts +1 -1
- package/lib/rules/next.d.ts.map +1 -1
- package/lib/rules/next.js +9 -0
- package/lib/rules/next.js.map +1 -1
- package/lib/rules/react.d.ts +1 -1
- package/lib/rules/react.d.ts.map +1 -1
- package/lib/rules/react.js +9 -4
- package/lib/rules/react.js.map +1 -1
- package/lib/rules/require-unsafe-dir.d.ts +10 -0
- package/lib/rules/require-unsafe-dir.d.ts.map +1 -0
- package/lib/rules/require-unsafe-dir.js +221 -0
- package/lib/rules/require-unsafe-dir.js.map +1 -0
- package/lib/rules/server.d.ts +4 -2
- package/lib/rules/server.d.ts.map +1 -1
- package/lib/rules/server.js +193 -6
- package/lib/rules/server.js.map +1 -1
- package/lib/rules/strict-collection.d.ts +7 -0
- package/lib/rules/strict-collection.d.ts.map +1 -0
- package/lib/rules/strict-collection.js +65 -0
- package/lib/rules/strict-collection.js.map +1 -0
- package/package.json +1 -1
package/lib/rules/server.js
CHANGED
|
@@ -19,17 +19,31 @@ exports.default = (0, create_rule_js_1.createRule)({
|
|
|
19
19
|
description: "Enforce layered architecture for server-side layers (core, service, adapter, infra). Checks imports, encoded representation globals, Schema boundary, and string interpretation.",
|
|
20
20
|
},
|
|
21
21
|
messages: {
|
|
22
|
+
noDate: layers_js_1.NO_DATE_MESSAGE,
|
|
22
23
|
importViolation: "'{{fromLayer}}' cannot import from '{{toLayer}}'.",
|
|
23
24
|
importNonLayer: "Import '{{importPath}}' does not resolve to a recognized layer. Move the target into a layer directory.",
|
|
24
25
|
encodedGlobal: "'{{name}}' is an encoded representation API. Not allowed in '{{layer}}'. Use canonical types (Effect.ts) instead.",
|
|
25
26
|
ioGlobal: "'{{name}}' is an IO boundary API. Not allowed in '{{layer}}'. IO belongs in infra.",
|
|
26
27
|
schemaBoundary: "Schema.{{method}}() crosses the canonical/encoded boundary. Only allowed in adapter/infra. Current layer: '{{layer}}'.",
|
|
27
28
|
encodedMethod: "'.{{method}}()' interprets encoded representation. Not allowed in '{{layer}}'. Encoded interpretation belongs in adapter.",
|
|
29
|
+
stringConstruction: "{{what}} builds a string in '{{layer}}'. Strings are encoded or display representations; produce them in adapter (codecs and display formatters).",
|
|
30
|
+
adapterImpure: "'{{name}}' is IO, environment-specific or non-deterministic. adapter is a pure codec shared by server and client. Move this to infra or ui/hooks.",
|
|
31
|
+
adapterNodeBuiltin: "'{{importPath}}' is a Node.js built-in. adapter is a pure codec shared by server and client.",
|
|
32
|
+
adapterPackageNotAllowed: "'{{name}}' is not in the adapter package allowlist. adapter is a pure codec shared by server and client; add the package to the server rule option adapterAllowedPackages only if it does no IO.",
|
|
33
|
+
adapterAmbientLocale: "'{{name}}' depends on the runtime's locale or time zone, which differ between server and client. {{fix}}",
|
|
28
34
|
},
|
|
29
|
-
schema: [
|
|
35
|
+
schema: [
|
|
36
|
+
{
|
|
37
|
+
type: "object",
|
|
38
|
+
properties: {
|
|
39
|
+
adapterAllowedPackages: { type: "array", items: { type: "string" } },
|
|
40
|
+
},
|
|
41
|
+
additionalProperties: false,
|
|
42
|
+
},
|
|
43
|
+
],
|
|
30
44
|
},
|
|
31
45
|
defaultOptions: [defaultOptions],
|
|
32
|
-
create(context) {
|
|
46
|
+
create(context, [options]) {
|
|
33
47
|
const filePath = context.filename;
|
|
34
48
|
if ((0, layers_js_1.isTestFile)(filePath))
|
|
35
49
|
return {};
|
|
@@ -37,7 +51,20 @@ exports.default = (0, create_rule_js_1.createRule)({
|
|
|
37
51
|
if (!layer || !SERVER_LAYERS.has(layer))
|
|
38
52
|
return {};
|
|
39
53
|
const isInner = INNER_LAYERS.has(layer);
|
|
40
|
-
|
|
54
|
+
const isAdapter = layer === "adapter";
|
|
55
|
+
const adapterPackages = new Set([
|
|
56
|
+
...layers_js_1.DEFAULT_ADAPTER_PACKAGES,
|
|
57
|
+
...(options.adapterAllowedPackages ?? []),
|
|
58
|
+
]);
|
|
59
|
+
function checkImport(importPath, node, typeOnly = false) {
|
|
60
|
+
if (isAdapter && (0, layers_js_1.isNodeBuiltinImport)(importPath)) {
|
|
61
|
+
context.report({
|
|
62
|
+
node,
|
|
63
|
+
messageId: "adapterNodeBuiltin",
|
|
64
|
+
data: { importPath },
|
|
65
|
+
});
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
41
68
|
const resolved = (0, layers_js_1.resolveImportPath)(importPath, filePath);
|
|
42
69
|
const toLayer = (0, layers_js_1.getLayerFromImport)(resolved);
|
|
43
70
|
if (!toLayer) {
|
|
@@ -48,6 +75,17 @@ exports.default = (0, create_rule_js_1.createRule)({
|
|
|
48
75
|
data: { importPath },
|
|
49
76
|
});
|
|
50
77
|
}
|
|
78
|
+
const name = (0, layers_js_1.packageName)(importPath);
|
|
79
|
+
if (isAdapter &&
|
|
80
|
+
!typeOnly &&
|
|
81
|
+
name !== null &&
|
|
82
|
+
!adapterPackages.has(name)) {
|
|
83
|
+
context.report({
|
|
84
|
+
node,
|
|
85
|
+
messageId: "adapterPackageNotAllowed",
|
|
86
|
+
data: { name },
|
|
87
|
+
});
|
|
88
|
+
}
|
|
51
89
|
return;
|
|
52
90
|
}
|
|
53
91
|
if (!(0, layers_js_1.canImport)(layer, toLayer)) {
|
|
@@ -58,10 +96,62 @@ exports.default = (0, create_rule_js_1.createRule)({
|
|
|
58
96
|
});
|
|
59
97
|
}
|
|
60
98
|
}
|
|
99
|
+
// Intl.X() / new Intl.X(): the locale must be given, and DateTimeFormat needs a timeZone.
|
|
100
|
+
// Options passed as a variable or with a spread cannot be checked statically and are allowed.
|
|
101
|
+
function checkIntl(node) {
|
|
102
|
+
const callee = node.callee;
|
|
103
|
+
if (callee.type !== utils_1.AST_NODE_TYPES.MemberExpression ||
|
|
104
|
+
callee.computed ||
|
|
105
|
+
callee.object.type !== utils_1.AST_NODE_TYPES.Identifier ||
|
|
106
|
+
callee.object.name !== "Intl" ||
|
|
107
|
+
callee.property.type !== utils_1.AST_NODE_TYPES.Identifier ||
|
|
108
|
+
!layers_js_1.INTL_LOCALE_CONSTRUCTORS.has(callee.property.name)) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const name = `Intl.${callee.property.name}`;
|
|
112
|
+
const [locale, options] = node.arguments;
|
|
113
|
+
const missingLocale = locale === undefined ||
|
|
114
|
+
(locale.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
115
|
+
locale.name === "undefined") ||
|
|
116
|
+
(locale.type === utils_1.AST_NODE_TYPES.ArrayExpression &&
|
|
117
|
+
locale.elements.length === 0);
|
|
118
|
+
if (missingLocale) {
|
|
119
|
+
context.report({
|
|
120
|
+
node,
|
|
121
|
+
messageId: "adapterAmbientLocale",
|
|
122
|
+
data: { name, fix: "Pass the locale explicitly." },
|
|
123
|
+
});
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (callee.property.name !== "DateTimeFormat")
|
|
127
|
+
return;
|
|
128
|
+
const hasTimeZone = options !== undefined &&
|
|
129
|
+
(options.type !== utils_1.AST_NODE_TYPES.ObjectExpression ||
|
|
130
|
+
options.properties.some((p) => p.type === utils_1.AST_NODE_TYPES.SpreadElement ||
|
|
131
|
+
(!p.computed &&
|
|
132
|
+
p.key.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
133
|
+
p.key.name === "timeZone")));
|
|
134
|
+
if (!hasTimeZone) {
|
|
135
|
+
context.report({
|
|
136
|
+
node,
|
|
137
|
+
messageId: "adapterAmbientLocale",
|
|
138
|
+
data: { name, fix: "Pass the timeZone option explicitly." },
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
61
142
|
return {
|
|
62
143
|
// --- Import checks (all server layers) ---
|
|
144
|
+
"Identifier[name='Date']"(node) {
|
|
145
|
+
if ((0, layers_js_1.isDateReference)(node))
|
|
146
|
+
context.report({ node, messageId: "noDate" });
|
|
147
|
+
},
|
|
63
148
|
ImportDeclaration(node) {
|
|
64
|
-
|
|
149
|
+
// Type-only imports have no runtime effect
|
|
150
|
+
const typeOnly = node.importKind === "type" ||
|
|
151
|
+
(node.specifiers.length > 0 &&
|
|
152
|
+
node.specifiers.every((s) => s.type === utils_1.AST_NODE_TYPES.ImportSpecifier &&
|
|
153
|
+
s.importKind === "type"));
|
|
154
|
+
checkImport(node.source.value, node, typeOnly);
|
|
65
155
|
},
|
|
66
156
|
ImportExpression(node) {
|
|
67
157
|
if (node.source.type === utils_1.AST_NODE_TYPES.Literal &&
|
|
@@ -75,6 +165,72 @@ exports.default = (0, create_rule_js_1.createRule)({
|
|
|
75
165
|
checkImport(node.expression.value, node);
|
|
76
166
|
}
|
|
77
167
|
},
|
|
168
|
+
// --- adapter purity ---
|
|
169
|
+
...(isAdapter
|
|
170
|
+
? {
|
|
171
|
+
Identifier(node) {
|
|
172
|
+
if (!layers_js_1.ADAPTER_IMPURE_GLOBALS.has(node.name))
|
|
173
|
+
return;
|
|
174
|
+
if (node.parent?.type === utils_1.AST_NODE_TYPES.MemberExpression &&
|
|
175
|
+
node.parent.property === node &&
|
|
176
|
+
!node.parent.computed) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (isInTypeContext(node))
|
|
180
|
+
return;
|
|
181
|
+
context.report({
|
|
182
|
+
node,
|
|
183
|
+
messageId: "adapterImpure",
|
|
184
|
+
data: { name: node.name },
|
|
185
|
+
});
|
|
186
|
+
},
|
|
187
|
+
MemberExpression(node) {
|
|
188
|
+
if (node.object.type !== utils_1.AST_NODE_TYPES.Identifier ||
|
|
189
|
+
node.property.type !== utils_1.AST_NODE_TYPES.Identifier ||
|
|
190
|
+
node.computed) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
const name = `${node.object.name}.${node.property.name}`;
|
|
194
|
+
if (layers_js_1.ADAPTER_IMPURE_MEMBERS.get(node.object.name)?.has(node.property.name)) {
|
|
195
|
+
context.report({
|
|
196
|
+
node,
|
|
197
|
+
messageId: "adapterImpure",
|
|
198
|
+
data: { name },
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
// import.meta.env etc. read the build / runtime environment
|
|
203
|
+
MetaProperty(node) {
|
|
204
|
+
context.report({
|
|
205
|
+
node,
|
|
206
|
+
messageId: "adapterImpure",
|
|
207
|
+
data: { name: `${node.meta.name}.${node.property.name}` },
|
|
208
|
+
});
|
|
209
|
+
},
|
|
210
|
+
CallExpression(node) {
|
|
211
|
+
checkIntl(node);
|
|
212
|
+
if (node.callee.type !== utils_1.AST_NODE_TYPES.MemberExpression ||
|
|
213
|
+
node.callee.computed ||
|
|
214
|
+
node.callee.property.type !== utils_1.AST_NODE_TYPES.Identifier) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
const method = node.callee.property.name;
|
|
218
|
+
if (layers_js_1.ADAPTER_AMBIENT_LOCALE_METHODS.has(method)) {
|
|
219
|
+
context.report({
|
|
220
|
+
node,
|
|
221
|
+
messageId: "adapterAmbientLocale",
|
|
222
|
+
data: {
|
|
223
|
+
name: `.${method}()`,
|
|
224
|
+
fix: "Use an Intl constructor with an explicit locale (and timeZone for dates).",
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
NewExpression(node) {
|
|
230
|
+
checkIntl(node);
|
|
231
|
+
},
|
|
232
|
+
}
|
|
233
|
+
: {}),
|
|
78
234
|
// --- Inner layer restrictions (core/service only) ---
|
|
79
235
|
...(isInner
|
|
80
236
|
? {
|
|
@@ -104,6 +260,27 @@ exports.default = (0, create_rule_js_1.createRule)({
|
|
|
104
260
|
});
|
|
105
261
|
}
|
|
106
262
|
},
|
|
263
|
+
// `${a}` interpolation (plain string literals and template types are fine)
|
|
264
|
+
TemplateLiteral(node) {
|
|
265
|
+
if (node.expressions.length === 0)
|
|
266
|
+
return;
|
|
267
|
+
context.report({
|
|
268
|
+
node,
|
|
269
|
+
messageId: "stringConstruction",
|
|
270
|
+
data: { what: "Template literal interpolation", layer },
|
|
271
|
+
});
|
|
272
|
+
},
|
|
273
|
+
// "a" + b, s += "x" (string-ness is only known when one side is a string literal)
|
|
274
|
+
"BinaryExpression[operator='+'], AssignmentExpression[operator='+=']"(node) {
|
|
275
|
+
if (!isStringLiteral(node.left) && !isStringLiteral(node.right)) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
context.report({
|
|
279
|
+
node,
|
|
280
|
+
messageId: "stringConstruction",
|
|
281
|
+
data: { what: "String concatenation", layer },
|
|
282
|
+
});
|
|
283
|
+
},
|
|
107
284
|
// Schema boundary + string interpretation methods
|
|
108
285
|
CallExpression(node) {
|
|
109
286
|
if (node.callee.type !== utils_1.AST_NODE_TYPES.MemberExpression ||
|
|
@@ -119,9 +296,14 @@ exports.default = (0, create_rule_js_1.createRule)({
|
|
|
119
296
|
});
|
|
120
297
|
return;
|
|
121
298
|
}
|
|
122
|
-
|
|
123
|
-
|
|
299
|
+
if (layers_js_1.STRING_CONSTRUCTION_METHODS.has(method)) {
|
|
300
|
+
context.report({
|
|
301
|
+
node,
|
|
302
|
+
messageId: "stringConstruction",
|
|
303
|
+
data: { what: `.${method}()`, layer },
|
|
304
|
+
});
|
|
124
305
|
return;
|
|
306
|
+
}
|
|
125
307
|
if (layers_js_1.STRING_INTERPRETATION_METHODS.has(method)) {
|
|
126
308
|
context.report({
|
|
127
309
|
node,
|
|
@@ -133,6 +315,11 @@ exports.default = (0, create_rule_js_1.createRule)({
|
|
|
133
315
|
}
|
|
134
316
|
: {}),
|
|
135
317
|
};
|
|
318
|
+
function isStringLiteral(node) {
|
|
319
|
+
return ((node.type === utils_1.AST_NODE_TYPES.Literal &&
|
|
320
|
+
typeof node.value === "string") ||
|
|
321
|
+
node.type === utils_1.AST_NODE_TYPES.TemplateLiteral);
|
|
322
|
+
}
|
|
136
323
|
function isInTypeContext(node) {
|
|
137
324
|
let current = node.parent;
|
|
138
325
|
while (current) {
|
package/lib/rules/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/rules/server.ts"],"names":[],"mappings":";;AAAA,oDAAoE;AACpE,sDAA+C;AAC/C,
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/rules/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
type Options = Record<string, never>;
|
|
2
|
+
type MessageId = "useStrictCollection" | "noMutableCollection";
|
|
3
|
+
declare const _default: import("@typescript-eslint/utils/dist/ts-eslint/Rule.js").RuleModule<MessageId, [Options], unknown, import("@typescript-eslint/utils/dist/ts-eslint/Rule.js").RuleListener> & {
|
|
4
|
+
name: string;
|
|
5
|
+
};
|
|
6
|
+
export default _default;
|
|
7
|
+
//# sourceMappingURL=strict-collection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strict-collection.d.ts","sourceRoot":"","sources":["../../src/rules/strict-collection.ts"],"names":[],"mappings":"AAGA,KAAK,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAGrC,KAAK,SAAS,GAAG,qBAAqB,GAAG,qBAAqB,CAAC;;;;AA0B/D,wBAuCG"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
4
|
+
const create_rule_js_1 = require("../create-rule.js");
|
|
5
|
+
const defaultOptions = {};
|
|
6
|
+
// ReadonlyMap#get returns `V | undefined`, and ReadonlyMap/ReadonlySet can be upcast to Map/Set
|
|
7
|
+
const STRICT_REPLACEMENTS = new Map([
|
|
8
|
+
["ReadonlyMap", "StrictReadonlyMap"],
|
|
9
|
+
["ReadonlySet", "StrictReadonlySet"],
|
|
10
|
+
["Map", "StrictReadonlyMap"],
|
|
11
|
+
["Set", "StrictReadonlySet"],
|
|
12
|
+
]);
|
|
13
|
+
// No strict counterpart: keep them as inferred locals inside the module that mutates them
|
|
14
|
+
const MUTABLE_ONLY = new Set(["WeakMap", "WeakSet"]);
|
|
15
|
+
// `ReadonlyMap` or `globalThis.ReadonlyMap`; other qualified names are different types
|
|
16
|
+
function collectionName(typeName) {
|
|
17
|
+
if (typeName.type === utils_1.AST_NODE_TYPES.Identifier)
|
|
18
|
+
return typeName.name;
|
|
19
|
+
if (typeName.type === utils_1.AST_NODE_TYPES.TSQualifiedName &&
|
|
20
|
+
typeName.left.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
21
|
+
typeName.left.name === "globalThis") {
|
|
22
|
+
return typeName.right.name;
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
exports.default = (0, create_rule_js_1.createRule)({
|
|
27
|
+
name: "strict-collection",
|
|
28
|
+
meta: {
|
|
29
|
+
type: "problem",
|
|
30
|
+
docs: {
|
|
31
|
+
description: "Disallow Map/Set/ReadonlyMap/ReadonlySet/WeakMap/WeakSet types. Use StrictReadonlyMap/StrictReadonlySet from @luma-layered-ts/types.",
|
|
32
|
+
},
|
|
33
|
+
messages: {
|
|
34
|
+
useStrictCollection: "'{{name}}' is mutable or can be upcast to a mutable collection. Use '{{replacement}}' from @luma-layered-ts/types (convert with to{{replacement}}).",
|
|
35
|
+
noMutableCollection: "'{{name}}' is mutable and has no strict counterpart. Do not expose it as a type; keep it an inferred local inside the module that mutates it.",
|
|
36
|
+
},
|
|
37
|
+
schema: [],
|
|
38
|
+
},
|
|
39
|
+
defaultOptions: [defaultOptions],
|
|
40
|
+
create(context) {
|
|
41
|
+
return {
|
|
42
|
+
TSTypeReference(node) {
|
|
43
|
+
const name = collectionName(node.typeName);
|
|
44
|
+
if (name === null)
|
|
45
|
+
return;
|
|
46
|
+
const replacement = STRICT_REPLACEMENTS.get(name);
|
|
47
|
+
if (replacement !== undefined) {
|
|
48
|
+
context.report({
|
|
49
|
+
node,
|
|
50
|
+
messageId: "useStrictCollection",
|
|
51
|
+
data: { name, replacement },
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
else if (MUTABLE_ONLY.has(name)) {
|
|
55
|
+
context.report({
|
|
56
|
+
node,
|
|
57
|
+
messageId: "noMutableCollection",
|
|
58
|
+
data: { name },
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
//# sourceMappingURL=strict-collection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strict-collection.js","sourceRoot":"","sources":["../../src/rules/strict-collection.ts"],"names":[],"mappings":";;AAAA,oDAAoE;AACpE,sDAA+C;AAG/C,MAAM,cAAc,GAAY,EAAE,CAAC;AAInC,gGAAgG;AAChG,MAAM,mBAAmB,GAAgC,IAAI,GAAG,CAAC;IAC/D,CAAC,aAAa,EAAE,mBAAmB,CAAC;IACpC,CAAC,aAAa,EAAE,mBAAmB,CAAC;IACpC,CAAC,KAAK,EAAE,mBAAmB,CAAC;IAC5B,CAAC,KAAK,EAAE,mBAAmB,CAAC;CAC7B,CAAC,CAAC;AAEH,0FAA0F;AAC1F,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;AAErD,uFAAuF;AACvF,SAAS,cAAc,CAAC,QAA6B;IACnD,IAAI,QAAQ,CAAC,IAAI,KAAK,sBAAc,CAAC,UAAU;QAAE,OAAO,QAAQ,CAAC,IAAI,CAAC;IACtE,IACE,QAAQ,CAAC,IAAI,KAAK,sBAAc,CAAC,eAAe;QAChD,QAAQ,CAAC,IAAI,CAAC,IAAI,KAAK,sBAAc,CAAC,UAAU;QAChD,QAAQ,CAAC,IAAI,CAAC,IAAI,KAAK,YAAY,EACnC,CAAC;QACD,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;IAC7B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,kBAAe,IAAA,2BAAU,EAAuB;IAC9C,IAAI,EAAE,mBAAmB;IACzB,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EACT,sIAAsI;SACzI;QACD,QAAQ,EAAE;YACR,mBAAmB,EACjB,qJAAqJ;YACvJ,mBAAmB,EACjB,+IAA+I;SAClJ;QACD,MAAM,EAAE,EAAE;KACX;IACD,cAAc,EAAE,CAAC,cAAc,CAAC;IAChC,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,eAAe,CAAC,IAAI;gBAClB,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAC3C,IAAI,IAAI,KAAK,IAAI;oBAAE,OAAO;gBAC1B,MAAM,WAAW,GAAG,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAClD,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;oBAC9B,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI;wBACJ,SAAS,EAAE,qBAAqB;wBAChC,IAAI,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE;qBAC5B,CAAC,CAAC;gBACL,CAAC;qBAAM,IAAI,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;oBAClC,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI;wBACJ,SAAS,EAAE,qBAAqB;wBAChC,IAAI,EAAE,EAAE,IAAI,EAAE;qBACf,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
|