eslint-config-setup 0.5.1 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +9 -7
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +161 -155
- package/dist/index.js.map +1 -1
- package/dist/modules.d.ts +67 -39
- package/dist/modules.d.ts.map +1 -0
- package/dist/modules.js +1757 -2357
- package/dist/modules.js.map +1 -1
- package/dist/types-DElYtiZE.d.ts +32 -0
- package/dist/types-DElYtiZE.d.ts.map +1 -0
- package/package.json +3 -3
- package/dist/types-CAO1PbsB.d.ts +0 -34
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { c as RuleScope } from './types-CAO1PbsB.js';
|
|
3
|
-
import 'eslint';
|
|
1
|
+
import { a as RuleOptions, i as OxlintConfigResult, n as FlatConfigArray, o as RuleScope, r as OxlintConfigOptions, s as RuleSeverity, t as ConfigOptions } from "./types-DElYtiZE.js";
|
|
4
2
|
|
|
3
|
+
//#region src/api/rule-helpers.d.ts
|
|
5
4
|
/**
|
|
6
5
|
* Change the severity of a rule across all config blocks, preserving options.
|
|
7
6
|
*/
|
|
@@ -24,7 +23,8 @@ declare function addRule(config: FlatConfigArray, ruleName: string, severity: Ru
|
|
|
24
23
|
* Disable all rules except the specified one — useful for debugging.
|
|
25
24
|
*/
|
|
26
25
|
declare function disableAllRulesBut(config: FlatConfigArray, keepRuleName: string): void;
|
|
27
|
-
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/hash.d.ts
|
|
28
28
|
/**
|
|
29
29
|
* Converts config options to a deterministic bitmask.
|
|
30
30
|
* Bit order is fixed and must never change (would break published configs).
|
|
@@ -37,7 +37,8 @@ declare function optionsToBitmask(opts: ConfigOptions): number;
|
|
|
37
37
|
declare function bitmaskToHash(mask: number): string;
|
|
38
38
|
/** Convenience: options → filename (without path prefix). */
|
|
39
39
|
declare function optionsToFilename(opts: ConfigOptions): string;
|
|
40
|
-
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/loader.d.ts
|
|
41
42
|
/**
|
|
42
43
|
* Loads a pre-generated ESLint config by dynamically importing the hashed file.
|
|
43
44
|
* The hash is computed from the options using the same algorithm as the build.
|
|
@@ -48,5 +49,6 @@ declare function getEslintConfig(opts?: ConfigOptions): Promise<FlatConfigArray>
|
|
|
48
49
|
* Only `react`, `node`, and `ai` flags are relevant — `oxlint` is ignored.
|
|
49
50
|
*/
|
|
50
51
|
declare function getOxlintConfig(opts?: OxlintConfigOptions): OxlintConfigResult;
|
|
51
|
-
|
|
52
|
-
export { ConfigOptions, FlatConfigArray, OxlintConfigOptions, OxlintConfigResult, RuleOptions, RuleSeverity, addRule, bitmaskToHash, configureRule, disableAllRulesBut, disableRule, getEslintConfig, getOxlintConfig, optionsToBitmask, optionsToFilename, setRuleSeverity };
|
|
52
|
+
//#endregion
|
|
53
|
+
export { type ConfigOptions, type FlatConfigArray, type OxlintConfigOptions, type OxlintConfigResult, type RuleOptions, type RuleScope, type RuleSeverity, addRule, bitmaskToHash, configureRule, disableAllRulesBut, disableRule, getEslintConfig, getOxlintConfig, optionsToBitmask, optionsToFilename, setRuleSeverity };
|
|
54
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/api/rule-helpers.ts","../src/hash.ts","../src/loader.ts"],"mappings":";;;;;AAkCA;iBAAgB,eAAA,CACd,MAAA,EAAQ,eAAA,EACR,QAAA,UACA,QAAA,EAAU,YAAA,EACV,OAAA,GAAU,WAAA;;;;iBAkBI,aAAA,CACd,MAAA,EAAQ,eAAA,EACR,QAAA,UACA,OAAA,aACA,WAAA,GAAc,WAAW;;;;;iBAiBX,WAAA,CACd,MAAA,EAAQ,eAAA,EACR,QAAA,UACA,OAAA,GAAU,WAAW;;;;;iBAqBP,OAAA,CACd,MAAA,EAAQ,eAAA,EACR,QAAA,UACA,QAAA,EAAU,YAAA,EACV,OAAA,GAAU,WAAA,cACV,WAAA,GAAc,WAAA;AApEO;AAkBvB;;AAlBuB,iBAuGP,kBAAA,CACd,MAAA,EAAQ,eAAe,EACvB,YAAA;;;;;AA7GF;;iBC1BgB,gBAAA,CAAiB,IAAmB,EAAb,aAAa;;;;;iBAapC,aAAA,CAAc,IAAY;;iBAM1B,iBAAA,CAAkB,IAAmB,EAAb,aAAa;;;;;ADOrD;;iBErBsB,eAAA,CACpB,IAAA,GAAM,aAAA,GACL,OAAA,CAAQ,eAAA;;;;;iBAmCK,eAAA,CACd,IAAA,GAAM,mBAAA,GACL,kBAAkB"}
|
package/dist/index.js
CHANGED
|
@@ -1,178 +1,184 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
5
|
+
//#region src/api/rule-helpers.ts
|
|
6
|
+
const CONFIG_PREFIX = "eslint-config-setup/";
|
|
7
|
+
/** Maps user-facing scope names to config block name segments. */
|
|
8
|
+
const SCOPE_TO_BLOCK = { configs: "config-files" };
|
|
9
|
+
/**
|
|
10
|
+
* Check if a config block matches a given scope.
|
|
11
|
+
* A block matches if its name is `eslint-config-setup/{segment}` or starts with `eslint-config-setup/{segment}-`.
|
|
12
|
+
*/
|
|
6
13
|
function blockMatchesScope(block, scope) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
14
|
+
const name = block.name;
|
|
15
|
+
if (name == null) return false;
|
|
16
|
+
const segment = SCOPE_TO_BLOCK[scope] ?? scope;
|
|
17
|
+
const target = `${CONFIG_PREFIX}${segment}`;
|
|
18
|
+
return name === target || name.startsWith(`${target}-`);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Change the severity of a rule across all config blocks, preserving options.
|
|
22
|
+
*/
|
|
13
23
|
function setRuleSeverity(config, ruleName, severity, options) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
for (const block of config) {
|
|
25
|
+
if (options?.scope !== void 0 && !blockMatchesScope(block, options.scope)) continue;
|
|
26
|
+
if (block.rules?.[ruleName] == null) continue;
|
|
27
|
+
const current = block.rules[ruleName];
|
|
28
|
+
if (Array.isArray(current)) block.rules[ruleName] = [severity, ...current.slice(1)];
|
|
29
|
+
else block.rules[ruleName] = severity;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Update the options of a rule across all config blocks, preserving severity.
|
|
34
|
+
*/
|
|
25
35
|
function configureRule(config, ruleName, options, ruleOptions) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
36
|
+
for (const block of config) {
|
|
37
|
+
if (ruleOptions?.scope !== void 0 && !blockMatchesScope(block, ruleOptions.scope)) continue;
|
|
38
|
+
if (block.rules?.[ruleName] == null) continue;
|
|
39
|
+
const current = block.rules[ruleName];
|
|
40
|
+
const severity = Array.isArray(current) ? current[0] : current;
|
|
41
|
+
block.rules[ruleName] = [severity, ...options];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Completely disable a rule across all config blocks.
|
|
46
|
+
* With scope: disables in the first matching block (creates entry if needed).
|
|
47
|
+
*/
|
|
35
48
|
function disableRule(config, ruleName, options) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
+
if (options?.scope != null) {
|
|
50
|
+
const { scope } = options;
|
|
51
|
+
const block = config.find((b) => blockMatchesScope(b, scope));
|
|
52
|
+
if (!block) return;
|
|
53
|
+
block.rules ??= {};
|
|
54
|
+
block.rules[ruleName] = "off";
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
for (const block of config) {
|
|
58
|
+
if (block.rules?.[ruleName] == null) continue;
|
|
59
|
+
block.rules[ruleName] = "off";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Add a new rule to the first (base) config block.
|
|
64
|
+
* With scope: adds to the first matching block instead.
|
|
65
|
+
*/
|
|
49
66
|
function addRule(config, ruleName, severity, options, ruleOptions) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
target.rules[ruleName] = ruleOpts ? [severity, ...ruleOpts] : severity;
|
|
70
|
-
}
|
|
67
|
+
let ruleOpts;
|
|
68
|
+
let scopeOpts;
|
|
69
|
+
if (Array.isArray(options)) {
|
|
70
|
+
ruleOpts = options;
|
|
71
|
+
scopeOpts = ruleOptions;
|
|
72
|
+
} else if (options && typeof options === "object" && "scope" in options) scopeOpts = options;
|
|
73
|
+
else if (options === void 0) scopeOpts = ruleOptions;
|
|
74
|
+
let target;
|
|
75
|
+
if (scopeOpts?.scope != null) {
|
|
76
|
+
const { scope } = scopeOpts;
|
|
77
|
+
target = config.find((b) => blockMatchesScope(b, scope));
|
|
78
|
+
} else target = config[0];
|
|
79
|
+
if (!target) return;
|
|
80
|
+
target.rules ??= {};
|
|
81
|
+
target.rules[ruleName] = ruleOpts ? [severity, ...ruleOpts] : severity;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Disable all rules except the specified one — useful for debugging.
|
|
85
|
+
*/
|
|
71
86
|
function disableAllRulesBut(config, keepRuleName) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
import { createHash } from "crypto";
|
|
87
|
+
for (const block of config) {
|
|
88
|
+
if (!block.rules) continue;
|
|
89
|
+
for (const ruleName of Object.keys(block.rules)) if (ruleName !== keepRuleName) block.rules[ruleName] = "off";
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//#endregion
|
|
93
|
+
//#region src/hash.ts
|
|
94
|
+
/**
|
|
95
|
+
* Converts config options to a deterministic bitmask.
|
|
96
|
+
* Bit order is fixed and must never change (would break published configs).
|
|
97
|
+
*/
|
|
84
98
|
function optionsToBitmask(opts) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
99
|
+
let mask = 0;
|
|
100
|
+
if (opts.react) mask |= 1;
|
|
101
|
+
if (opts.node) mask |= 2;
|
|
102
|
+
if (opts.ai) mask |= 4;
|
|
103
|
+
if (opts.oxlint) mask |= 8;
|
|
104
|
+
return mask;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Converts a bitmask to a short deterministic hash (8 hex chars).
|
|
108
|
+
* The same hash is produced at build-time (generate) and run-time (getConfig).
|
|
109
|
+
*/
|
|
92
110
|
function bitmaskToHash(mask) {
|
|
93
|
-
|
|
94
|
-
|
|
111
|
+
const input = `effective-eslint-config:${mask}`;
|
|
112
|
+
return createHash("sha1").update(input).digest("hex").slice(0, 8);
|
|
95
113
|
}
|
|
114
|
+
/** Convenience: options → filename (without path prefix). */
|
|
96
115
|
function optionsToFilename(opts) {
|
|
97
|
-
|
|
116
|
+
return `${bitmaskToHash(optionsToBitmask(opts))}.js`;
|
|
98
117
|
}
|
|
118
|
+
/** Converts OxLint-relevant options to a 3-bit bitmask (react, node, ai). */
|
|
99
119
|
function oxlintOptionsToBitmask(opts) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
120
|
+
let mask = 0;
|
|
121
|
+
if (opts.react) mask |= 1;
|
|
122
|
+
if (opts.node) mask |= 2;
|
|
123
|
+
if (opts.ai) mask |= 4;
|
|
124
|
+
return mask;
|
|
105
125
|
}
|
|
126
|
+
/** Deterministic hash for OxLint configs (different salt to avoid collisions). */
|
|
106
127
|
function oxlintBitmaskToHash(mask) {
|
|
107
|
-
|
|
108
|
-
|
|
128
|
+
const input = `eslint-config-setup-oxlint:${mask}`;
|
|
129
|
+
return createHash("sha1").update(input).digest("hex").slice(0, 8);
|
|
109
130
|
}
|
|
131
|
+
/** OxLint options → filename (without path prefix). */
|
|
110
132
|
function oxlintOptionsToFilename(opts) {
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
133
|
+
return `${oxlintBitmaskToHash(oxlintOptionsToBitmask(opts))}.json`;
|
|
134
|
+
}
|
|
135
|
+
//#endregion
|
|
136
|
+
//#region src/loader.ts
|
|
137
|
+
/**
|
|
138
|
+
* Loads a pre-generated ESLint config by dynamically importing the hashed file.
|
|
139
|
+
* The hash is computed from the options using the same algorithm as the build.
|
|
140
|
+
*/
|
|
118
141
|
async function getEslintConfig(opts = {}) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
{ cause: error }
|
|
140
|
-
);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
142
|
+
const filename = optionsToFilename(opts);
|
|
143
|
+
const dirname = import.meta.dirname;
|
|
144
|
+
const configPath = path.join(dirname, "configs", filename);
|
|
145
|
+
if (!existsSync(configPath)) throwMissingConfigError(opts, filename);
|
|
146
|
+
const configUrl = pathToFileURL(configPath);
|
|
147
|
+
configUrl.search = String(Date.now());
|
|
148
|
+
try {
|
|
149
|
+
return (await import(
|
|
150
|
+
/* webpackIgnore: true */
|
|
151
|
+
configUrl.href
|
|
152
|
+
)).default;
|
|
153
|
+
} catch (error) {
|
|
154
|
+
if (!existsSync(configPath)) throwMissingConfigError(opts, filename, error);
|
|
155
|
+
throw new Error(`eslint-config-setup: Pre-generated config failed to load for options ${JSON.stringify(opts)}. Expected file: configs/${filename}. Original error: ${getErrorMessage(error)}`, { cause: error });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Loads a pre-generated OxLint config from the hashed JSON file.
|
|
160
|
+
* Only `react`, `node`, and `ai` flags are relevant — `oxlint` is ignored.
|
|
161
|
+
*/
|
|
143
162
|
function getOxlintConfig(opts = {}) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
);
|
|
154
|
-
}
|
|
163
|
+
const filename = oxlintOptionsToFilename(opts);
|
|
164
|
+
const dirname = import.meta.dirname;
|
|
165
|
+
const configPath = path.join(dirname, "oxlint-configs", filename);
|
|
166
|
+
try {
|
|
167
|
+
const content = readFileSync(configPath, "utf8");
|
|
168
|
+
return JSON.parse(content);
|
|
169
|
+
} catch {
|
|
170
|
+
throw new Error(`eslint-config-setup: No pre-generated OxLint config found for options ${JSON.stringify(opts)}. Expected file: oxlint-configs/${filename}. Run "npm run generate" in the package to build configs.`);
|
|
171
|
+
}
|
|
155
172
|
}
|
|
156
173
|
function getErrorMessage(error) {
|
|
157
|
-
|
|
174
|
+
return error instanceof Error ? error.message : String(error);
|
|
158
175
|
}
|
|
159
176
|
function throwMissingConfigError(opts, filename, cause) {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
addRule,
|
|
168
|
-
bitmaskToHash,
|
|
169
|
-
configureRule,
|
|
170
|
-
disableAllRulesBut,
|
|
171
|
-
disableRule,
|
|
172
|
-
getEslintConfig,
|
|
173
|
-
getOxlintConfig,
|
|
174
|
-
optionsToBitmask,
|
|
175
|
-
optionsToFilename,
|
|
176
|
-
setRuleSeverity
|
|
177
|
-
};
|
|
177
|
+
const message = `eslint-config-setup: No pre-generated config found for options ${JSON.stringify(opts)}. Expected file: configs/${filename}. Run "npm run generate" in the package to build configs.`;
|
|
178
|
+
if (cause === void 0) throw new Error(message);
|
|
179
|
+
throw new Error(message, { cause });
|
|
180
|
+
}
|
|
181
|
+
//#endregion
|
|
182
|
+
export { addRule, bitmaskToHash, configureRule, disableAllRulesBut, disableRule, getEslintConfig, getOxlintConfig, optionsToBitmask, optionsToFilename, setRuleSeverity };
|
|
183
|
+
|
|
178
184
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/api/rule-helpers.ts","../src/hash.ts","../src/loader.ts"],"sourcesContent":["/* eslint-disable max-params, complexity -- Public API: config + ruleName + severity + options is the natural signature. Options objects would hurt ergonomics for one-liner calls. */\nimport type { Linter } from \"eslint\"\n\nimport type {\n FlatConfigArray,\n RuleOptions,\n RuleSeverity,\n} from \"../types\"\n\nconst CONFIG_PREFIX = \"eslint-config-setup/\"\n\n/** Maps user-facing scope names to config block name segments. */\nconst SCOPE_TO_BLOCK: Record<string, string> = {\n configs: \"config-files\",\n}\n\n/**\n * Check if a config block matches a given scope.\n * A block matches if its name is `eslint-config-setup/{segment}` or starts with `eslint-config-setup/{segment}-`.\n */\nfunction blockMatchesScope(\n block: Linter.Config,\n scope: string,\n): boolean {\n const name = block.name\n if (name == null) return false\n const segment = SCOPE_TO_BLOCK[scope] ?? scope\n const target = `${CONFIG_PREFIX}${segment}`\n return name === target || name.startsWith(`${target}-`)\n}\n\n/**\n * Change the severity of a rule across all config blocks, preserving options.\n */\nexport function setRuleSeverity(\n config: FlatConfigArray,\n ruleName: string,\n severity: RuleSeverity,\n options?: RuleOptions,\n): void {\n for (const block of config) {\n if (options?.scope !== undefined && !blockMatchesScope(block, options.scope)) continue\n if (block.rules?.[ruleName] == null) continue\n\n const current = block.rules[ruleName]\n if (Array.isArray(current)) {\n block.rules[ruleName] = [severity, ...current.slice(1)] as Linter.RuleEntry\n } else {\n block.rules[ruleName] = severity\n }\n }\n}\n\n/**\n * Update the options of a rule across all config blocks, preserving severity.\n */\nexport function configureRule(\n config: FlatConfigArray,\n ruleName: string,\n options: unknown[],\n ruleOptions?: RuleOptions,\n): void {\n for (const block of config) {\n if (ruleOptions?.scope !== undefined && !blockMatchesScope(block, ruleOptions.scope))\n continue\n if (block.rules?.[ruleName] == null) continue\n\n const current = block.rules[ruleName]\n const severity = Array.isArray(current) ? current[0] : current\n block.rules[ruleName] = [severity, ...options] as Linter.RuleEntry\n }\n}\n\n/**\n * Completely disable a rule across all config blocks.\n * With scope: disables in the first matching block (creates entry if needed).\n */\nexport function disableRule(\n config: FlatConfigArray,\n ruleName: string,\n options?: RuleOptions,\n): void {\n if (options?.scope != null) {\n const { scope } = options\n const block = config.find((b) => blockMatchesScope(b, scope))\n if (!block) return\n block.rules ??= {}\n block.rules[ruleName] = \"off\"\n return\n }\n\n for (const block of config) {\n if (block.rules?.[ruleName] == null) continue\n block.rules[ruleName] = \"off\"\n }\n}\n\n/**\n * Add a new rule to the first (base) config block.\n * With scope: adds to the first matching block instead.\n */\nexport function addRule(\n config: FlatConfigArray,\n ruleName: string,\n severity: RuleSeverity,\n options?: RuleOptions | unknown[],\n ruleOptions?: RuleOptions,\n): void {\n // Handle overloaded signatures: addRule(config, rule, severity, options?, ruleOptions?)\n // When options is a plain object with scope, it's actually ruleOptions\n let ruleOpts: undefined | unknown[]\n let scopeOpts: RuleOptions | undefined\n\n if (Array.isArray(options)) {\n ruleOpts = options\n scopeOpts = ruleOptions\n } else if (options && typeof options === \"object\" && \"scope\" in options) {\n scopeOpts = options\n } else if (options === undefined) {\n scopeOpts = ruleOptions\n }\n\n let target: Linter.Config | undefined\n if (scopeOpts?.scope != null) {\n const { scope } = scopeOpts\n target = config.find((b) => blockMatchesScope(b, scope))\n } else {\n target = config[0]\n }\n\n if (!target) return\n\n target.rules ??= {}\n target.rules[ruleName] = ruleOpts\n ? ([severity, ...ruleOpts] as Linter.RuleEntry)\n : severity\n}\n\n/**\n * Disable all rules except the specified one — useful for debugging.\n */\nexport function disableAllRulesBut(\n config: FlatConfigArray,\n keepRuleName: string,\n): void {\n for (const block of config) {\n if (!block.rules) continue\n for (const ruleName of Object.keys(block.rules)) {\n if (ruleName !== keepRuleName) {\n block.rules[ruleName] = \"off\"\n }\n }\n }\n}\n","import { createHash } from \"node:crypto\"\n\nimport type { ConfigOptions, OxlintConfigOptions } from \"./types\"\n\n/**\n * Converts config options to a deterministic bitmask.\n * Bit order is fixed and must never change (would break published configs).\n */\nexport function optionsToBitmask(opts: ConfigOptions): number {\n let mask = 0\n if (opts.react) mask |= 1 << 0\n if (opts.node) mask |= 1 << 1\n if (opts.ai) mask |= 1 << 2\n if (opts.oxlint) mask |= 1 << 3\n return mask\n}\n\n/**\n * Converts a bitmask to a short deterministic hash (8 hex chars).\n * The same hash is produced at build-time (generate) and run-time (getConfig).\n */\nexport function bitmaskToHash(mask: number): string {\n const input = `effective-eslint-config:${mask}`\n return createHash(\"sha1\").update(input).digest(\"hex\").slice(0, 8)\n}\n\n/** Convenience: options → filename (without path prefix). */\nexport function optionsToFilename(opts: ConfigOptions): string {\n return `${bitmaskToHash(optionsToBitmask(opts))}.js`\n}\n\n/** Total number of permutations (2^4 = 16). */\nexport const TOTAL_PERMUTATIONS = 16\n\n/** Iterate all possible option combinations. */\nexport function* allPermutations(): Generator<ConfigOptions> {\n for (let mask = 0; mask < TOTAL_PERMUTATIONS; mask++) {\n yield {\n react: Boolean(mask & (1 << 0)),\n node: Boolean(mask & (1 << 1)),\n ai: Boolean(mask & (1 << 2)),\n oxlint: Boolean(mask & (1 << 3)),\n }\n }\n}\n\n// --- OxLint config permutations (3 flags → 8 combos) ---\n\n/** Converts OxLint-relevant options to a 3-bit bitmask (react, node, ai). */\nexport function oxlintOptionsToBitmask(opts: OxlintConfigOptions): number {\n let mask = 0\n if (opts.react) mask |= 1 << 0\n if (opts.node) mask |= 1 << 1\n if (opts.ai) mask |= 1 << 2\n return mask\n}\n\n/** Deterministic hash for OxLint configs (different salt to avoid collisions). */\nexport function oxlintBitmaskToHash(mask: number): string {\n const input = `eslint-config-setup-oxlint:${mask}`\n return createHash(\"sha1\").update(input).digest(\"hex\").slice(0, 8)\n}\n\n/** OxLint options → filename (without path prefix). */\nexport function oxlintOptionsToFilename(opts: OxlintConfigOptions): string {\n return `${oxlintBitmaskToHash(oxlintOptionsToBitmask(opts))}.json`\n}\n\n/** Total number of OxLint permutations (2^3 = 8). */\nexport const TOTAL_OXLINT_PERMUTATIONS = 8\n\n/** Iterate all OxLint option combinations. */\nexport function* allOxlintPermutations(): Generator<OxlintConfigOptions> {\n for (let mask = 0; mask < TOTAL_OXLINT_PERMUTATIONS; mask++) {\n yield {\n react: Boolean(mask & (1 << 0)),\n node: Boolean(mask & (1 << 1)),\n ai: Boolean(mask & (1 << 2)),\n }\n }\n}\n","/* eslint-disable security/detect-non-literal-fs-filename, @typescript-eslint/no-unsafe-type-assertion -- Paths are computed from deterministic hashes in dist/, not from user input. */\nimport { existsSync, readFileSync } from \"node:fs\"\nimport path from \"node:path\"\nimport { pathToFileURL } from \"node:url\"\n\nimport type { ConfigOptions, FlatConfigArray, OxlintConfigOptions, OxlintConfigResult } from \"./types\"\n\nimport { optionsToFilename, oxlintOptionsToFilename } from \"./hash\"\n\n/**\n * Loads a pre-generated ESLint config by dynamically importing the hashed file.\n * The hash is computed from the options using the same algorithm as the build.\n */\nexport async function getEslintConfig(\n opts: ConfigOptions = {},\n): Promise<FlatConfigArray> {\n const filename = optionsToFilename(opts)\n const dirname = import.meta.dirname\n const configPath = path.join(dirname, \"configs\", filename)\n\n if (!existsSync(configPath)) {\n throwMissingConfigError(opts, filename)\n }\n\n const configUrl = pathToFileURL(configPath)\n configUrl.search = String(Date.now())\n\n try {\n const module = (await import(\n /* webpackIgnore: true */\n configUrl.href\n )) as { default: FlatConfigArray }\n return module.default\n } catch (error) {\n if (!existsSync(configPath)) {\n throwMissingConfigError(opts, filename, error)\n }\n\n throw new Error(\n `eslint-config-setup: Pre-generated config failed to load for options ${JSON.stringify(opts)}. ` +\n `Expected file: configs/${filename}. Original error: ${getErrorMessage(error)}`,\n { cause: error },\n )\n }\n}\n\n/**\n * Loads a pre-generated OxLint config from the hashed JSON file.\n * Only `react`, `node`, and `ai` flags are relevant — `oxlint` is ignored.\n */\nexport function getOxlintConfig(\n opts: OxlintConfigOptions = {},\n): OxlintConfigResult {\n const filename = oxlintOptionsToFilename(opts)\n const dirname = import.meta.dirname\n const configPath = path.join(dirname, \"oxlint-configs\", filename)\n\n try {\n const content = readFileSync(configPath, \"utf8\")\n return JSON.parse(content) as OxlintConfigResult\n } catch {\n throw new Error(\n `eslint-config-setup: No pre-generated OxLint config found for options ${JSON.stringify(opts)}. ` +\n `Expected file: oxlint-configs/${filename}. Run \"npm run generate\" in the package to build configs.`,\n )\n }\n}\n\nfunction getErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\nfunction throwMissingConfigError(\n opts: ConfigOptions,\n filename: string,\n cause?: unknown,\n): never {\n const message =\n `eslint-config-setup: No pre-generated config found for options ${JSON.stringify(opts)}. ` +\n `Expected file: configs/${filename}. Run \"npm run generate\" in the package to build configs.`\n\n if (cause === undefined) {\n throw new Error(message)\n }\n\n throw new Error(message, { cause })\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/api/rule-helpers.ts","../src/hash.ts","../src/loader.ts"],"sourcesContent":["/* eslint-disable max-params, complexity -- Public API: config + ruleName + severity + options is the natural signature. Options objects would hurt ergonomics for one-liner calls. */\nimport type { Linter } from \"eslint\"\n\nimport type {\n FlatConfigArray,\n RuleOptions,\n RuleSeverity,\n} from \"../types\"\n\nconst CONFIG_PREFIX = \"eslint-config-setup/\"\n\n/** Maps user-facing scope names to config block name segments. */\nconst SCOPE_TO_BLOCK: Record<string, string> = {\n configs: \"config-files\",\n}\n\n/**\n * Check if a config block matches a given scope.\n * A block matches if its name is `eslint-config-setup/{segment}` or starts with `eslint-config-setup/{segment}-`.\n */\nfunction blockMatchesScope(\n block: Linter.Config,\n scope: string,\n): boolean {\n const name = block.name\n if (name == null) return false\n const segment = SCOPE_TO_BLOCK[scope] ?? scope\n const target = `${CONFIG_PREFIX}${segment}`\n return name === target || name.startsWith(`${target}-`)\n}\n\n/**\n * Change the severity of a rule across all config blocks, preserving options.\n */\nexport function setRuleSeverity(\n config: FlatConfigArray,\n ruleName: string,\n severity: RuleSeverity,\n options?: RuleOptions,\n): void {\n for (const block of config) {\n if (options?.scope !== undefined && !blockMatchesScope(block, options.scope)) continue\n if (block.rules?.[ruleName] == null) continue\n\n const current = block.rules[ruleName]\n if (Array.isArray(current)) {\n block.rules[ruleName] = [severity, ...current.slice(1)] as Linter.RuleEntry\n } else {\n block.rules[ruleName] = severity\n }\n }\n}\n\n/**\n * Update the options of a rule across all config blocks, preserving severity.\n */\nexport function configureRule(\n config: FlatConfigArray,\n ruleName: string,\n options: unknown[],\n ruleOptions?: RuleOptions,\n): void {\n for (const block of config) {\n if (ruleOptions?.scope !== undefined && !blockMatchesScope(block, ruleOptions.scope))\n continue\n if (block.rules?.[ruleName] == null) continue\n\n const current = block.rules[ruleName]\n const severity = Array.isArray(current) ? current[0] : current\n block.rules[ruleName] = [severity, ...options] as Linter.RuleEntry\n }\n}\n\n/**\n * Completely disable a rule across all config blocks.\n * With scope: disables in the first matching block (creates entry if needed).\n */\nexport function disableRule(\n config: FlatConfigArray,\n ruleName: string,\n options?: RuleOptions,\n): void {\n if (options?.scope != null) {\n const { scope } = options\n const block = config.find((b) => blockMatchesScope(b, scope))\n if (!block) return\n block.rules ??= {}\n block.rules[ruleName] = \"off\"\n return\n }\n\n for (const block of config) {\n if (block.rules?.[ruleName] == null) continue\n block.rules[ruleName] = \"off\"\n }\n}\n\n/**\n * Add a new rule to the first (base) config block.\n * With scope: adds to the first matching block instead.\n */\nexport function addRule(\n config: FlatConfigArray,\n ruleName: string,\n severity: RuleSeverity,\n options?: RuleOptions | unknown[],\n ruleOptions?: RuleOptions,\n): void {\n // Handle overloaded signatures: addRule(config, rule, severity, options?, ruleOptions?)\n // When options is a plain object with scope, it's actually ruleOptions\n let ruleOpts: undefined | unknown[]\n let scopeOpts: RuleOptions | undefined\n\n if (Array.isArray(options)) {\n ruleOpts = options\n scopeOpts = ruleOptions\n } else if (options && typeof options === \"object\" && \"scope\" in options) {\n scopeOpts = options\n } else if (options === undefined) {\n scopeOpts = ruleOptions\n }\n\n let target: Linter.Config | undefined\n if (scopeOpts?.scope != null) {\n const { scope } = scopeOpts\n target = config.find((b) => blockMatchesScope(b, scope))\n } else {\n target = config[0]\n }\n\n if (!target) return\n\n target.rules ??= {}\n target.rules[ruleName] = ruleOpts\n ? ([severity, ...ruleOpts] as Linter.RuleEntry)\n : severity\n}\n\n/**\n * Disable all rules except the specified one — useful for debugging.\n */\nexport function disableAllRulesBut(\n config: FlatConfigArray,\n keepRuleName: string,\n): void {\n for (const block of config) {\n if (!block.rules) continue\n for (const ruleName of Object.keys(block.rules)) {\n if (ruleName !== keepRuleName) {\n block.rules[ruleName] = \"off\"\n }\n }\n }\n}\n","import { createHash } from \"node:crypto\"\n\nimport type { ConfigOptions, OxlintConfigOptions } from \"./types\"\n\n/**\n * Converts config options to a deterministic bitmask.\n * Bit order is fixed and must never change (would break published configs).\n */\nexport function optionsToBitmask(opts: ConfigOptions): number {\n let mask = 0\n if (opts.react) mask |= 1 << 0\n if (opts.node) mask |= 1 << 1\n if (opts.ai) mask |= 1 << 2\n if (opts.oxlint) mask |= 1 << 3\n return mask\n}\n\n/**\n * Converts a bitmask to a short deterministic hash (8 hex chars).\n * The same hash is produced at build-time (generate) and run-time (getConfig).\n */\nexport function bitmaskToHash(mask: number): string {\n const input = `effective-eslint-config:${mask}`\n return createHash(\"sha1\").update(input).digest(\"hex\").slice(0, 8)\n}\n\n/** Convenience: options → filename (without path prefix). */\nexport function optionsToFilename(opts: ConfigOptions): string {\n return `${bitmaskToHash(optionsToBitmask(opts))}.js`\n}\n\n/** Total number of permutations (2^4 = 16). */\nexport const TOTAL_PERMUTATIONS = 16\n\n/** Iterate all possible option combinations. */\nexport function* allPermutations(): Generator<ConfigOptions> {\n for (let mask = 0; mask < TOTAL_PERMUTATIONS; mask++) {\n yield {\n react: Boolean(mask & (1 << 0)),\n node: Boolean(mask & (1 << 1)),\n ai: Boolean(mask & (1 << 2)),\n oxlint: Boolean(mask & (1 << 3)),\n }\n }\n}\n\n// --- OxLint config permutations (3 flags → 8 combos) ---\n\n/** Converts OxLint-relevant options to a 3-bit bitmask (react, node, ai). */\nexport function oxlintOptionsToBitmask(opts: OxlintConfigOptions): number {\n let mask = 0\n if (opts.react) mask |= 1 << 0\n if (opts.node) mask |= 1 << 1\n if (opts.ai) mask |= 1 << 2\n return mask\n}\n\n/** Deterministic hash for OxLint configs (different salt to avoid collisions). */\nexport function oxlintBitmaskToHash(mask: number): string {\n const input = `eslint-config-setup-oxlint:${mask}`\n return createHash(\"sha1\").update(input).digest(\"hex\").slice(0, 8)\n}\n\n/** OxLint options → filename (without path prefix). */\nexport function oxlintOptionsToFilename(opts: OxlintConfigOptions): string {\n return `${oxlintBitmaskToHash(oxlintOptionsToBitmask(opts))}.json`\n}\n\n/** Total number of OxLint permutations (2^3 = 8). */\nexport const TOTAL_OXLINT_PERMUTATIONS = 8\n\n/** Iterate all OxLint option combinations. */\nexport function* allOxlintPermutations(): Generator<OxlintConfigOptions> {\n for (let mask = 0; mask < TOTAL_OXLINT_PERMUTATIONS; mask++) {\n yield {\n react: Boolean(mask & (1 << 0)),\n node: Boolean(mask & (1 << 1)),\n ai: Boolean(mask & (1 << 2)),\n }\n }\n}\n","/* eslint-disable security/detect-non-literal-fs-filename, @typescript-eslint/no-unsafe-type-assertion -- Paths are computed from deterministic hashes in dist/, not from user input. */\nimport { existsSync, readFileSync } from \"node:fs\"\nimport path from \"node:path\"\nimport { pathToFileURL } from \"node:url\"\n\nimport type { ConfigOptions, FlatConfigArray, OxlintConfigOptions, OxlintConfigResult } from \"./types\"\n\nimport { optionsToFilename, oxlintOptionsToFilename } from \"./hash\"\n\n/**\n * Loads a pre-generated ESLint config by dynamically importing the hashed file.\n * The hash is computed from the options using the same algorithm as the build.\n */\nexport async function getEslintConfig(\n opts: ConfigOptions = {},\n): Promise<FlatConfigArray> {\n const filename = optionsToFilename(opts)\n const dirname = import.meta.dirname\n const configPath = path.join(dirname, \"configs\", filename)\n\n if (!existsSync(configPath)) {\n throwMissingConfigError(opts, filename)\n }\n\n const configUrl = pathToFileURL(configPath)\n configUrl.search = String(Date.now())\n\n try {\n const module = (await import(\n /* webpackIgnore: true */\n configUrl.href\n )) as { default: FlatConfigArray }\n return module.default\n } catch (error) {\n if (!existsSync(configPath)) {\n throwMissingConfigError(opts, filename, error)\n }\n\n throw new Error(\n `eslint-config-setup: Pre-generated config failed to load for options ${JSON.stringify(opts)}. ` +\n `Expected file: configs/${filename}. Original error: ${getErrorMessage(error)}`,\n { cause: error },\n )\n }\n}\n\n/**\n * Loads a pre-generated OxLint config from the hashed JSON file.\n * Only `react`, `node`, and `ai` flags are relevant — `oxlint` is ignored.\n */\nexport function getOxlintConfig(\n opts: OxlintConfigOptions = {},\n): OxlintConfigResult {\n const filename = oxlintOptionsToFilename(opts)\n const dirname = import.meta.dirname\n const configPath = path.join(dirname, \"oxlint-configs\", filename)\n\n try {\n const content = readFileSync(configPath, \"utf8\")\n return JSON.parse(content) as OxlintConfigResult\n } catch {\n throw new Error(\n `eslint-config-setup: No pre-generated OxLint config found for options ${JSON.stringify(opts)}. ` +\n `Expected file: oxlint-configs/${filename}. Run \"npm run generate\" in the package to build configs.`,\n )\n }\n}\n\nfunction getErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\nfunction throwMissingConfigError(\n opts: ConfigOptions,\n filename: string,\n cause?: unknown,\n): never {\n const message =\n `eslint-config-setup: No pre-generated config found for options ${JSON.stringify(opts)}. ` +\n `Expected file: configs/${filename}. Run \"npm run generate\" in the package to build configs.`\n\n if (cause === undefined) {\n throw new Error(message)\n }\n\n throw new Error(message, { cause })\n}\n"],"mappings":"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"}
|