@sister.software/oxlint-config 9.3.0 → 10.0.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/README.md CHANGED
@@ -31,16 +31,38 @@ export default createOxlintConfig({
31
31
 
32
32
  ### Options
33
33
 
34
- | Option | Default | Purpose |
35
- | ----------------------- | ------------------------ | -------------------------------------------------- |
36
- | `packageNamespace` | `@sister.software` | Namespace the runtime-boundary rules apply to. |
37
- | `copyrightHolder` | `Sister Software` | `@copyright` value stamped into file headers. |
38
- | `spdxLicenseIdentifier` | `UNLICENSED` | `@license` value stamped into file headers. |
39
- | `author` | `Teffen Ellis, et al.` | `@author` value stamped into file headers. |
40
- | `react` | `false` | Enable oxlint's React plugin. |
41
- | `headers` | `true` | Enforce file headers (error severity, auto-fixed). |
42
- | `ignorePatterns` | build/output dirs | Replace the default ignore list. |
43
- | `overrides` | `{}` | Extra config merged last (escape hatch). |
34
+ | Option | Default | Purpose |
35
+ | ------------------------ | ------------------------- | ----------------------------------------------------------- |
36
+ | `packageNamespace` | `@sister.software` | Namespace the runtime-boundary rules apply to. |
37
+ | `copyrightHolder` | `Sister Software` | `@copyright` value stamped into file headers. |
38
+ | `spdxLicenseIdentifier` | `UNLICENSED` | `@license` value stamped into file headers. |
39
+ | `author` | `Teffen Ellis, et al.` | `@author` value stamped into file headers. |
40
+ | `react` | `false` | Enable oxlint's React plugin. |
41
+ | `headers` | `true` | Enforce file headers (error severity, auto-fixed). |
42
+ | `padding` | `true` | Blank line before `return`/block-like statements. |
43
+ | `braces` | `true` | Braces around single-statement bodies. |
44
+ | `restrictProcessGlobals` | `false` | Forbid direct `process.env` / `process.argv` access. |
45
+ | `limits` | calibrated defaults | Override individual legibility ceilings. |
46
+ | `testFilePatterns` | `**/*.test.ts`, … | Globs where the size and constant rules switch off. |
47
+ | `generatedFilePatterns` | `**/*.gen.ts`, … | Globs where only the size ceilings switch off. |
48
+ | `unnamedThresholds` | `false` | Flag numeric literals used as comparison thresholds. |
49
+ | `constantDocs` | `false` | Require JSDoc on exported / `SCREAMING_CASE` constants. |
50
+ | `lengthTruthiness` | `true` | Rewrite explicit length comparisons to truthiness. |
51
+ | `ignorePatterns` | build output, `.yarn` | Replace the default ignore list. |
52
+ | `overrides` | `{}` | Extra config merged last (escape hatch). |
53
+
54
+ `limits` takes any subset of the ceilings; unspecified keys keep their calibrated default:
55
+
56
+ ```ts
57
+ createOxlintConfig({
58
+ spdxLicenseIdentifier: "AGPL-3.0",
59
+ limits: { maxStatements: 60, complexity: 40 },
60
+ })
61
+ ```
62
+
63
+ Generated files are exempt from the size ceilings only — every correctness rule still applies, because
64
+ generated code ships. Point `generatedFilePatterns` at your own globs if they differ from the defaults
65
+ (`**/*.gen.ts(x)`, `**/*.generated.ts`, `**/generated/**`).
44
66
 
45
67
  ## Features
46
68
 
@@ -62,3 +84,73 @@ files may not import Node built-ins at all.
62
84
  A bundled oxlint JS plugin (`sister-software/require-file-header`) reports and auto-fixes the
63
85
  `@copyright`/`@license`/`@author` header, preserving any other JSDoc tags already in the leading
64
86
  comment block. Run `oxlint --fix` to stamp headers.
87
+
88
+ ### Legibility tiers
89
+
90
+ v10 turns on four tiers of upstream rules by default:
91
+
92
+ 1. **Structural guardrails** — nesting depth, function and file size, parameter count, cyclomatic
93
+ complexity. The numbers are ceilings, calibrated so considered code stays silent and runaway
94
+ generation does not. Tune them with `limits`.
95
+ 2. **Defect classes `correctness` misses** — import cycles, in-place `.sort()`/`.reverse()` on
96
+ arrays that may be shared, hook-order violations, `.then()` without a return, dead stores.
97
+ 3. **Test discipline** — the vitest plugin, including `expect-expect`, which catches a test that
98
+ runs, passes, and asserts nothing.
99
+ 4. **Mechanical hygiene** — literal form, import discipline, modern-API preference. All autofixable
100
+ via `oxlint --fix`.
101
+
102
+ The design record lives in `docs/superpowers/specs/2026-07-28-oxlint-legibility-tiers-design.md`,
103
+ including a register of the rules that were measured and **turned down**. Check it before enabling
104
+ something that looks like an oversight — `no-magic-numbers` in particular is off on purpose, and
105
+ `verify-fixtures.mjs` fails the build if it or eleven others are switched on.
106
+
107
+ ### Named thresholds and documented constants
108
+
109
+ Two opt-in rules, complements rather than duplicates:
110
+
111
+ - `unnamedThresholds` flags a number used as a comparison threshold — `if (entries.length > 12)`.
112
+ Numbers inside array and object literals are untouched, so a bounding box or a codepoint table
113
+ stays silent. Radix-prefixed literals are exempt by default: `cp >= 0x3040` already reads as a
114
+ codepoint boundary.
115
+ - `constantDocs` requires a JSDoc block on module-level constants that are exported or
116
+ `SCREAMING_CASE` — the two signals that a constant is public surface or a tuning knob.
117
+ Function-valued constants are out of scope.
118
+
119
+ The first says a threshold needs a name; the second says a name needs an explanation. A data table
120
+ satisfies both by documenting the table, rather than extracting a constant per row.
121
+
122
+ Write provenance in those blocks — what the value means and where it came from:
123
+
124
+ ```ts
125
+ /** Entries above this count mean the surface is too ambiguous to disambiguate; set by the 2026-03 sweep. */
126
+ const AMBIGUITY_CEILING = 12
127
+ ```
128
+
129
+ Not `/** The ambiguity ceiling. */`, which leaves the reader exactly where they started.
130
+
131
+ ### Length checks
132
+
133
+ The house convention is truthiness — `if (items.length)`, not `if (items.length > 0)`.
134
+ `sister-software/prefer-length-truthiness` enforces it and autofixes, which is why
135
+ `unicorn/explicit-length-check` (which enforces the opposite) is off.
136
+
137
+ It only rewrites where the value is already coerced to a boolean — a condition, a ternary test, the
138
+ operand of `!`, or a `&&`/`||` inside one of those. Elsewhere the comparison *is* the value, and
139
+ rewriting it would change the type:
140
+
141
+ ```ts
142
+ if (items.length > 0) { … } // → if (items.length)
143
+ if (items.length === 0) { … } // → if (!items.length)
144
+ const hasItems = items.length > 0 // untouched — this is a boolean, not a condition
145
+ if (items.length === 2) { … } // untouched — not an emptiness check
146
+ ```
147
+
148
+ ### Escape hatch
149
+
150
+ Both rules, and every tier rule, take a scoped disable with a stated reason:
151
+
152
+ ```ts
153
+ // oxlint-disable-next-line max-statements -- generated dispatch table; splitting it hides the shape.
154
+ ```
155
+
156
+ Prefer that over a config-level exemption, which silently widens to every future file.
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ * @file A require-constant-doc rule, authored as an oxlint JS plugin (ESLint v9-compatible API). A
6
+ * module-level constant that is exported or SCREAMING_CASE is either public surface or a tuning
7
+ * knob, and in both cases a reader needs to know what the value means and where it came from. A
8
+ * documented table also answers for every number inside it, which is why data-heavy files satisfy
9
+ * this rule without extracting a constant per row.
10
+ */
11
+ import type { Rule } from "./plugin-types.js";
12
+ /** Which module-level constants the rule applies to. */
13
+ export type ConstantDocScope = "exported" | "screaming" | "exported-or-screaming";
14
+ /** Options accepted by {@link requireConstantDocRule}. */
15
+ export interface ConstantDocOptions {
16
+ /** Defaults to `"exported-or-screaming"`. */
17
+ scope?: ConstantDocScope;
18
+ /**
19
+ * Export names a framework requires and gives meaning to, which a JSDoc block cannot improve on — Pastel's
20
+ * `description` (whose value IS the help text), a route module's `loader`, and so on.
21
+ */
22
+ ignoreNames?: string[];
23
+ }
24
+ export declare const requireConstantDocRule: Rule;
25
+ export default requireConstantDocRule;
26
+ //# sourceMappingURL=constant-doc-plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constant-doc-plugin.d.ts","sourceRoot":"","sources":["../src/constant-doc-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAA;AAQ7C,wDAAwD;AACxD,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,WAAW,GAAG,uBAAuB,CAAA;AAEjF,0DAA0D;AAC1D,MAAM,WAAW,kBAAkB;IAClC,6CAA6C;IAC7C,KAAK,CAAC,EAAE,gBAAgB,CAAA;IACxB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CACtB;AAED,eAAO,MAAM,sBAAsB,EAAE,IA8EpC,CAAA;AAED,eAAe,sBAAsB,CAAA"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ * @file A require-constant-doc rule, authored as an oxlint JS plugin (ESLint v9-compatible API). A
6
+ * module-level constant that is exported or SCREAMING_CASE is either public surface or a tuning
7
+ * knob, and in both cases a reader needs to know what the value means and where it came from. A
8
+ * documented table also answers for every number inside it, which is why data-heavy files satisfy
9
+ * this rule without extracting a constant per row.
10
+ */
11
+ /** Names in SCREAMING_SNAKE_CASE, the convention for a tuning knob. */
12
+ const SCREAMING_CASE = /^[A-Z][A-Z0-9_]*$/;
13
+ /** Initializers that make the binding a function rather than a constant value. */
14
+ const FUNCTION_INITIALIZERS = new Set(["ArrowFunctionExpression", "FunctionExpression"]);
15
+ export const requireConstantDocRule = {
16
+ meta: {
17
+ name: "require-constant-doc",
18
+ type: "suggestion",
19
+ schema: [{ type: "object", additionalProperties: true }],
20
+ },
21
+ create(context) {
22
+ const options = (context.options[0] ?? {});
23
+ const scope = options.scope ?? "exported-or-screaming";
24
+ const ignoreNames = new Set(options.ignoreNames);
25
+ const sourceCode = context.sourceCode ?? context.getSourceCode();
26
+ const text = sourceCode.getText();
27
+ const comments = sourceCode.getAllComments();
28
+ /**
29
+ * True when a JSDoc block documents the declaration starting at `start`.
30
+ *
31
+ * Attachment requires the comment to be directly above it — whitespace spanning a single newline. A blank line in
32
+ * between means the comment belongs to something else, which is what separates a declaration's own JSDoc from the
33
+ * file header block that precedes the first declaration in every file.
34
+ */
35
+ function hasJSDocBefore(start) {
36
+ for (const comment of comments) {
37
+ if (comment.range[1] > start)
38
+ continue;
39
+ if (comment.type !== "Block" || !comment.value.startsWith("*"))
40
+ continue;
41
+ const gap = text.slice(comment.range[1], start);
42
+ if (/^\s*$/.test(gap) && (gap.match(/\n/g) ?? []).length <= 1)
43
+ return true;
44
+ }
45
+ return false;
46
+ }
47
+ function inScope(exported, screaming) {
48
+ if (scope === "exported")
49
+ return exported;
50
+ if (scope === "screaming")
51
+ return screaming;
52
+ return exported || screaming;
53
+ }
54
+ return {
55
+ VariableDeclaration(node) {
56
+ if (node.kind !== "const")
57
+ return;
58
+ const exported = node.parent?.type === "ExportNamedDeclaration";
59
+ const container = exported ? node.parent : node;
60
+ // Module level only: the declaration (or its export wrapper) sits directly in Program.
61
+ if (container.parent?.type !== "Program")
62
+ return;
63
+ if (hasJSDocBefore(container.range[0]))
64
+ return;
65
+ for (const declarator of node.declarations ?? []) {
66
+ const id = declarator.id;
67
+ if (id?.type !== "Identifier" || !id.name)
68
+ continue;
69
+ if (ignoreNames.has(id.name))
70
+ continue;
71
+ const initializer = declarator.init;
72
+ if (initializer && FUNCTION_INITIALIZERS.has(initializer.type))
73
+ continue;
74
+ if (!inScope(exported, SCREAMING_CASE.test(id.name)))
75
+ continue;
76
+ context.report({
77
+ node: declarator,
78
+ message: `\`${id.name}\` is ${exported ? "exported" : "a named constant"} but undocumented — add a ` +
79
+ `JSDoc block saying what the value means and where it came from.`,
80
+ });
81
+ }
82
+ },
83
+ };
84
+ },
85
+ };
86
+ export default requireConstantDocRule;
87
+ //# sourceMappingURL=constant-doc-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constant-doc-plugin.js","sourceRoot":"","sources":["../src/constant-doc-plugin.ts"],"names":[],"mappings":"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"}
@@ -49,7 +49,7 @@ export const headerRule = {
49
49
  if (leading) {
50
50
  const existing = parseInnerLines(leading);
51
51
  const missing = headerLines.filter((line) => !existing.includes(line));
52
- if (missing.length === 0)
52
+ if (!missing.length)
53
53
  return;
54
54
  const preserved = existing.filter((line) => !HEADER_TAG_PATTERN.test(line));
55
55
  const block = buildBlock(preserved);
@@ -1 +1 @@
1
- {"version":3,"file":"headers-plugin.js","sourceRoot":"","sources":["../src/headers-plugin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"headers-plugin.js","sourceRoot":"","sources":["../src/headers-plugin.ts"],"names":[],"mappings":"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"}
package/out/index.d.ts CHANGED
@@ -7,6 +7,52 @@
7
7
  export * from "./restrictions.js";
8
8
  /** An oxlint configuration object, as consumed by `oxlint.config.ts` / `.oxlintrc.json`. */
9
9
  export type OxlintConfig = Record<string, unknown>;
10
+ /** Numeric ceilings for the legibility-guardrail rules. Each is a hard ceiling, not a target. */
11
+ export interface OxlintConfigLimits {
12
+ /** Maximum block nesting depth. */
13
+ maxDepth: number;
14
+ /** Maximum parameters on a single function. */
15
+ maxParams: number;
16
+ /** Maximum statements in a single function body. */
17
+ maxStatements: number;
18
+ /** Maximum lines in a single function body, blank lines and comments excluded. */
19
+ maxLinesPerFunction: number;
20
+ /** Maximum lines in a single file, blank lines and comments excluded. */
21
+ maxLines: number;
22
+ /** Maximum nested callback depth. */
23
+ maxNestedCallbacks: number;
24
+ /** Maximum nested call-expression depth, e.g. `a(b(c(d())))`. */
25
+ maxNestedCalls: number;
26
+ /** Maximum cyclomatic complexity of a single function. */
27
+ complexity: number;
28
+ }
29
+ /**
30
+ * Calibrated against the mailwoman corpus (1,048 non-test source files). Each value sits just past the knee in that
31
+ * repo's distribution, so considered human code stays silent and runaway generation does not. See the design spec for
32
+ * the full sweep.
33
+ *
34
+ * The four SIZE ceilings are deliberately looser than the knee. Adopting v10 surfaced 172 pre-existing violations, and
35
+ * splitting that many functions across a parser — with no accuracy gate available to verify the result — is a larger
36
+ * risk than the legibility it buys. They are set at the p90 of the measured overage instead, so the worst decile had to
37
+ * be fixed at adoption while the body was grandfathered:
38
+ *
39
+ * max-statements n=88 median= 73 p90= 115 max= 272
40
+ * complexity n=32 median= 49 p90= 84 max= 173
41
+ * max-lines-per-function n=26 median=283 p90= 829 max=1329
42
+ * max-params n=15 median= 7 p90= 8 max= 10
43
+ *
44
+ * RATCHET THESE DOWN as the grandfathered functions are split. They exist to stop new code drifting, and every step
45
+ * toward the knee makes them do more of that job.
46
+ */
47
+ export declare const DefaultLimits: OxlintConfigLimits;
48
+ /** Globs treated as test files, where the size and named-constant rules are switched off. */
49
+ export declare const DefaultTestFilePatterns: string[];
50
+ /**
51
+ * Globs whose contents are emitted by a generator, not written by hand. The size ceilings are meaningless there — the
52
+ * file is as long as its input is wide, and no reviewer reads it top to bottom — but every correctness rule still
53
+ * applies, because generated code ships.
54
+ */
55
+ export declare const DefaultGeneratedFilePatterns: string[];
10
56
  /** Options for {@link createOxlintConfig}. */
11
57
  export interface OxlintConfigOptions {
12
58
  /** The package namespace whose runtime boundaries are enforced, e.g. `@sister.software`. */
@@ -30,12 +76,35 @@ export interface OxlintConfigOptions {
30
76
  * through blessed helpers, which disable `sister-software/no-process-globals`.
31
77
  */
32
78
  restrictProcessGlobals?: boolean;
79
+ /**
80
+ * Flag numeric literals used as comparison thresholds (off by default). Pass an object to change the ignore list or
81
+ * to stop exempting radix-prefixed literals.
82
+ */
83
+ unnamedThresholds?: boolean | {
84
+ ignore?: number[];
85
+ allowHex?: boolean;
86
+ };
87
+ /**
88
+ * Require a JSDoc block on module-level constants (off by default). `scope` selects which ones: `"exported"`,
89
+ * `"screaming"`, or the default `"exported-or-screaming"`.
90
+ */
91
+ constantDocs?: boolean | {
92
+ scope?: "exported" | "screaming" | "exported-or-screaming";
93
+ };
94
+ /** Rewrite explicit length comparisons to truthiness in boolean positions (on by default). */
95
+ lengthTruthiness?: boolean;
96
+ /** Override individual legibility ceilings. Unspecified keys keep their calibrated default. */
97
+ limits?: Partial<OxlintConfigLimits>;
98
+ /** Replace the globs treated as test files. */
99
+ testFilePatterns?: string[];
100
+ /** Replace the globs treated as generated files, where only the size ceilings are switched off. */
101
+ generatedFilePatterns?: string[];
33
102
  /** Override the default ignore patterns. */
34
103
  ignorePatterns?: string[];
35
104
  /** Extra config deep-merged last; an escape hatch for per-repo tweaks. */
36
105
  overrides?: OxlintConfig;
37
106
  }
38
- /** Default ignore patterns for generated/build output. */
107
+ /** Default ignore patterns for generated/build output and vendored tooling. */
39
108
  export declare const DefaultIgnorePatterns: string[];
40
109
  /**
41
110
  * Builds the complete oxlint configuration for a Sister Software package.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,cAAc,mBAAmB,CAAA;AAEjC,4FAA4F;AAC5F,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAElD,8CAA8C;AAC9C,MAAM,WAAW,mBAAmB;IACnC,4FAA4F;IAC5F,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,sDAAsD;IACtD,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,6DAA6D;IAC7D,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,qDAAqD;IACrD,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,kFAAkF;IAClF,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gGAAgG;IAChG,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB;;;OAGG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,4CAA4C;IAC5C,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;IACzB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,YAAY,CAAA;CACxB;AAED,0DAA0D;AAC1D,eAAO,MAAM,qBAAqB,UAOjC,CAAA;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,mBAAwB,GAAG,YAAY,CAkFlF;AAED,eAAe,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,cAAc,mBAAmB,CAAA;AAEjC,4FAA4F;AAC5F,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAElD,iGAAiG;AACjG,MAAM,WAAW,kBAAkB;IAClC,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAA;IAChB,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAA;IACjB,oDAAoD;IACpD,aAAa,EAAE,MAAM,CAAA;IACrB,kFAAkF;IAClF,mBAAmB,EAAE,MAAM,CAAA;IAC3B,yEAAyE;IACzE,QAAQ,EAAE,MAAM,CAAA;IAChB,qCAAqC;IACrC,kBAAkB,EAAE,MAAM,CAAA;IAC1B,iEAAiE;IACjE,cAAc,EAAE,MAAM,CAAA;IACtB,0DAA0D;IAC1D,UAAU,EAAE,MAAM,CAAA;CAClB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,aAAa,EAAE,kBAS3B,CAAA;AAED,6FAA6F;AAC7F,eAAO,MAAM,uBAAuB,UAWnC,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,UAA0E,CAAA;AAEnH,8CAA8C;AAC9C,MAAM,WAAW,mBAAmB;IACnC,4FAA4F;IAC5F,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,sDAAsD;IACtD,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,6DAA6D;IAC7D,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,qDAAqD;IACrD,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,kFAAkF;IAClF,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gGAAgG;IAChG,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB;;;OAGG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,GAAG;QAAE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAA;IACvE;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG;QAAE,KAAK,CAAC,EAAE,UAAU,GAAG,WAAW,GAAG,uBAAuB,CAAA;KAAE,CAAA;IACvF,8FAA8F;IAC9F,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,+FAA+F;IAC/F,MAAM,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAA;IACpC,+CAA+C;IAC/C,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC3B,mGAAmG;IACnG,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAA;IAChC,4CAA4C;IAC5C,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;IACzB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,YAAY,CAAA;CACxB;AAED,+EAA+E;AAC/E,eAAO,MAAM,qBAAqB,UAUjC,CAAA;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,mBAAwB,GAAG,YAAY,CAuUlF;AAED,eAAe,kBAAkB,CAAA"}