@shivaedev/quality 0.3.1 → 0.4.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.
Files changed (29) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +69 -2
  3. package/dist/rules/suppressions/biome/configs.d.ts +21 -10
  4. package/dist/rules/suppressions/biome/configs.d.ts.map +1 -1
  5. package/dist/rules/suppressions/biome/configs.js +57 -21
  6. package/dist/rules/suppressions/biome/configs.js.map +1 -1
  7. package/dist/rules/suppressions/biome/declarations.d.ts +18 -0
  8. package/dist/rules/suppressions/biome/declarations.d.ts.map +1 -0
  9. package/dist/rules/suppressions/biome/declarations.js +20 -0
  10. package/dist/rules/suppressions/biome/declarations.js.map +1 -0
  11. package/dist/rules/suppressions/biome/resolve.d.ts +3 -0
  12. package/dist/rules/suppressions/biome/resolve.d.ts.map +1 -0
  13. package/dist/rules/suppressions/biome/resolve.js +70 -0
  14. package/dist/rules/suppressions/biome/resolve.js.map +1 -0
  15. package/dist/rules/suppressions/biome/weakenings.d.ts +3 -3
  16. package/dist/rules/suppressions/biome/weakenings.d.ts.map +1 -1
  17. package/dist/rules/suppressions/biome/weakenings.js +41 -33
  18. package/dist/rules/suppressions/biome/weakenings.js.map +1 -1
  19. package/dist/rules/suppressions/biome-overrides.d.ts.map +1 -1
  20. package/dist/rules/suppressions/biome-overrides.js +31 -23
  21. package/dist/rules/suppressions/biome-overrides.js.map +1 -1
  22. package/package.json +5 -3
  23. package/src/rules/suppressions/biome/configs.ts +97 -28
  24. package/src/rules/suppressions/biome/declarations.ts +37 -0
  25. package/src/rules/suppressions/biome/resolve.ts +86 -0
  26. package/src/rules/suppressions/biome/weakenings.ts +54 -37
  27. package/src/rules/suppressions/biome-overrides.ts +40 -31
  28. package/tsconfig/base.json +35 -0
  29. package/tsconfig/package.json +10 -0
@@ -1 +1 @@
1
- {"version":3,"file":"weakenings.js","sourceRoot":"","sources":["../../../../src/rules/suppressions/biome/weakenings.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"weakenings.js","sourceRoot":"","sources":["../../../../src/rules/suppressions/biome/weakenings.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"biome-overrides.d.ts","sourceRoot":"","sources":["../../../src/rules/suppressions/biome-overrides.ts"],"names":[],"mappings":"AAyCA,eAAO,MAAM,cAAc;;;;;;EAmBzB,CAAC"}
1
+ {"version":3,"file":"biome-overrides.d.ts","sourceRoot":"","sources":["../../../src/rules/suppressions/biome-overrides.ts"],"names":[],"mappings":"AAmDA,eAAO,MAAM,cAAc;;;;;;EAkBzB,CAAC"}
@@ -1,46 +1,54 @@
1
1
  import { Effect, Schema } from "effect";
2
2
  import { defineRule } from "../../rule.js";
3
3
  import { biomeConfigs } from "./biome/configs.js";
4
+ import { Declaration, matches, scoped, scopeText } from "./biome/declarations.js";
4
5
  import { weakeningsOf } from "./biome/weakenings.js";
5
- const Declaration = Schema.Struct({
6
- rule: Schema.NonEmptyString,
7
- includes: Schema.NonEmptyArray(Schema.NonEmptyString),
8
- reason: Schema.String.check(Schema.isPattern(/\S/, { expected: "a reason that says why the scope needs the rule weakened" })),
9
- });
10
6
  const BiomeOverridesOptions = Schema.Struct({
11
7
  declared: Schema.Array(Declaration).pipe(Schema.withDecodingDefaultKey(Effect.succeed([]))),
12
8
  });
13
- const sameScope = (left, right) => new Set(left).size === new Set(right).size && left.every((glob) => right.includes(glob));
14
- const matches = (declaration, weakening) => declaration.rule === weakening.rule && sameScope(declaration.includes, weakening.includes);
15
- const scopeText = (includes) => includes.map((glob) => `"${glob}"`).join(", ");
16
- const undeclared = (weakening) => ({
17
- file: weakening.file,
18
- line: weakening.line,
19
- message: `Weakens "${weakening.rule}" for ${scopeText(weakening.includes)} without a declaration.`,
20
- subject: weakening.rule,
21
- });
9
+ const shippedBy = ({ base, layers }) => layers.flatMap(({ preset }) => preset === undefined
10
+ ? []
11
+ : preset.declared.map(({ includes, rule }) => ({ includes: includes.map((glob) => scoped(base, glob)), rule, specifier: preset.specifier })));
12
+ const undeclared = ({ includes, layer, line, rule }) => layer.preset === undefined
13
+ ? { file: layer.path, line, message: `Weakens "${rule}" for ${scopeText(includes)} without a declaration.`, subject: rule }
14
+ : {
15
+ file: layer.preset.file,
16
+ line: layer.preset.line,
17
+ message: `Extends "${layer.preset.specifier}", which weakens "${rule}" for ${scopeText(includes)} without a declaration.`,
18
+ subject: rule,
19
+ };
22
20
  const unused = (file, declaration) => ({
23
21
  file,
24
22
  message: `Declares "${declaration.rule}" for ${scopeText(declaration.includes)}, which no Biome config weakens. Remove the declaration.`,
25
23
  subject: declaration.rule,
26
24
  });
27
- const unreadable = (config) => config._tag === "Unreadable" ? [{ file: config.path, message: `Cannot read this Biome config: ${config.reason}.` }] : [];
25
+ const repeated = (file, declaration, shipped) => ({
26
+ file,
27
+ message: `Declares "${declaration.rule}" for ${scopeText(declaration.includes)}, which "${shipped.specifier}" already declares. Remove the declaration.`,
28
+ subject: declaration.rule,
29
+ });
30
+ const staleOrRepeated = (file, weakenings, shipped) => (declaration) => {
31
+ if (!weakenings.some((weakening) => matches(declaration, weakening))) {
32
+ return [unused(file, declaration)];
33
+ }
34
+ const already = shipped.find((candidate) => matches(declaration, candidate));
35
+ return already === undefined ? [] : [repeated(file, declaration, already)];
36
+ };
28
37
  export const biomeOverrides = defineRule({
29
38
  id: "suppressions/biome-overrides",
30
39
  description: "A Biome setting that turns a check off or down, or keeps files out of it, is an exception for every file it covers. Fix the code and remove the setting, or declare its rule, includes and reason under this rule's declared option.",
31
40
  options: Schema.toStandardSchemaV1(BiomeOverridesOptions, { parseOptions: { errors: "all", onExcessProperty: "error" } }),
32
41
  registrable: false,
33
42
  check: async (inputs) => {
34
- const configs = await biomeConfigs(inputs);
43
+ const { chains, problems, root } = await biomeConfigs(inputs);
35
44
  const { declared } = inputs.options;
36
- const weakenings = configs.flatMap((config) => (config._tag === "Config" ? weakeningsOf(config.json, config.path, config.base) : []));
37
- const root = configs.find((config) => !config.path.includes("/"))?.path ?? "biome.json";
45
+ const weakenings = chains.flatMap(weakeningsOf);
46
+ const shipped = chains.flatMap(shippedBy);
47
+ const covered = (weakening) => [...declared, ...shipped].some((declaration) => matches(declaration, weakening));
38
48
  return [
39
- ...configs.flatMap(unreadable),
40
- ...weakenings.filter((weakening) => !declared.some((declaration) => matches(declaration, weakening))).map(undeclared),
41
- ...declared
42
- .filter((declaration) => !weakenings.some((weakening) => matches(declaration, weakening)))
43
- .map((declaration) => unused(root, declaration)),
49
+ ...problems,
50
+ ...weakenings.filter((weakening) => !covered(weakening)).map(undeclared),
51
+ ...declared.flatMap(staleOrRepeated(root, weakenings, shipped)),
44
52
  ];
45
53
  },
46
54
  });
@@ -1 +1 @@
1
- {"version":3,"file":"biome-overrides.js","sourceRoot":"","sources":["../../../src/rules/suppressions/biome-overrides.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"biome-overrides.js","sourceRoot":"","sources":["../../../src/rules/suppressions/biome-overrides.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shivaedev/quality",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "Repository quality gate with typed rules, a shrink-only baseline and a registry of reasoned exceptions",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -23,6 +23,7 @@
23
23
  "files": [
24
24
  "dist",
25
25
  "src",
26
+ "tsconfig",
26
27
  "CHANGELOG.md",
27
28
  "README.md"
28
29
  ],
@@ -33,6 +34,8 @@
33
34
  "import": "./dist/index.js",
34
35
  "default": "./dist/index.js"
35
36
  },
37
+ "./tsconfig/base.json": "./tsconfig/base.json",
38
+ "./tsconfig/package.json": "./tsconfig/package.json",
36
39
  "./package.json": "./package.json"
37
40
  },
38
41
  "publishConfig": {
@@ -62,7 +65,6 @@
62
65
  "check": "biome check .",
63
66
  "test": "vitest run",
64
67
  "typecheck": "tsc --noEmit",
65
- "typecheck:compat": "tsc6 --noEmit",
66
- "ready": "pnpm check && pnpm typecheck && pnpm typecheck:compat && pnpm test && pnpm build"
68
+ "ready": "pnpm check && pnpm typecheck && pnpm test && pnpm build"
67
69
  }
68
70
  }
@@ -1,50 +1,119 @@
1
1
  import { posix } from "node:path";
2
- import type { RuleInputs } from "../../../rule.ts";
3
- import { itemsOf, type Json, member, parseJsonc, textOf } from "./json.ts";
2
+ import type { Finding, RuleInputs } from "../../../rule.ts";
3
+ import { type Declaration, decodeShipped, PRESET_DECLARATIONS } from "./declarations.ts";
4
+ import { itemsOf, type Json, member, type Parsed, parseJsonc, textOf } from "./json.ts";
5
+ import { resolvePackage } from "./resolve.ts";
4
6
 
5
- export type Config =
6
- | { readonly _tag: "Config"; readonly path: string; readonly base: string; readonly json: Json }
7
- | { readonly _tag: "Unreadable"; readonly path: string; readonly reason: string };
7
+ export interface Preset {
8
+ readonly specifier: string;
9
+ readonly file: string;
10
+ readonly line: number;
11
+ readonly declared: ReadonlyArray<Declaration>;
12
+ }
13
+
14
+ export interface Layer {
15
+ readonly path: string;
16
+ readonly json: Json;
17
+ readonly preset: Preset | undefined;
18
+ }
19
+
20
+ export interface Chain {
21
+ readonly base: string;
22
+ readonly layers: ReadonlyArray<Layer>;
23
+ }
24
+
25
+ interface Loaded {
26
+ readonly layers: ReadonlyArray<Layer>;
27
+ readonly problems: ReadonlyArray<Finding>;
28
+ }
29
+
30
+ type ReadText = RuleInputs["readText"];
8
31
 
9
32
  const ROOT_CONFIGS: ReadonlyArray<string> = ["biome.json", "biome.jsonc"];
10
33
 
11
34
  const NESTED = /(?:^|\/)biome\.jsonc?$/;
12
35
 
36
+ const RELATIVE = /^\.\.?(?:\/|$)/;
37
+
13
38
  const directoryOf = (path: string): string => (posix.dirname(path) === "." ? "" : posix.dirname(path));
14
39
 
15
- const localExtends = (path: string, json: Json): ReadonlyArray<string> => {
16
- const node = member(json, "extends");
17
- const entries = node?._tag === "Array" ? itemsOf(node).flatMap((item) => textOf(item) ?? []) : [textOf(node) ?? ""];
18
- return entries.filter((entry) => entry.startsWith(".")).map((entry) => posix.join(posix.dirname(path), entry));
40
+ const read = async (readText: ReadText, path: string): Promise<Parsed> => {
41
+ const text = await readText(path);
42
+ return text === undefined ? { _tag: "Unreadable", reason: "the file does not exist" } : parseJsonc(path, text);
19
43
  };
20
44
 
21
- const load = async (readText: RuleInputs["readText"], path: string, base: string, seen: Set<string>): Promise<ReadonlyArray<Config>> => {
22
- if (seen.has(path)) {
23
- return [];
24
- }
25
- seen.add(path);
26
- const text = await readText(path);
27
- if (text === undefined) {
28
- return [{ _tag: "Unreadable", path, reason: "the file does not exist" }];
45
+ const problem = (file: string, message: string, line?: number): Loaded => ({ layers: [], problems: [{ file, line, message }] });
46
+
47
+ const local = async (readText: ReadText, path: string): Promise<Loaded> => {
48
+ const parsed = await read(readText, path);
49
+ return parsed._tag === "Parsed"
50
+ ? { layers: [{ json: parsed.json, path, preset: undefined }], problems: [] }
51
+ : problem(path, `Cannot read this Biome config: ${parsed.reason}.`);
52
+ };
53
+
54
+ const fromPackage = async (readText: ReadText, from: string, entry: Json, specifier: string): Promise<Loaded> => {
55
+ const target = await resolvePackage(readText, specifier);
56
+ if (target === undefined) {
57
+ return problem(from, `Cannot resolve the Biome config "${specifier}" from node_modules.`, entry.line);
29
58
  }
30
- const parsed = parseJsonc(path, text);
59
+ const parsed = await read(readText, target);
31
60
  if (parsed._tag === "Unreadable") {
32
- return [{ _tag: "Unreadable", path, reason: parsed.reason }];
61
+ return problem(from, `Cannot read the Biome config "${specifier}" at ${target}: ${parsed.reason}.`, entry.line);
33
62
  }
34
- const extended = await Promise.all(localExtends(path, parsed.json).map((target) => load(readText, target, base, seen)));
35
- return [{ _tag: "Config", base, json: parsed.json, path }, ...extended.flat()];
63
+ const shipped = posix.join(posix.dirname(target), PRESET_DECLARATIONS);
64
+ const declared = await decodeShipped(await readText(shipped));
65
+ if (declared._tag === "Invalid") {
66
+ return problem(from, `Cannot read the declarations shipped with "${specifier}" at ${shipped}: ${declared.issues.join("; ")}.`, entry.line);
67
+ }
68
+ const preset = { declared: declared.value, file: from, line: entry.line, specifier };
69
+ return { layers: [{ json: parsed.json, path: target, preset }], problems: [] };
70
+ };
71
+
72
+ const extended = async (readText: ReadText, from: string, entry: Json): Promise<Loaded> => {
73
+ const specifier = textOf(entry);
74
+ if (specifier === undefined || specifier === "//") {
75
+ return { layers: [], problems: [] };
76
+ }
77
+ if (RELATIVE.test(specifier)) {
78
+ return local(readText, posix.join(posix.dirname(from), specifier));
79
+ }
80
+ const relative = posix.normalize(specifier);
81
+ return (await readText(relative)) === undefined ? fromPackage(readText, from, entry, specifier) : local(readText, relative);
36
82
  };
37
83
 
38
- const rootConfig = async (readText: RuleInputs["readText"]): Promise<string | undefined> => {
84
+ const extendsOf = (json: Json): ReadonlyArray<Json> => itemsOf(member(json, "extends"));
85
+
86
+ const chainOf = async (readText: ReadText, path: string): Promise<Loaded> => {
87
+ const own = await local(readText, path);
88
+ const [layer] = own.layers;
89
+ if (layer === undefined) {
90
+ return own;
91
+ }
92
+ const parents = await Promise.all(extendsOf(layer.json).map((entry) => extended(readText, path, entry)));
93
+ return { layers: [...parents.flatMap((parent) => parent.layers), layer], problems: parents.flatMap((parent) => parent.problems) };
94
+ };
95
+
96
+ const rootConfig = async (readText: ReadText): Promise<string | undefined> => {
39
97
  const present = await Promise.all(ROOT_CONFIGS.map(async (path) => ((await readText(path)) === undefined ? [] : [path])));
40
98
  return present.flat()[0];
41
99
  };
42
100
 
43
- export const biomeConfigs = async ({ files, readText }: RuleInputs): Promise<ReadonlyArray<Config>> => {
44
- const seen = new Set<string>();
101
+ export interface BiomeConfigs {
102
+ readonly root: string;
103
+ readonly chains: ReadonlyArray<Chain>;
104
+ readonly problems: ReadonlyArray<Finding>;
105
+ }
106
+
107
+ export const biomeConfigs = async ({ files, readText }: RuleInputs): Promise<BiomeConfigs> => {
45
108
  const root = await rootConfig(readText);
46
- const nested = files.filter((path) => NESTED.test(path) && path !== root);
47
- const roots = root === undefined ? [] : await load(readText, root, "", seen);
48
- const below = await Promise.all(nested.map((path) => load(readText, path, directoryOf(path), seen)));
49
- return [...roots, ...below.flat()];
109
+ const rootChain = root === undefined ? { layers: [], problems: [] } : await chainOf(readText, root);
110
+ const loaded = new Set(rootChain.layers.map((layer) => layer.path));
111
+ const nested = files.filter((path) => NESTED.test(path) && path !== root && !loaded.has(path));
112
+ const below = await Promise.all(nested.map(async (path) => ({ base: directoryOf(path), ...(await chainOf(readText, path)) })));
113
+ const all = [{ base: "", ...rootChain }, ...below];
114
+ return {
115
+ chains: all.filter((chain) => chain.layers.length > 0).map(({ base, layers }) => ({ base, layers })),
116
+ problems: all.flatMap((chain) => chain.problems),
117
+ root: root ?? "biome.json",
118
+ };
50
119
  };
@@ -0,0 +1,37 @@
1
+ import { Schema } from "effect";
2
+ import { type Decoded, decodeWith } from "../../../decoded.ts";
3
+
4
+ export const Declaration = Schema.Struct({
5
+ rule: Schema.NonEmptyString,
6
+ includes: Schema.NonEmptyArray(Schema.NonEmptyString),
7
+ reason: Schema.String.check(Schema.isPattern(/\S/, { expected: "a reason that says why the scope needs the rule weakened" })),
8
+ });
9
+
10
+ export type Declaration = typeof Declaration.Type;
11
+
12
+ export const PRESET_DECLARATIONS = "declarations.json";
13
+
14
+ const shipped = Schema.toStandardSchemaV1(Schema.fromJsonString(Schema.Array(Declaration)), {
15
+ parseOptions: { errors: "all", onExcessProperty: "error" },
16
+ });
17
+
18
+ export const decodeShipped = (text: string | undefined): Promise<Decoded<ReadonlyArray<Declaration>>> =>
19
+ text === undefined ? Promise.resolve({ _tag: "Valid", value: [] }) : decodeWith(shipped, text);
20
+
21
+ export interface Scoped {
22
+ readonly rule: string;
23
+ readonly includes: ReadonlyArray<string>;
24
+ }
25
+
26
+ const sameScope = (left: ReadonlyArray<string>, right: ReadonlyArray<string>): boolean =>
27
+ new Set(left).size === new Set(right).size && left.every((glob) => right.includes(glob));
28
+
29
+ export const matches = (declaration: Scoped, weakening: Scoped): boolean =>
30
+ declaration.rule === weakening.rule && sameScope(declaration.includes, weakening.includes);
31
+
32
+ export const scoped = (base: string, glob: string): string => {
33
+ const [, negation = "", path = glob] = /^(!*)(.*)$/.exec(glob) ?? [];
34
+ return base === "" ? glob : `${negation}${base}/${path}`;
35
+ };
36
+
37
+ export const scopeText = (includes: ReadonlyArray<string>): string => includes.map((glob) => `"${glob}"`).join(", ");
@@ -0,0 +1,86 @@
1
+ import { posix } from "node:path";
2
+ import { Schema } from "effect";
3
+ import { decodeWith } from "../../../decoded.ts";
4
+ import type { RuleInputs } from "../../../rule.ts";
5
+
6
+ const Manifest = Schema.Struct({
7
+ name: Schema.optionalKey(Schema.String),
8
+ main: Schema.optionalKey(Schema.String),
9
+ exports: Schema.optionalKey(Schema.Unknown),
10
+ });
11
+
12
+ type Manifest = typeof Manifest.Type;
13
+
14
+ const manifestSchema = Schema.toStandardSchemaV1(Schema.fromJsonString(Manifest));
15
+
16
+ const CONDITIONS: ReadonlySet<string> = new Set(["biome", "default"]);
17
+
18
+ const SPECIFIER = /^((?:@[^/]+\/)?[^/]+)(?:\/(.+))?$/;
19
+
20
+ const isRecord = (value: unknown): value is Readonly<Record<string, unknown>> => typeof value === "object" && value !== null && !Array.isArray(value);
21
+
22
+ const targetOf = (value: unknown, star: string | undefined): string | undefined => {
23
+ if (typeof value === "string") {
24
+ return star === undefined ? value : value.replaceAll("*", star);
25
+ }
26
+ if (Array.isArray(value)) {
27
+ return value.map((item: unknown) => targetOf(item, star)).find((target) => target !== undefined);
28
+ }
29
+ const condition = isRecord(value) ? Object.keys(value).find((key) => CONDITIONS.has(key)) : undefined;
30
+ return isRecord(value) && condition !== undefined ? targetOf(value[condition], star) : undefined;
31
+ };
32
+
33
+ const bySpecificity = (left: string, right: string): number => right.indexOf("*") - left.indexOf("*") || right.length - left.length;
34
+
35
+ const patternTarget = (exports: Readonly<Record<string, unknown>>, key: string): string | undefined => {
36
+ const pattern = Object.keys(exports)
37
+ .filter((candidate) => candidate.split("*").length === 2)
38
+ .sort(bySpecificity)
39
+ .find((candidate) => {
40
+ const [prefix = "", suffix = ""] = candidate.split("*");
41
+ return key.startsWith(prefix) && key !== prefix && key.endsWith(suffix) && key.length >= candidate.length;
42
+ });
43
+ const [prefix = "", suffix = ""] = pattern?.split("*") ?? [];
44
+ return pattern === undefined ? undefined : targetOf(exports[pattern], key.slice(prefix.length, key.length - suffix.length));
45
+ };
46
+
47
+ const exported = (exports: unknown, subpath: string): string | undefined => {
48
+ const key = subpath === "" ? "." : `./${subpath}`;
49
+ if (!isRecord(exports)) {
50
+ return targetOf(exports, undefined);
51
+ }
52
+ return Object.hasOwn(exports, key) ? targetOf(exports[key], undefined) : (patternTarget(exports, key) ?? targetOf(exports, undefined));
53
+ };
54
+
55
+ const inPackage = (directory: string, target: string | undefined): string | undefined =>
56
+ target?.startsWith("./") === true ? posix.join(directory, target) : undefined;
57
+
58
+ const manifestAt = async (readText: RuleInputs["readText"], path: string): Promise<Manifest | undefined> => {
59
+ const text = await readText(path);
60
+ const decoded = text === undefined ? undefined : await decodeWith(manifestSchema, text);
61
+ return decoded?._tag === "Valid" ? decoded.value : undefined;
62
+ };
63
+
64
+ const fromDependency = (directory: string, manifest: Manifest, subpath: string): string | undefined => {
65
+ if (manifest.exports !== undefined) {
66
+ return inPackage(directory, exported(manifest.exports, subpath));
67
+ }
68
+ if (subpath === "" && manifest.main !== undefined) {
69
+ return posix.join(directory, manifest.main);
70
+ }
71
+ return subpath === "" ? undefined : posix.join(directory, subpath);
72
+ };
73
+
74
+ export const resolvePackage = async (readText: RuleInputs["readText"], specifier: string): Promise<string | undefined> => {
75
+ const [, name, subpath = ""] = SPECIFIER.exec(specifier) ?? [];
76
+ if (name === undefined) {
77
+ return undefined;
78
+ }
79
+ const own = await manifestAt(readText, "package.json");
80
+ if (own?.name === name && own.exports !== undefined && subpath !== "") {
81
+ return inPackage("", exported(own.exports, subpath));
82
+ }
83
+ const directory = posix.join("node_modules", name);
84
+ const manifest = await manifestAt(readText, posix.join(directory, "package.json"));
85
+ return manifest === undefined ? undefined : fromDependency(directory, manifest, subpath);
86
+ };
@@ -1,15 +1,19 @@
1
+ import type { Chain, Layer } from "./configs.ts";
2
+ import { scoped } from "./declarations.ts";
1
3
  import { entriesOf, isFalse, itemsOf, type Json, member, textOf } from "./json.ts";
2
4
 
3
5
  export interface Weakening {
4
6
  readonly rule: string;
5
7
  readonly includes: ReadonlyArray<string>;
6
- readonly file: string;
7
8
  readonly line: number;
9
+ readonly layer: Layer;
8
10
  }
9
11
 
10
12
  interface Setting {
11
13
  readonly rule: string;
12
14
  readonly line: number;
15
+ readonly weak: boolean;
16
+ readonly wholeGroup: boolean;
13
17
  }
14
18
 
15
19
  const LINT_WEAK = new Set(["off", "warn", "info"]);
@@ -18,39 +22,45 @@ const PRESETS = new Set(["recommended", "preset"]);
18
22
 
19
23
  const levelOf = (node: Json): string | undefined => textOf(node) ?? textOf(member(node, "level"));
20
24
 
21
- const at = (rule: string, node: Json | undefined): ReadonlyArray<Setting> => (node === undefined ? [] : [{ line: node.line, rule }]);
25
+ const at = (rule: string, node: Json | undefined, weak: boolean, wholeGroup = false): ReadonlyArray<Setting> =>
26
+ node === undefined ? [] : [{ line: node.line, rule, weak, wholeGroup }];
22
27
 
23
- const disabled = (rule: string, section: Json | undefined): ReadonlyArray<Setting> =>
24
- isFalse(member(section, "enabled")) ? at(rule, member(section, "enabled")) : [];
28
+ const enabled = (rule: string, section: Json | undefined): ReadonlyArray<Setting> =>
29
+ at(rule, member(section, "enabled"), isFalse(member(section, "enabled")));
25
30
 
26
- const withoutDefaults = (rule: string, set: Json | undefined): ReadonlyArray<Setting> => [
27
- ...(isFalse(member(set, "recommended")) ? at(rule, member(set, "recommended")) : []),
28
- ...(textOf(member(set, "preset")) === "none" ? at(rule, member(set, "preset")) : []),
31
+ const defaults = (rule: string, set: Json | undefined): ReadonlyArray<Setting> => [
32
+ ...at(rule, member(set, "recommended"), isFalse(member(set, "recommended"))),
33
+ ...at(rule, member(set, "preset"), textOf(member(set, "preset")) === "none"),
29
34
  ];
30
35
 
36
+ const ruleSettings = (group: string, weak: ReadonlySet<string>, rules: Json): ReadonlyArray<Setting> =>
37
+ entriesOf(rules)
38
+ .filter(([rule]) => !PRESETS.has(rule))
39
+ .flatMap(([rule, setting]) => {
40
+ const level = levelOf(setting);
41
+ return level === undefined ? [] : at(`${group}/${rule}`, setting, weak.has(level));
42
+ });
43
+
31
44
  const groupSettings = (prefix: string, weak: ReadonlySet<string>, groups: Json | undefined): ReadonlyArray<Setting> =>
32
45
  entriesOf(groups)
33
46
  .filter(([group]) => !PRESETS.has(group))
34
- .flatMap(([group, rules]) => [
35
- ...(weak.has(textOf(rules) ?? "") ? at(`${prefix}/${group}`, rules) : []),
36
- ...withoutDefaults(`${prefix}/${group}`, rules),
37
- ...entriesOf(rules)
38
- .filter(([rule, setting]) => !PRESETS.has(rule) && weak.has(levelOf(setting) ?? ""))
39
- .flatMap(([rule, setting]) => at(`${prefix}/${group}/${rule}`, setting)),
40
- ]);
47
+ .flatMap(([group, rules]) => {
48
+ const severity = textOf(rules);
49
+ return severity === undefined
50
+ ? [...defaults(`${prefix}/${group}`, rules), ...ruleSettings(`${prefix}/${group}`, weak, rules)]
51
+ : at(`${prefix}/${group}`, rules, weak.has(severity), true);
52
+ });
41
53
 
42
54
  const linter = (section: Json | undefined): ReadonlyArray<Setting> => [
43
- ...disabled("lint", section),
44
- ...withoutDefaults("lint/recommended", member(section, "rules")),
55
+ ...enabled("lint", section),
56
+ ...defaults("lint/recommended", member(section, "rules")),
45
57
  ...groupSettings("lint", LINT_WEAK, member(section, "rules")),
46
- ...entriesOf(member(section, "domains"))
47
- .filter(([, value]) => textOf(value) === "none")
48
- .flatMap(([domain, value]) => at(`lint/domains/${domain}`, value)),
58
+ ...entriesOf(member(section, "domains")).flatMap(([domain, value]) => at(`lint/domains/${domain}`, value, textOf(value) === "none")),
49
59
  ];
50
60
 
51
61
  const assist = (section: Json | undefined): ReadonlyArray<Setting> => [
52
- ...disabled("assist", section),
53
- ...withoutDefaults("assist/recommended", member(section, "actions")),
62
+ ...enabled("assist", section),
63
+ ...defaults("assist/recommended", member(section, "actions")),
54
64
  ...groupSettings("assist", ASSIST_WEAK, member(section, "actions")),
55
65
  ];
56
66
 
@@ -64,17 +74,15 @@ const TOOLS: ReadonlyArray<readonly [string, string]> = [
64
74
 
65
75
  const SCOPED_SECTIONS: ReadonlyArray<readonly [string, string]> = [["files", "files"], ...TOOLS];
66
76
 
67
- const scopeSettings = (scope: Json): ReadonlyArray<Setting> => [
77
+ const settingsOf = (scope: Json): ReadonlyArray<Setting> => [
68
78
  ...linter(member(scope, "linter")),
69
79
  ...assist(member(scope, "assist")),
70
- ...disabled("format", member(scope, "formatter")),
71
- ...LANGUAGES.flatMap((language) => TOOLS.flatMap(([key, name]) => disabled(`${language}/${name}`, member(member(scope, language), key)))),
80
+ ...enabled("format", member(scope, "formatter")),
81
+ ...LANGUAGES.flatMap((language) => TOOLS.flatMap(([key, name]) => enabled(`${language}/${name}`, member(member(scope, language), key)))),
72
82
  ];
73
83
 
74
- const scoped = (base: string, glob: string): string => {
75
- const [, negation = "", path = glob] = /^(!*)(.*)$/.exec(glob) ?? [];
76
- return base === "" ? glob : `${negation}${base}/${path}`;
77
- };
84
+ const replaces = (later: Setting, earlier: Setting): boolean =>
85
+ later.rule === earlier.rule || (later.wholeGroup && earlier.rule.startsWith(`${later.rule}/`));
78
86
 
79
87
  const includesOf = (override: Json): ReadonlyArray<string> => {
80
88
  const includes = itemsOf(member(override, "includes")).flatMap((item) => textOf(item) ?? []);
@@ -84,19 +92,28 @@ const includesOf = (override: Json): ReadonlyArray<string> => {
84
92
  const narrowsScope = (globs: ReadonlyArray<string>): boolean =>
85
93
  globs.length > 0 && (globs.some((glob) => glob.startsWith("!")) || !globs.includes("**"));
86
94
 
87
- const narrowings = (config: Json, file: string, base: string): ReadonlyArray<Weakening> =>
95
+ const narrowings = (config: Json, base: string): ReadonlyArray<Omit<Weakening, "layer">> =>
88
96
  SCOPED_SECTIONS.flatMap(([key, name]) => {
89
97
  const list = member(member(config, key), "includes");
90
98
  const globs = itemsOf(list).flatMap((item) => textOf(item) ?? []);
91
99
  return list === undefined || !narrowsScope(globs)
92
100
  ? []
93
- : [{ file, includes: globs.map((glob) => scoped(base, glob)), line: list.line, rule: `${name}/includes` }];
101
+ : [{ includes: globs.map((glob) => scoped(base, glob)), line: list.line, rule: `${name}/includes` }];
94
102
  });
95
103
 
96
- export const weakeningsOf = (config: Json, file: string, base: string): ReadonlyArray<Weakening> => [
97
- ...narrowings(config, file, base),
98
- ...scopeSettings(config).map((setting) => ({ ...setting, file, includes: [scoped(base, "**")] })),
99
- ...itemsOf(member(config, "overrides")).flatMap((override) =>
100
- scopeSettings(override).map((setting) => ({ ...setting, file, includes: includesOf(override).map((glob) => scoped(base, glob)) })),
101
- ),
102
- ];
104
+ const layerWeakenings = (layer: Layer, later: ReadonlyArray<Layer>, base: string): ReadonlyArray<Weakening> => {
105
+ const overriding = later.flatMap((next) => settingsOf(next.json));
106
+ const top = settingsOf(layer.json).filter((setting) => setting.weak && !overriding.some((next) => replaces(next, setting)));
107
+ return [
108
+ ...narrowings(layer.json, base),
109
+ ...top.map(({ line, rule }) => ({ includes: [scoped(base, "**")], line, rule })),
110
+ ...itemsOf(member(layer.json, "overrides")).flatMap((override) =>
111
+ settingsOf(override)
112
+ .filter((setting) => setting.weak)
113
+ .map(({ line, rule }) => ({ includes: includesOf(override).map((glob) => scoped(base, glob)), line, rule })),
114
+ ),
115
+ ].map((weakening) => ({ ...weakening, layer }));
116
+ };
117
+
118
+ export const weakeningsOf = ({ base, layers }: Chain): ReadonlyArray<Weakening> =>
119
+ layers.flatMap((layer, index) => layerWeakenings(layer, layers.slice(index + 1), base));