@goodbones/oxlint 0.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/build/dts/config-loader.d.ts +5 -0
- package/build/dts/config-loader.d.ts.map +1 -0
- package/build/dts/exports-rule.d.ts +4 -0
- package/build/dts/exports-rule.d.ts.map +1 -0
- package/build/dts/imports-rule.d.ts +4 -0
- package/build/dts/imports-rule.d.ts.map +1 -0
- package/build/dts/members-rule.d.ts +4 -0
- package/build/dts/members-rule.d.ts.map +1 -0
- package/build/dts/oxlint-api.d.ts +46 -0
- package/build/dts/oxlint-api.d.ts.map +1 -0
- package/build/dts/plugin.d.ts +16 -0
- package/build/dts/plugin.d.ts.map +1 -0
- package/build/dts/structure-rule.d.ts +4 -0
- package/build/dts/structure-rule.d.ts.map +1 -0
- package/build/dts/surface-rule.d.ts +4 -0
- package/build/dts/surface-rule.d.ts.map +1 -0
- package/build/esm/config-loader.js +24 -0
- package/build/esm/config-loader.js.map +1 -0
- package/build/esm/exports-rule.js +137 -0
- package/build/esm/exports-rule.js.map +1 -0
- package/build/esm/imports-rule.js +71 -0
- package/build/esm/imports-rule.js.map +1 -0
- package/build/esm/members-rule.js +138 -0
- package/build/esm/members-rule.js.map +1 -0
- package/build/esm/oxlint-api.js +24 -0
- package/build/esm/oxlint-api.js.map +1 -0
- package/build/esm/plugin.js +30 -0
- package/build/esm/plugin.js.map +1 -0
- package/build/esm/structure-rule.js +36 -0
- package/build/esm/structure-rule.js.map +1 -0
- package/build/esm/surface-rule.js +161 -0
- package/build/esm/surface-rule.js.map +1 -0
- package/package.json +67 -0
- package/src/config-loader.ts +35 -0
- package/src/exports-rule.ts +195 -0
- package/src/imports-rule.ts +96 -0
- package/src/members-rule.ts +205 -0
- package/src/oxlint-api.ts +66 -0
- package/src/plugin.ts +44 -0
- package/src/structure-rule.ts +38 -0
- package/src/surface-rule.ts +237 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Data Quail
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type LoadedPolicy } from "@goodbones/core";
|
|
2
|
+
export type { LoadedPolicy } from "@goodbones/core";
|
|
3
|
+
export { DEFAULT_CONFIG_FILENAME } from "@goodbones/core";
|
|
4
|
+
export declare const loadPolicyFromFile: (repoRoot: string, configFilename?: string) => Promise<LoadedPolicy>;
|
|
5
|
+
//# sourceMappingURL=config-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../src/config-loader.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,YAAY,EAIlB,MAAM,iBAAiB,CAAC;AAIzB,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAO1D,eAAO,MAAM,kBAAkB,aACnB,MAAM,mBACA,MAAM,KACrB,OAAO,CAAC,YAAY,CAWtB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exports-rule.d.ts","sourceRoot":"","sources":["../../src/exports-rule.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,YAAY,EAElB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAOL,KAAK,UAAU,EAKhB,MAAM,iBAAiB,CAAC;AA4EzB,eAAO,MAAM,eAAe,WAAY,YAAY,KAAG,UAgGrD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"imports-rule.d.ts","sourceRoot":"","sources":["../../src/imports-rule.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,YAAY,EAGlB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAML,KAAK,UAAU,EAOhB,MAAM,iBAAiB,CAAC;AAOzB,eAAO,MAAM,eAAe,WAAY,YAAY,KAAG,UAkErD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"members-rule.d.ts","sourceRoot":"","sources":["../../src/members-rule.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,YAAY,EAElB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,KAAK,UAAU,EAIhB,MAAM,iBAAiB,CAAC;AAsGzB,eAAO,MAAM,eAAe,WAAY,YAAY,KAAG,UAwFrD,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { RuleTester } from "oxlint/plugins-dev";
|
|
2
|
+
export type OxlintRule = Parameters<RuleTester["run"]>[1];
|
|
3
|
+
export type RuleContext = Parameters<Extract<OxlintRule, {
|
|
4
|
+
createOnce: unknown;
|
|
5
|
+
}>["createOnce"]>[0];
|
|
6
|
+
type Diagnostic = Parameters<RuleContext["report"]>[0];
|
|
7
|
+
export type ReportableNode = Extract<Diagnostic, {
|
|
8
|
+
node: unknown;
|
|
9
|
+
}>["node"];
|
|
10
|
+
export type Fixer = Parameters<NonNullable<Diagnostic["fix"]>>[0];
|
|
11
|
+
export type SourceNode = ReportableNode & {
|
|
12
|
+
readonly source?: {
|
|
13
|
+
readonly value?: unknown;
|
|
14
|
+
} | null;
|
|
15
|
+
};
|
|
16
|
+
export declare const toRepoRelative: (repoRoot: string, filename: string) => string;
|
|
17
|
+
export declare const specifierOf: (node: SourceNode) => string | null;
|
|
18
|
+
export type CallNode = ReportableNode & {
|
|
19
|
+
readonly callee?: {
|
|
20
|
+
readonly type: string;
|
|
21
|
+
readonly name?: unknown;
|
|
22
|
+
} | null;
|
|
23
|
+
readonly arguments?: ReadonlyArray<{
|
|
24
|
+
readonly type: string;
|
|
25
|
+
readonly value?: unknown;
|
|
26
|
+
}> | null;
|
|
27
|
+
};
|
|
28
|
+
export type ImportExpressionNode = ReportableNode & {
|
|
29
|
+
readonly source?: {
|
|
30
|
+
readonly type?: string;
|
|
31
|
+
readonly value?: unknown;
|
|
32
|
+
} | null;
|
|
33
|
+
};
|
|
34
|
+
export type ImportEqualsNode = ReportableNode & {
|
|
35
|
+
readonly moduleReference?: {
|
|
36
|
+
readonly type: string;
|
|
37
|
+
readonly expression?: {
|
|
38
|
+
readonly value?: unknown;
|
|
39
|
+
} | null;
|
|
40
|
+
} | null;
|
|
41
|
+
};
|
|
42
|
+
export declare const requireSpecifierOf: (node: CallNode) => string | null;
|
|
43
|
+
export declare const importExpressionSpecifierOf: (node: ImportExpressionNode) => string | null;
|
|
44
|
+
export declare const importEqualsSpecifierOf: (node: ImportEqualsNode) => string | null;
|
|
45
|
+
export {};
|
|
46
|
+
//# sourceMappingURL=oxlint-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oxlint-api.d.ts","sourceRoot":"","sources":["../../src/oxlint-api.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAKrD,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1D,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,CAAC,UAAU,EAAE;IAAE,UAAU,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAEpG,KAAK,UAAU,GAAG,UAAU,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvD,MAAM,MAAM,cAAc,GAAG,OAAO,CAAC,UAAU,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC,MAAM,CAAC,CAAC;AAC5E,MAAM,MAAM,KAAK,GAAG,UAAU,CAAC,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAElE,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG;IACxC,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;CACvD,CAAC;AAEF,eAAO,MAAM,cAAc,aAAc,MAAM,YAAY,MAAM,KAAG,MACP,CAAC;AAE9D,eAAO,MAAM,WAAW,SAAU,UAAU,KAAG,MAAM,GAAG,IAGvD,CAAC;AAOF,MAAM,MAAM,QAAQ,GAAG,cAAc,GAAG;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IAC5E,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,GAAG,IAAI,CAAC;CAChG,CAAC;AAGF,MAAM,MAAM,oBAAoB,GAAG,cAAc,GAAG;IAClD,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;CAC/E,CAAC;AAGF,MAAM,MAAM,gBAAgB,GAAG,cAAc,GAAG;IAC9C,QAAQ,CAAC,eAAe,CAAC,EAAE;QACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,UAAU,CAAC,EAAE;YAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;SAAE,GAAG,IAAI,CAAC;KAC3D,GAAG,IAAI,CAAC;CACV,CAAC;AAEF,eAAO,MAAM,kBAAkB,SAAU,QAAQ,KAAG,MAAM,GAAG,IAI5D,CAAC;AAEF,eAAO,MAAM,2BAA2B,SAAU,oBAAoB,KAAG,MAAM,GAAG,IAGjF,CAAC;AAEF,eAAO,MAAM,uBAAuB,SAAU,gBAAgB,KAAG,MAAM,GAAG,IAKzE,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { OxlintRule } from "./oxlint-api.js";
|
|
2
|
+
export declare const rules: {
|
|
3
|
+
readonly imports: OxlintRule;
|
|
4
|
+
readonly exports: OxlintRule;
|
|
5
|
+
readonly members: OxlintRule;
|
|
6
|
+
readonly structure: OxlintRule;
|
|
7
|
+
readonly surface: OxlintRule;
|
|
8
|
+
};
|
|
9
|
+
declare const plugin: {
|
|
10
|
+
readonly meta: {
|
|
11
|
+
readonly name: string;
|
|
12
|
+
};
|
|
13
|
+
readonly rules: typeof rules;
|
|
14
|
+
};
|
|
15
|
+
export default plugin;
|
|
16
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/plugin.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAoBlD,eAAO,MAAM,KAAK,EAAE;IAClB,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;CAO9B,CAAC;AAEF,QAAA,MAAM,MAAM,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,KAAK,CAAA;CAGrF,CAAC;eAEa,MAAM"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structure-rule.d.ts","sourceRoot":"","sources":["../../src/structure-rule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEtF,OAAO,EAAE,KAAK,UAAU,EAAoC,MAAM,iBAAiB,CAAC;AAEpF,eAAO,MAAM,iBAAiB,WAAY,YAAY,KAAG,UAiCvD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surface-rule.d.ts","sourceRoot":"","sources":["../../src/surface-rule.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,YAAY,EAElB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,KAAK,UAAU,EAIhB,MAAM,iBAAiB,CAAC;AA+KzB,eAAO,MAAM,eAAe,WAAY,YAAY,KAAG,UA8CrD,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
import { DEFAULT_CONFIG_FILENAME, loadPolicy, makeFileSystemLive, readManifestFile, } from "@goodbones/core";
|
|
3
|
+
import { typescriptLanguage } from "@goodbones/typescript";
|
|
4
|
+
import * as Result from "effect/Result";
|
|
5
|
+
export { DEFAULT_CONFIG_FILENAME } from "@goodbones/core";
|
|
6
|
+
// The plugin's composition root: read the manifest file, construct the
|
|
7
|
+
// language packs and the live file system, and hand them to the loader. A load
|
|
8
|
+
// failure throws out of here and out of oxlint's import of the plugin — a
|
|
9
|
+
// plugin that came up with no policy would report nothing and be
|
|
10
|
+
// indistinguishable from a clean codebase.
|
|
11
|
+
export const loadPolicyFromFile = async (repoRoot, configFilename = DEFAULT_CONFIG_FILENAME) => {
|
|
12
|
+
const configPath = path.resolve(repoRoot, configFilename);
|
|
13
|
+
const loaded = loadPolicy({
|
|
14
|
+
repoRoot,
|
|
15
|
+
configPath,
|
|
16
|
+
manifest: await readManifestFile(configPath),
|
|
17
|
+
languages: [typescriptLanguage()],
|
|
18
|
+
fileSystem: makeFileSystemLive(repoRoot),
|
|
19
|
+
});
|
|
20
|
+
if (Result.isFailure(loaded))
|
|
21
|
+
throw loaded.failure;
|
|
22
|
+
return loaded.success;
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=config-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../../src/config-loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EACL,uBAAuB,EAEvB,UAAU,EACV,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAGxC,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,uEAAuE;AACvE,+EAA+E;AAC/E,0EAA0E;AAC1E,iEAAiE;AACjE,2CAA2C;AAC3C,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,EACrC,QAAgB,EAChB,cAAc,GAAW,uBAAuB,EACzB,EAAE;IACzB,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAG,UAAU,CAAC;QACxB,QAAQ;QACR,UAAU;QACV,QAAQ,EAAE,MAAM,gBAAgB,CAAC,UAAU,CAAC;QAC5C,SAAS,EAAE,CAAC,kBAAkB,EAAE,CAAC;QACjC,UAAU,EAAE,kBAAkB,CAAC,QAAQ,CAAC;KACzC,CAAC,CAAC;IACH,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC;QAAE,MAAM,MAAM,CAAC,OAAO,CAAC;IACnD,OAAO,MAAM,CAAC,OAAO,CAAC;AACxB,CAAC,CAAC"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { evaluateSelectedBindings, exportRulesSelecting, formatMessage, } from "@goodbones/core";
|
|
2
|
+
import * as Result from "effect/Result";
|
|
3
|
+
import { importEqualsSpecifierOf, importExpressionSpecifierOf, requireSpecifierOf, toRepoRelative, } from "./oxlint-api.js";
|
|
4
|
+
const nameOf = (node) => {
|
|
5
|
+
if (node === null || node === undefined)
|
|
6
|
+
return null;
|
|
7
|
+
if (typeof node.name === "string")
|
|
8
|
+
return node.name;
|
|
9
|
+
// `import { "a-b" as ab }` — a string-literal export name.
|
|
10
|
+
return typeof node.value === "string" ? node.value : null;
|
|
11
|
+
};
|
|
12
|
+
// The whole module, as one binding. `export * from "m"`, `export * as ns from
|
|
13
|
+
// "m"`, `import x = require("m")`, `import("m")` and `require("m")` all carry
|
|
14
|
+
// every export of `m` at once, exactly as `import * as ns` does — and are the
|
|
15
|
+
// same way around a rule about a name. A side-effect import carries nothing.
|
|
16
|
+
const wholeModule = (node, local = "") => ({
|
|
17
|
+
symbol: "*",
|
|
18
|
+
kind: "namespace",
|
|
19
|
+
node,
|
|
20
|
+
local,
|
|
21
|
+
});
|
|
22
|
+
const boundOf = (specifier) => {
|
|
23
|
+
const local = nameOf(specifier.local) ?? "";
|
|
24
|
+
switch (specifier.type) {
|
|
25
|
+
case "ImportSpecifier": {
|
|
26
|
+
const symbol = nameOf(specifier.imported);
|
|
27
|
+
return symbol === null ? null : { symbol, kind: "named", node: specifier, local };
|
|
28
|
+
}
|
|
29
|
+
case "ImportDefaultSpecifier":
|
|
30
|
+
return { symbol: "default", kind: "default", node: specifier, local };
|
|
31
|
+
case "ImportNamespaceSpecifier":
|
|
32
|
+
return { symbol: "*", kind: "namespace", node: specifier, local };
|
|
33
|
+
// `export { a } from "…"` — `local` is the name in the source module.
|
|
34
|
+
case "ExportSpecifier": {
|
|
35
|
+
const symbol = nameOf(specifier.local);
|
|
36
|
+
return symbol === null ? null : { symbol, kind: "named", node: specifier, local: symbol };
|
|
37
|
+
}
|
|
38
|
+
default:
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
const specifierOf = (node) => {
|
|
43
|
+
const value = node.source?.value;
|
|
44
|
+
return typeof value === "string" ? value : null;
|
|
45
|
+
};
|
|
46
|
+
const boundSpecifiers = (node) => (node.specifiers ?? []).map(boundOf).filter((one) => one !== null);
|
|
47
|
+
// `import { A, B as C } from "pkg"` becomes `import * as A from "pkg/A"` and
|
|
48
|
+
// `import * as C from "pkg/B"`. Only whole-declaration rewrites are offered: a
|
|
49
|
+
// declaration mixing restricted named imports with a default or namespace one
|
|
50
|
+
// would need comma surgery inside the braces, and a fix that is subtly wrong is
|
|
51
|
+
// worse than a diagnostic the author resolves by hand.
|
|
52
|
+
const subpathNamespaceImport = (specifier, bound) => bound
|
|
53
|
+
.map((binding) => `import * as ${binding.local} from "${specifier}/${binding.symbol}";`)
|
|
54
|
+
.join("\n");
|
|
55
|
+
export const makeExportsRule = (policy) => ({
|
|
56
|
+
meta: {
|
|
57
|
+
type: "problem",
|
|
58
|
+
fixable: "code",
|
|
59
|
+
docs: {
|
|
60
|
+
description: "which exported symbols a file may import, for rules a path alone cannot express",
|
|
61
|
+
},
|
|
62
|
+
schema: [],
|
|
63
|
+
},
|
|
64
|
+
createOnce(context) {
|
|
65
|
+
let importer = "";
|
|
66
|
+
let selected = [];
|
|
67
|
+
// `fixable` is whether a rewrite could apply: only an `import` declaration
|
|
68
|
+
// can be rewritten into subpath namespace imports. `export *` and the
|
|
69
|
+
// whole-module forms are reported and left for the author.
|
|
70
|
+
const check = (node, specifierValue, bound, fixable) => {
|
|
71
|
+
if (specifierValue === null || bound.length === 0)
|
|
72
|
+
return;
|
|
73
|
+
const outcome = evaluateSelectedBindings(selected, policy.resolver, {
|
|
74
|
+
importer,
|
|
75
|
+
specifier: specifierValue,
|
|
76
|
+
bindings: bound,
|
|
77
|
+
});
|
|
78
|
+
if (Result.isFailure(outcome)) {
|
|
79
|
+
// `architecture/imports` reports the same unresolved edge, so staying
|
|
80
|
+
// quiet here avoids two diagnostics for one broken specifier.
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
for (const { bindings, rule, violation } of outcome.success) {
|
|
84
|
+
if (policy.baseline.isBaselined(violation))
|
|
85
|
+
continue;
|
|
86
|
+
const offending = bound.filter((one) => bindings.some((binding) => binding.symbol === one.symbol && binding.kind === one.kind));
|
|
87
|
+
// The rewrite is `import * as X from "pkg/<name>"`, which only means
|
|
88
|
+
// something for a named binding — a namespace one has no name to put
|
|
89
|
+
// in the subpath.
|
|
90
|
+
const rewritable = fixable &&
|
|
91
|
+
rule.fix === "subpath-namespace-import" &&
|
|
92
|
+
offending.length === bound.length &&
|
|
93
|
+
offending.every((one) => one.kind === "named");
|
|
94
|
+
if (rewritable) {
|
|
95
|
+
context.report({
|
|
96
|
+
node,
|
|
97
|
+
message: formatMessage(violation),
|
|
98
|
+
fix: (fixer) => fixer.replaceText(node, subpathNamespaceImport(specifierValue, offending)),
|
|
99
|
+
});
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
context.report({
|
|
103
|
+
node: offending[0]?.node ?? node,
|
|
104
|
+
message: formatMessage(violation),
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
return {
|
|
109
|
+
before() {
|
|
110
|
+
importer = toRepoRelative(policy.repoRoot, context.filename);
|
|
111
|
+
if (importer.startsWith(".."))
|
|
112
|
+
return false;
|
|
113
|
+
selected = exportRulesSelecting(policy.exportRules, importer);
|
|
114
|
+
return selected.length > 0;
|
|
115
|
+
},
|
|
116
|
+
ImportDeclaration(node) {
|
|
117
|
+
check(node, specifierOf(node), boundSpecifiers(node), true);
|
|
118
|
+
},
|
|
119
|
+
ExportNamedDeclaration(node) {
|
|
120
|
+
check(node, specifierOf(node), boundSpecifiers(node), false);
|
|
121
|
+
},
|
|
122
|
+
ExportAllDeclaration(node) {
|
|
123
|
+
check(node, specifierOf(node), [wholeModule(node, nameOf(node.exported) ?? "")], false);
|
|
124
|
+
},
|
|
125
|
+
ImportExpression(node) {
|
|
126
|
+
check(node, importExpressionSpecifierOf(node), [wholeModule(node)], false);
|
|
127
|
+
},
|
|
128
|
+
CallExpression(node) {
|
|
129
|
+
check(node, requireSpecifierOf(node), [wholeModule(node)], false);
|
|
130
|
+
},
|
|
131
|
+
TSImportEqualsDeclaration(node) {
|
|
132
|
+
check(node, importEqualsSpecifierOf(node), [wholeModule(node)], false);
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
//# sourceMappingURL=exports-rule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exports-rule.js","sourceRoot":"","sources":["../../src/exports-rule.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { evaluateSelectedEdge, formatMessage, rulesSelecting, } from "@goodbones/core";
|
|
2
|
+
import * as Result from "effect/Result";
|
|
3
|
+
import { importEqualsSpecifierOf, importExpressionSpecifierOf, requireSpecifierOf, specifierOf, toRepoRelative, } from "./oxlint-api.js";
|
|
4
|
+
const unresolvedMessage = (specifier, detail) => `[unresolved-import] "${specifier}" could not be resolved, so every import rule about it ` +
|
|
5
|
+
`enforces nothing. Fix the resolve scope in the architecture config, or list the specifier ` +
|
|
6
|
+
`in resolve.ignoreUnresolved. (${detail})`;
|
|
7
|
+
export const makeImportsRule = (policy) => ({
|
|
8
|
+
meta: {
|
|
9
|
+
type: "problem",
|
|
10
|
+
docs: {
|
|
11
|
+
description: "import boundaries between folders and packages, matched against fully resolved module paths",
|
|
12
|
+
},
|
|
13
|
+
schema: [],
|
|
14
|
+
},
|
|
15
|
+
// `createOnce` is what makes resolution affordable: the resolver and the
|
|
16
|
+
// compiled rules are built once per lint run, and `before` decides per file
|
|
17
|
+
// whether any rule selects it at all — a file none select is skipped whole.
|
|
18
|
+
createOnce(context) {
|
|
19
|
+
let importer = "";
|
|
20
|
+
let selected = [];
|
|
21
|
+
const check = (node, specifier) => {
|
|
22
|
+
if (specifier === null)
|
|
23
|
+
return;
|
|
24
|
+
const outcome = evaluateSelectedEdge(selected, policy.resolver, { importer, specifier });
|
|
25
|
+
if (Result.isFailure(outcome)) {
|
|
26
|
+
if (policy.config.resolve.unresolved === "off")
|
|
27
|
+
return;
|
|
28
|
+
if (policy.ignoreUnresolved.some((pattern) => pattern.test(specifier)))
|
|
29
|
+
return;
|
|
30
|
+
context.report({ node, message: unresolvedMessage(specifier, outcome.failure.detail) });
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
for (const violation of outcome.success) {
|
|
34
|
+
if (policy.baseline.isBaselined(violation))
|
|
35
|
+
continue;
|
|
36
|
+
context.report({ node, message: formatMessage(violation) });
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const checkSource = (node) => {
|
|
40
|
+
check(node, specifierOf(node));
|
|
41
|
+
};
|
|
42
|
+
// Every form that names a module is an edge. The CLI adapter reads the same
|
|
43
|
+
// five out of TypeScript's tree, and the parity suite holds the two to it: a
|
|
44
|
+
// `require` the plugin skipped would be a rule that enforces nothing under
|
|
45
|
+
// `oxlint` while failing under `architecture check`.
|
|
46
|
+
return {
|
|
47
|
+
before() {
|
|
48
|
+
importer = toRepoRelative(policy.repoRoot, context.filename);
|
|
49
|
+
if (importer.startsWith(".."))
|
|
50
|
+
return false;
|
|
51
|
+
selected = rulesSelecting(policy.importRules, importer);
|
|
52
|
+
return selected.length > 0;
|
|
53
|
+
},
|
|
54
|
+
ImportDeclaration: checkSource,
|
|
55
|
+
ExportNamedDeclaration: checkSource,
|
|
56
|
+
ExportAllDeclaration: checkSource,
|
|
57
|
+
// `import("m")` with a literal argument. A computed one is not a fact a
|
|
58
|
+
// static policy can speak about, in either adapter.
|
|
59
|
+
ImportExpression(node) {
|
|
60
|
+
check(node, importExpressionSpecifierOf(node));
|
|
61
|
+
},
|
|
62
|
+
CallExpression(node) {
|
|
63
|
+
check(node, requireSpecifierOf(node));
|
|
64
|
+
},
|
|
65
|
+
TSImportEqualsDeclaration(node) {
|
|
66
|
+
check(node, importEqualsSpecifierOf(node));
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
//# sourceMappingURL=imports-rule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"imports-rule.js","sourceRoot":"","sources":["../../src/imports-rule.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { evaluateMemberSite, formatMessage, memberRulesSelecting, } from "@goodbones/core";
|
|
2
|
+
import { toRepoRelative, } from "./oxlint-api.js";
|
|
3
|
+
const isMemberList = (value) => Array.isArray(value);
|
|
4
|
+
// The member shapes that carry a name a vocabulary rule can speak about: a
|
|
5
|
+
// property or method signature in a type, a property, method or accessor in a
|
|
6
|
+
// class. Mirrors the CLI's `isNamedMember`.
|
|
7
|
+
const DECLARED_MEMBER_TYPES = new Set([
|
|
8
|
+
"TSPropertySignature",
|
|
9
|
+
"TSMethodSignature",
|
|
10
|
+
"PropertyDefinition",
|
|
11
|
+
"MethodDefinition",
|
|
12
|
+
"TSAbstractPropertyDefinition",
|
|
13
|
+
"TSAbstractMethodDefinition",
|
|
14
|
+
]);
|
|
15
|
+
// The type literals written in a type, through intersections, unions and
|
|
16
|
+
// parentheses. A reference is not followed: its members are declared where it
|
|
17
|
+
// is, and reported there under its own name. Mirrors the CLI's `literalsOf`.
|
|
18
|
+
const literalsOf = (node) => {
|
|
19
|
+
if (node === null || node === undefined)
|
|
20
|
+
return [];
|
|
21
|
+
switch (node.type) {
|
|
22
|
+
case "TSTypeLiteral":
|
|
23
|
+
return [node];
|
|
24
|
+
case "TSIntersectionType":
|
|
25
|
+
case "TSUnionType":
|
|
26
|
+
return (node.types ?? []).flatMap(literalsOf);
|
|
27
|
+
case "TSParenthesizedType":
|
|
28
|
+
return literalsOf(node.typeAnnotation);
|
|
29
|
+
default:
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
const nameOf = (node) => {
|
|
34
|
+
if (node === null || node === undefined)
|
|
35
|
+
return null;
|
|
36
|
+
if (typeof node.name === "string")
|
|
37
|
+
return node.name;
|
|
38
|
+
return typeof node.value === "string" ? node.value : null;
|
|
39
|
+
};
|
|
40
|
+
// The name a call is made by: `f()` and `x.f()` are both `f`. `x[f]()` and
|
|
41
|
+
// `x["f"]()` are not — a computed property is not a name a vocabulary rule can
|
|
42
|
+
// speak about — and neither is a private `x.#f()`. The CLI reads the same
|
|
43
|
+
// three cases out of TypeScript's tree; the parity suite keeps them agreeing.
|
|
44
|
+
const calleeName = (node) => {
|
|
45
|
+
const callee = node.callee;
|
|
46
|
+
if (callee === null || callee === undefined)
|
|
47
|
+
return null;
|
|
48
|
+
if (callee.type === "Identifier" && typeof callee.name === "string")
|
|
49
|
+
return callee.name;
|
|
50
|
+
if (callee.type !== "MemberExpression" || callee.computed === true)
|
|
51
|
+
return null;
|
|
52
|
+
const property = callee.property;
|
|
53
|
+
if (property?.type !== "Identifier")
|
|
54
|
+
return null;
|
|
55
|
+
return nameOf(property);
|
|
56
|
+
};
|
|
57
|
+
export const makeMembersRule = (policy) => ({
|
|
58
|
+
meta: {
|
|
59
|
+
type: "problem",
|
|
60
|
+
docs: {
|
|
61
|
+
description: "which names a file may declare or call — a port's method vocabulary, a tier's allowed hooks",
|
|
62
|
+
},
|
|
63
|
+
schema: [],
|
|
64
|
+
},
|
|
65
|
+
createOnce(context) {
|
|
66
|
+
let file = "";
|
|
67
|
+
let selected = [];
|
|
68
|
+
const report = (node, name, declaration) => {
|
|
69
|
+
const violations = evaluateMemberSite(selected, {
|
|
70
|
+
file,
|
|
71
|
+
subject: declaration === undefined ? "calls" : "members",
|
|
72
|
+
name,
|
|
73
|
+
...(declaration === undefined
|
|
74
|
+
? {}
|
|
75
|
+
: { in: declaration.name, declares: declaration.declares }),
|
|
76
|
+
});
|
|
77
|
+
for (const violation of violations) {
|
|
78
|
+
if (policy.baseline.isBaselined(violation))
|
|
79
|
+
continue;
|
|
80
|
+
context.report({ node, message: formatMessage(violation) });
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
// The members written in a declaration, under that declaration's name and
|
|
84
|
+
// kind. A computed key is not a name a vocabulary rule can speak about;
|
|
85
|
+
// neither is a private `#name`, an index, call or construct signature, or
|
|
86
|
+
// a constructor.
|
|
87
|
+
const declared = (declaration, declares, members) => {
|
|
88
|
+
for (const member of members) {
|
|
89
|
+
if (member.computed === true || !DECLARED_MEMBER_TYPES.has(member.type))
|
|
90
|
+
continue;
|
|
91
|
+
if (member.key?.type === "PrivateIdentifier" || member.kind === "constructor")
|
|
92
|
+
continue;
|
|
93
|
+
const name = nameOf(member.key);
|
|
94
|
+
if (name !== null)
|
|
95
|
+
report(member.key ?? member, name, { name: declaration, declares });
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
return {
|
|
99
|
+
before() {
|
|
100
|
+
file = toRepoRelative(policy.repoRoot, context.filename);
|
|
101
|
+
if (file.startsWith(".."))
|
|
102
|
+
return false;
|
|
103
|
+
selected = memberRulesSelecting(policy.memberRules, file);
|
|
104
|
+
return selected.length > 0;
|
|
105
|
+
},
|
|
106
|
+
TSTypeAliasDeclaration(node) {
|
|
107
|
+
const declaration = nameOf(node.id);
|
|
108
|
+
if (declaration === null)
|
|
109
|
+
return;
|
|
110
|
+
for (const literal of literalsOf(node.typeAnnotation)) {
|
|
111
|
+
declared(declaration, "type", literal.members ?? []);
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
TSInterfaceDeclaration(node) {
|
|
115
|
+
const declaration = nameOf(node.id);
|
|
116
|
+
const members = node.body?.body;
|
|
117
|
+
if (declaration === null || !isMemberList(members))
|
|
118
|
+
return;
|
|
119
|
+
declared(declaration, "interface", members);
|
|
120
|
+
},
|
|
121
|
+
// A named class only, as the CLI reads it: an anonymous default class has
|
|
122
|
+
// no name for `in`, and a class expression is a value.
|
|
123
|
+
ClassDeclaration(node) {
|
|
124
|
+
const declaration = nameOf(node.id);
|
|
125
|
+
const members = node.body?.body;
|
|
126
|
+
if (declaration === null || !isMemberList(members))
|
|
127
|
+
return;
|
|
128
|
+
declared(declaration, "class", members);
|
|
129
|
+
},
|
|
130
|
+
CallExpression(node) {
|
|
131
|
+
const name = calleeName(node);
|
|
132
|
+
if (name !== null)
|
|
133
|
+
report(node, name);
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
//# sourceMappingURL=members-rule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"members-rule.js","sourceRoot":"","sources":["../../src/members-rule.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
export const toRepoRelative = (repoRoot, filename) => path.relative(repoRoot, filename).replaceAll(path.sep, "/");
|
|
3
|
+
export const specifierOf = (node) => {
|
|
4
|
+
const value = node.source?.value;
|
|
5
|
+
return typeof value === "string" ? value : null;
|
|
6
|
+
};
|
|
7
|
+
export const requireSpecifierOf = (node) => {
|
|
8
|
+
if (node.callee?.type !== "Identifier" || node.callee.name !== "require")
|
|
9
|
+
return null;
|
|
10
|
+
const [first] = node.arguments ?? [];
|
|
11
|
+
return first?.type === "Literal" && typeof first.value === "string" ? first.value : null;
|
|
12
|
+
};
|
|
13
|
+
export const importExpressionSpecifierOf = (node) => {
|
|
14
|
+
const source = node.source;
|
|
15
|
+
return source?.type === "Literal" && typeof source.value === "string" ? source.value : null;
|
|
16
|
+
};
|
|
17
|
+
export const importEqualsSpecifierOf = (node) => {
|
|
18
|
+
const reference = node.moduleReference;
|
|
19
|
+
if (reference?.type !== "TSExternalModuleReference")
|
|
20
|
+
return null;
|
|
21
|
+
const value = reference.expression?.value;
|
|
22
|
+
return typeof value === "string" ? value : null;
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=oxlint-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oxlint-api.js","sourceRoot":"","sources":["../../src/oxlint-api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAkBlC,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,QAAgB,EAAE,QAAgB,EAAU,EAAE,CAC3E,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AAE9D,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAgB,EAAiB,EAAE;IAC7D,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;IACjC,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAClD,CAAC,CAAC;AAyBF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,IAAc,EAAiB,EAAE;IAClE,IAAI,IAAI,CAAC,MAAM,EAAE,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACtF,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC;IACrC,OAAO,KAAK,EAAE,IAAI,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3F,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,IAA0B,EAAiB,EAAE;IACvF,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAC3B,OAAO,MAAM,EAAE,IAAI,KAAK,SAAS,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9F,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,IAAsB,EAAiB,EAAE;IAC/E,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC;IACvC,IAAI,SAAS,EAAE,IAAI,KAAK,2BAA2B;QAAE,OAAO,IAAI,CAAC;IACjE,MAAM,KAAK,GAAG,SAAS,CAAC,UAAU,EAAE,KAAK,CAAC;IAC1C,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAClD,CAAC,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { DEFAULT_CONFIG_FILENAME, loadPolicyFromFile } from "./config-loader.js";
|
|
2
|
+
import { makeExportsRule } from "./exports-rule.js";
|
|
3
|
+
import { makeImportsRule } from "./imports-rule.js";
|
|
4
|
+
import { makeMembersRule } from "./members-rule.js";
|
|
5
|
+
import { makeStructureRule } from "./structure-rule.js";
|
|
6
|
+
import { makeSurfaceRule } from "./surface-rule.js";
|
|
7
|
+
// oxlint imports this module once per lint run and reads `rules` synchronously,
|
|
8
|
+
// so the policy is loaded here rather than inside a rule. A load failure throws
|
|
9
|
+
// out of the import and fails the run — which is the point: a plugin that came
|
|
10
|
+
// up with no policy would report nothing and be indistinguishable from a clean
|
|
11
|
+
// codebase.
|
|
12
|
+
const policy = await loadPolicyFromFile(process.env.ARCHITECTURE_ROOT ?? process.cwd(), process.env.ARCHITECTURE_CONFIG ?? DEFAULT_CONFIG_FILENAME);
|
|
13
|
+
// A manifest written in a shape on its way out still loads; it says so once,
|
|
14
|
+
// here, rather than on every file.
|
|
15
|
+
for (const notice of policy.notices) {
|
|
16
|
+
process.stderr.write(`[architecture] deprecated: ${notice}\n`);
|
|
17
|
+
}
|
|
18
|
+
export const rules = {
|
|
19
|
+
imports: makeImportsRule(policy),
|
|
20
|
+
exports: makeExportsRule(policy),
|
|
21
|
+
members: makeMembersRule(policy),
|
|
22
|
+
structure: makeStructureRule(policy),
|
|
23
|
+
surface: makeSurfaceRule(policy),
|
|
24
|
+
};
|
|
25
|
+
const plugin = {
|
|
26
|
+
meta: { name: "architecture" },
|
|
27
|
+
rules,
|
|
28
|
+
};
|
|
29
|
+
export default plugin;
|
|
30
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,gFAAgF;AAChF,gFAAgF;AAChF,+EAA+E;AAC/E,+EAA+E;AAC/E,YAAY;AACZ,MAAM,MAAM,GAAG,MAAM,kBAAkB,CACrC,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,OAAO,CAAC,GAAG,EAAE,EAC9C,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,uBAAuB,CAC3D,CAAC;AAEF,6EAA6E;AAC7E,mCAAmC;AACnC,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;IACpC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,MAAM,IAAI,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,CAAC,MAAM,KAAK,GAMd;IACF,OAAO,EAAE,eAAe,CAAC,MAAM,CAAC;IAChC,OAAO,EAAE,eAAe,CAAC,MAAM,CAAC;IAChC,OAAO,EAAE,eAAe,CAAC,MAAM,CAAC;IAChC,SAAS,EAAE,iBAAiB,CAAC,MAAM,CAAC;IACpC,OAAO,EAAE,eAAe,CAAC,MAAM,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,GAA+E;IACzF,IAAI,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE;IAC9B,KAAK;CACN,CAAC;AAEF,eAAe,MAAM,CAAC"}
|