@blumintinc/eslint-plugin-blumint 1.20.95 → 1.20.97
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/lib/index.js +1 -1
- package/lib/rules/enforce-boolean-naming-prefixes.js +38 -3
- package/lib/rules/enforce-css-media-queries.d.ts +2 -1
- package/lib/rules/enforce-css-media-queries.js +203 -8
- package/lib/rules/enforce-exported-function-types.js +209 -6
- package/lib/rules/enforce-firestore-doc-ref-generic.js +71 -18
- package/lib/rules/enforce-mui-rounded-icons.d.ts +2 -1
- package/lib/rules/enforce-mui-rounded-icons.js +194 -13
- package/lib/rules/enforce-positive-naming.js +112 -24
- package/lib/rules/generic-starts-with-t.js +49 -0
- package/lib/rules/global-const-style.js +101 -51
- package/lib/rules/no-always-true-false-conditions.js +231 -62
- package/lib/rules/no-unnecessary-verb-suffix.js +52 -5
- package/lib/rules/parallelize-loop-awaits.d.ts +1 -0
- package/lib/rules/parallelize-loop-awaits.js +233 -43
- package/lib/rules/prefer-getter-over-parameterless-method.d.ts +2 -1
- package/lib/rules/prefer-getter-over-parameterless-method.js +259 -0
- package/lib/rules/prefer-type-alias-over-typeof-constant.js +63 -4
- package/lib/rules/require-https-error.js +6 -2
- package/lib/rules/use-custom-link.js +45 -1
- package/lib/rules/use-custom-memo.js +30 -0
- package/lib/rules/use-custom-router.js +32 -2
- package/lib/utils/harvestRuleTesterCases.d.ts +48 -0
- package/lib/utils/harvestRuleTesterCases.js +168 -0
- package/package.json +1 -1
- package/release-manifest.json +151 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.harvestRuleTesterCases = void 0;
|
|
27
|
+
const fs = __importStar(require("fs"));
|
|
28
|
+
const os = __importStar(require("os"));
|
|
29
|
+
const path = __importStar(require("path"));
|
|
30
|
+
const sharedTesters = __importStar(require("./ruleTester"));
|
|
31
|
+
const TESTS_DIR = path.join(__dirname, '..', 'tests');
|
|
32
|
+
/**
|
|
33
|
+
* Only suites that import the shared tester module can declare a case, since
|
|
34
|
+
* `src/tests/no-local-rule-tester.test.ts` forbids a locally-built tester. That
|
|
35
|
+
* makes the import a sound admission test rather than a heuristic, and it is
|
|
36
|
+
* what keeps this affordable: the ~28 files it excludes are the meta-suites
|
|
37
|
+
* (`fixer-type-safety`, `docs-examples-conformance`, `rule-crash-robustness`,
|
|
38
|
+
* this guard's own siblings) which run full corpus sweeps at module scope and
|
|
39
|
+
* cost more to load than every rule suite combined.
|
|
40
|
+
*
|
|
41
|
+
* Matching the import rather than a `ruleTesterTs.run(` call site is
|
|
42
|
+
* deliberate: `prefer-next-dynamic.test.ts` aliases the tester
|
|
43
|
+
* (`const jsx = ruleTesterJsx`) before calling `run`, so a call-site pattern
|
|
44
|
+
* drops it.
|
|
45
|
+
*/
|
|
46
|
+
const IMPORTS_SHARED_TESTER = /from\s+'\.\.\/utils\/ruleTester'/;
|
|
47
|
+
/**
|
|
48
|
+
* Jest registers a test for every `describe`/`it` a loaded module calls, so
|
|
49
|
+
* loading 271 suites inside a suite would graft their entire test list onto
|
|
50
|
+
* this one. Neutralizing the registrars for the duration of the load keeps the
|
|
51
|
+
* captured declarations and discards the registrations.
|
|
52
|
+
*
|
|
53
|
+
* `describe` bodies still execute — several suites call `run` inside one, and
|
|
54
|
+
* skipping the body would drop those cases — but everything that would register
|
|
55
|
+
* or assert becomes a no-op.
|
|
56
|
+
*/
|
|
57
|
+
const REGISTRAR_GLOBALS = [
|
|
58
|
+
'it',
|
|
59
|
+
'test',
|
|
60
|
+
'beforeEach',
|
|
61
|
+
'afterEach',
|
|
62
|
+
'beforeAll',
|
|
63
|
+
'afterAll',
|
|
64
|
+
];
|
|
65
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
66
|
+
const asAny = (value) => value;
|
|
67
|
+
const noop = () => undefined;
|
|
68
|
+
/** `it.each(rows)(name, fn)` is a call chain, so the stub needs the same shape. */
|
|
69
|
+
const withEach = (fn) => {
|
|
70
|
+
fn.each = () => () => undefined;
|
|
71
|
+
fn.only = fn;
|
|
72
|
+
fn.skip = fn;
|
|
73
|
+
fn.todo = noop;
|
|
74
|
+
fn.failing = fn;
|
|
75
|
+
fn.concurrent = fn;
|
|
76
|
+
return fn;
|
|
77
|
+
};
|
|
78
|
+
function harvestRuleTesterCases() {
|
|
79
|
+
const suites = [];
|
|
80
|
+
const failures = [];
|
|
81
|
+
let currentFile = '';
|
|
82
|
+
let filesLoaded = 0;
|
|
83
|
+
let filesSkipped = 0;
|
|
84
|
+
const testerEntries = Object.entries(sharedTesters).filter(([, value]) => typeof asAny(value)?.run === 'function');
|
|
85
|
+
const originalRun = new Map();
|
|
86
|
+
for (const [key, tester] of testerEntries) {
|
|
87
|
+
originalRun.set(key, tester.run);
|
|
88
|
+
tester.run = (name, rule, tests) => {
|
|
89
|
+
const bag = asAny(tests) || {};
|
|
90
|
+
suites.push({
|
|
91
|
+
name,
|
|
92
|
+
tester: key,
|
|
93
|
+
file: currentFile,
|
|
94
|
+
rule,
|
|
95
|
+
valid: bag.valid || [],
|
|
96
|
+
invalid: bag.invalid || [],
|
|
97
|
+
});
|
|
98
|
+
return undefined;
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
const globalScope = global;
|
|
102
|
+
const savedGlobals = new Map();
|
|
103
|
+
const stub = (key, value) => {
|
|
104
|
+
savedGlobals.set(key, globalScope[key]);
|
|
105
|
+
globalScope[key] = value;
|
|
106
|
+
};
|
|
107
|
+
stub('describe', withEach((_name, body) => {
|
|
108
|
+
if (typeof body === 'function')
|
|
109
|
+
body();
|
|
110
|
+
}));
|
|
111
|
+
for (const key of REGISTRAR_GLOBALS)
|
|
112
|
+
stub(key, withEach(noop));
|
|
113
|
+
/**
|
|
114
|
+
* A handful of suites write fixture files at module scope, and
|
|
115
|
+
* `test-file-location-enforcement` writes them under
|
|
116
|
+
* `path.join(process.cwd(), '.cursor/tmp/...')` — a path it also `rmSync`s in
|
|
117
|
+
* an `afterAll` that the stubs above turn into a no-op. Loading it from the
|
|
118
|
+
* real working directory would therefore race that suite when it runs
|
|
119
|
+
* concurrently in another worker (its cleanup landing between this harvest's
|
|
120
|
+
* `mkdirSync` and `writeFileSync` throws ENOENT) and would strand fixtures in
|
|
121
|
+
* the repo when it does not. Pointing the working directory at a private
|
|
122
|
+
* scratch root for the duration of the load sends every cwd-derived write
|
|
123
|
+
* somewhere no other worker can see, and it is removed below.
|
|
124
|
+
*
|
|
125
|
+
* The paths the suites *record* are unaffected: they are made relative to the
|
|
126
|
+
* same cwd they were built from, so the harvested filenames come out
|
|
127
|
+
* identical either way.
|
|
128
|
+
*/
|
|
129
|
+
const scratchRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'blumint-harvest-'));
|
|
130
|
+
const realCwd = process.cwd();
|
|
131
|
+
process.chdir(scratchRoot);
|
|
132
|
+
try {
|
|
133
|
+
const files = fs
|
|
134
|
+
.readdirSync(TESTS_DIR)
|
|
135
|
+
.filter((file) => file.endsWith('.test.ts'))
|
|
136
|
+
.sort();
|
|
137
|
+
for (const file of files) {
|
|
138
|
+
const fullPath = path.join(TESTS_DIR, file);
|
|
139
|
+
if (!IMPORTS_SHARED_TESTER.test(fs.readFileSync(fullPath, 'utf8'))) {
|
|
140
|
+
filesSkipped++;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
currentFile = file;
|
|
144
|
+
try {
|
|
145
|
+
require(fullPath);
|
|
146
|
+
filesLoaded++;
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
failures.push(`${file}: ${error?.message}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
finally {
|
|
154
|
+
process.chdir(realCwd);
|
|
155
|
+
fs.rmSync(scratchRoot, { recursive: true, force: true });
|
|
156
|
+
for (const [key, tester] of testerEntries) {
|
|
157
|
+
const original = originalRun.get(key);
|
|
158
|
+
if (original)
|
|
159
|
+
tester.run = original;
|
|
160
|
+
}
|
|
161
|
+
for (const [key, value] of savedGlobals)
|
|
162
|
+
globalScope[key] = value;
|
|
163
|
+
}
|
|
164
|
+
return { suites, failures, filesLoaded, filesSkipped };
|
|
165
|
+
}
|
|
166
|
+
exports.harvestRuleTesterCases = harvestRuleTesterCases;
|
|
167
|
+
/* eslint-enable @typescript-eslint/no-explicit-any */
|
|
168
|
+
//# sourceMappingURL=harvestRuleTesterCases.js.map
|
package/package.json
CHANGED
package/release-manifest.json
CHANGED
|
@@ -1,4 +1,155 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "1.20.97",
|
|
4
|
+
"date": "2026-08-04T08:50:14.394Z",
|
|
5
|
+
"rules": [
|
|
6
|
+
{
|
|
7
|
+
"name": "enforce-boolean-naming-prefixes",
|
|
8
|
+
"changeType": "fix",
|
|
9
|
+
"issues": [
|
|
10
|
+
1690,
|
|
11
|
+
1691
|
|
12
|
+
],
|
|
13
|
+
"summary": "infer a callee's return from its body when the annotation is absent (closes #1691); accept a digit or $ fused onto an UPPER_SNAKE prefix (closes #1690)"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"name": "enforce-positive-naming",
|
|
17
|
+
"changeType": "fix",
|
|
18
|
+
"issues": [
|
|
19
|
+
1692
|
|
20
|
+
],
|
|
21
|
+
"summary": "decline when a function's returns yield no verdict (closes #1692)"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"version": "1.20.96",
|
|
27
|
+
"date": "2026-08-04T07:23:58.552Z",
|
|
28
|
+
"rules": [
|
|
29
|
+
{
|
|
30
|
+
"name": "enforce-css-media-queries",
|
|
31
|
+
"changeType": "fix",
|
|
32
|
+
"issues": [
|
|
33
|
+
1675
|
|
34
|
+
],
|
|
35
|
+
"summary": "exempt capability queries and report once per usage (closes #1675)"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"name": "enforce-exported-function-types",
|
|
39
|
+
"changeType": "fix",
|
|
40
|
+
"issues": [
|
|
41
|
+
1677,
|
|
42
|
+
1686
|
|
43
|
+
],
|
|
44
|
+
"summary": "read destructured props params and resolve memo(Identifier) components (closes #1686); see arrow and memo/forwardRef component shapes, autofix the type export (closes #1677)"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"name": "enforce-firestore-doc-ref-generic",
|
|
48
|
+
"changeType": "fix",
|
|
49
|
+
"issues": [
|
|
50
|
+
1678
|
|
51
|
+
],
|
|
52
|
+
"summary": "resolve type-alias generics beside interfaces (closes #1678)"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"name": "enforce-mui-rounded-icons",
|
|
56
|
+
"changeType": "fix",
|
|
57
|
+
"issues": [
|
|
58
|
+
1674
|
|
59
|
+
],
|
|
60
|
+
"summary": "rename the binding with the path it retargets (closes #1674)"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"name": "generic-starts-with-t",
|
|
64
|
+
"changeType": "fix",
|
|
65
|
+
"issues": [
|
|
66
|
+
1676
|
|
67
|
+
],
|
|
68
|
+
"summary": "exempt module augmentations where the name is upstream-owned (closes #1676)"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"name": "global-const-style",
|
|
72
|
+
"changeType": "fix",
|
|
73
|
+
"issues": [
|
|
74
|
+
1681
|
|
75
|
+
],
|
|
76
|
+
"summary": "exempt function-expression components and unwrap satisfies/non-null wrappers (closes #1681)"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"name": "no-always-true-false-conditions",
|
|
80
|
+
"changeType": "fix",
|
|
81
|
+
"issues": [
|
|
82
|
+
1682
|
|
83
|
+
],
|
|
84
|
+
"summary": "resolve any const object in optional chains and climb assertion wrappers (closes #1682)"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"name": "no-unnecessary-verb-suffix",
|
|
88
|
+
"changeType": "fix",
|
|
89
|
+
"issues": [
|
|
90
|
+
1679
|
|
91
|
+
],
|
|
92
|
+
"summary": "read intersection-alias contracts constituent by constituent (closes #1679)"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"name": "parallelize-loop-awaits",
|
|
96
|
+
"changeType": "fix",
|
|
97
|
+
"issues": [
|
|
98
|
+
1687,
|
|
99
|
+
1688
|
|
100
|
+
],
|
|
101
|
+
"summary": "cover do-while, dedupe nested-loop reports, stop property keys vetoing (closes #1688); exempt test files, condition-coupled loops, and for-await-of (closes #1687)"
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"name": "prefer-getter-over-parameterless-method",
|
|
105
|
+
"changeType": "fix",
|
|
106
|
+
"issues": [
|
|
107
|
+
1684
|
|
108
|
+
],
|
|
109
|
+
"summary": "skip methods bound by a heritage clause (closes #1684)"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"name": "prefer-type-alias-over-typeof-constant",
|
|
113
|
+
"changeType": "fix",
|
|
114
|
+
"issues": [
|
|
115
|
+
1680
|
|
116
|
+
],
|
|
117
|
+
"summary": "exempt only canonical alias derivations, not nested use sites (closes #1680)"
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"name": "require-https-error",
|
|
121
|
+
"changeType": "fix",
|
|
122
|
+
"issues": [
|
|
123
|
+
1685
|
|
124
|
+
],
|
|
125
|
+
"summary": "name the codebase-owned HttpsError module, not a placeholder package (closes #1685)"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"name": "use-custom-link",
|
|
129
|
+
"changeType": "fix",
|
|
130
|
+
"issues": [
|
|
131
|
+
1673
|
|
132
|
+
],
|
|
133
|
+
"summary": "exempt the wrapper's implementation files (closes #1673)"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"name": "use-custom-memo",
|
|
137
|
+
"changeType": "fix",
|
|
138
|
+
"issues": [
|
|
139
|
+
1671
|
|
140
|
+
],
|
|
141
|
+
"summary": "exempt the wrapper module the rule points at (closes #1671)"
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"name": "use-custom-router",
|
|
145
|
+
"changeType": "fix",
|
|
146
|
+
"issues": [
|
|
147
|
+
1672
|
|
148
|
+
],
|
|
149
|
+
"summary": "exempt the wrapper module the rule points at (closes #1672)"
|
|
150
|
+
}
|
|
151
|
+
]
|
|
152
|
+
},
|
|
2
153
|
{
|
|
3
154
|
"version": "1.20.95",
|
|
4
155
|
"date": "2026-08-03T23:44:33.733Z",
|