@blumintinc/eslint-plugin-blumint 1.20.39 → 1.20.41
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/lib/index.js +1 -1
- package/lib/rules/avoid-utils-directory.js +11 -1
- package/lib/rules/enforce-assert-safe-object-key.js +20 -14
- package/lib/rules/enforce-dynamic-imports.d.ts +13 -0
- package/lib/rules/enforce-dynamic-imports.js +20 -0
- package/lib/rules/no-async-foreach.d.ts +1 -1
- package/lib/rules/no-async-foreach.js +4 -2
- package/lib/rules/no-useless-fragment.d.ts +1 -2
- package/lib/rules/no-useless-fragment.js +4 -2
- package/lib/rules/prefer-fragment-shorthand.d.ts +1 -3
- package/lib/rules/prefer-fragment-shorthand.js +4 -2
- package/lib/rules/require-memo.d.ts +1 -1
- package/lib/rules/require-memo.js +4 -2
- package/lib/rules/require-props-composition.js +15 -3
- package/lib/rules/test-file-location-enforcement.js +8 -1
- package/lib/utils/createRule.js +4 -1
- package/package.json +1 -1
- package/release-manifest.json +80 -0
package/lib/index.js
CHANGED
|
@@ -21,6 +21,14 @@ exports.avoidUtilsDirectory = (0, createRule_1.createRule)({
|
|
|
21
21
|
},
|
|
22
22
|
defaultOptions: [],
|
|
23
23
|
create(context) {
|
|
24
|
+
// Anchor the reported path at the directory ESLint was configured with,
|
|
25
|
+
// not the node process cwd. The two differ under the VS Code ESLint
|
|
26
|
+
// extension, in monorepos, and for any programmatic `new ESLint({ cwd })`,
|
|
27
|
+
// where reading the process cwd names the file by a path the reader cannot
|
|
28
|
+
// locate (issue #1475). The `typeof` guard keeps the rule working under
|
|
29
|
+
// harnesses that predate `getCwd`, matching the sibling rules that resolve
|
|
30
|
+
// a cwd.
|
|
31
|
+
const cwd = typeof context.getCwd === 'function' ? context.getCwd() : process.cwd();
|
|
24
32
|
return {
|
|
25
33
|
Program(node) {
|
|
26
34
|
// Normalize Windows backslash separators so the forward-slash `utils/`
|
|
@@ -28,8 +36,10 @@ exports.avoidUtilsDirectory = (0, createRule_1.createRule)({
|
|
|
28
36
|
// returns `C:\repo\src\utils\foo.ts` on Windows, the regex never
|
|
29
37
|
// matches, and the rule silently reports nothing (issue #1270).
|
|
30
38
|
const filename = context.getFilename().replace(/\\/g, '/');
|
|
39
|
+
// `|| filename` covers the case where the file IS the cwd (an empty
|
|
40
|
+
// relative path), keeping a usable path in the message.
|
|
31
41
|
const relativePath = path_1.default.isAbsolute(filename)
|
|
32
|
-
? path_1.default.relative(
|
|
42
|
+
? path_1.default.relative(cwd, filename) || filename
|
|
33
43
|
: filename;
|
|
34
44
|
// Skip files in node_modules
|
|
35
45
|
if (filename.includes('node_modules')) {
|
|
@@ -71,31 +71,37 @@ exports.enforceAssertSafeObjectKey = (0, createRule_1.createRule)({
|
|
|
71
71
|
*/
|
|
72
72
|
const isReportSuppressed = (0, disableDirectives_1.createSuppressionChecker)(context);
|
|
73
73
|
/**
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
74
|
+
* The directory ESLint itself was configured with, which is what
|
|
75
|
+
* `importPath` is anchored at. The node process cwd is only a fallback for
|
|
76
|
+
* harnesses that predate `getCwd`: the two differ under the VS Code ESLint
|
|
77
|
+
* extension, in monorepos, and for any programmatic `new ESLint({ cwd })`,
|
|
78
|
+
* and anchoring at the process cwd there emits an unresolvable specifier.
|
|
79
|
+
*/
|
|
80
|
+
const cwd = typeof context.getCwd === 'function' ? context.getCwd() : process.cwd();
|
|
81
|
+
/**
|
|
82
|
+
* Directory of the file being fixed, relative to the configured cwd, or
|
|
83
|
+
* null for virtual/stdin files (RuleTester default 'file.ts', '<input>',
|
|
84
|
+
* '<text>') whose non-absolute name cannot anchor a relative path.
|
|
77
85
|
*/
|
|
78
86
|
const fileDirFromRoot = () => {
|
|
79
87
|
const rawFilename = context.getFilename().replace(/\\/g, '/');
|
|
80
88
|
if (!path_1.default.isAbsolute(rawFilename)) {
|
|
81
89
|
return null;
|
|
82
90
|
}
|
|
83
|
-
const fileRelToCwd = path_1.default
|
|
84
|
-
.relative(process.cwd(), rawFilename)
|
|
85
|
-
.replace(/\\/g, '/');
|
|
91
|
+
const fileRelToCwd = path_1.default.relative(cwd, rawFilename).replace(/\\/g, '/');
|
|
86
92
|
return path_1.default.posix.dirname(fileRelToCwd);
|
|
87
93
|
};
|
|
88
94
|
/**
|
|
89
95
|
* Computes the module specifier for the injected assertSafe import.
|
|
90
96
|
*
|
|
91
|
-
* `importPath` is anchored at the repo root
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
* functions
|
|
97
|
-
*
|
|
98
|
-
*
|
|
97
|
+
* `importPath` is anchored at the repo root — the directory ESLint runs
|
|
98
|
+
* with, not the node process cwd — matching how avoid-utils-directory and
|
|
99
|
+
* test-file-location-enforcement treat paths. A bare repo-root specifier
|
|
100
|
+
* such as 'functions/src/util/assertSafe' is unresolvable inside the
|
|
101
|
+
* functions/ TS project, whose baseUrl is functions/: it would resolve to
|
|
102
|
+
* functions/functions/src/util/assertSafe, which does not exist. The
|
|
103
|
+
* specifier is therefore derived relative to the file being fixed so the
|
|
104
|
+
* emitted import resolves from that file's location.
|
|
99
105
|
*/
|
|
100
106
|
const computeImportSpecifier = () => {
|
|
101
107
|
const fileDir = fileDirFromRoot();
|
|
@@ -7,6 +7,19 @@ type Options = [
|
|
|
7
7
|
allowImportType?: boolean;
|
|
8
8
|
}
|
|
9
9
|
];
|
|
10
|
+
/**
|
|
11
|
+
* A module this plugin injects on the user's behalf must be one the plugin's
|
|
12
|
+
* own default config accepts. Several rules in the recommended config write a
|
|
13
|
+
* *static* import as part of their autofix; without these entries `--fix`
|
|
14
|
+
* would trade an auto-fixable violation for a non-fixable one, and the
|
|
15
|
+
* suggested remedy is impossible for most of them anyway (hooks must be called
|
|
16
|
+
* unconditionally and decorators must resolve statically, so neither can be
|
|
17
|
+
* loaded dynamically).
|
|
18
|
+
*
|
|
19
|
+
* `src/tests/enforce-dynamic-imports.test.ts` derives the set of specifiers the
|
|
20
|
+
* fixers emit from the rule sources and asserts every external one is listed
|
|
21
|
+
* here, so a seventh injected module cannot slip in unlisted.
|
|
22
|
+
*/
|
|
10
23
|
export declare const DEFAULT_IGNORED_LIBRARIES: string[];
|
|
11
24
|
export declare const DEFAULT_INTERNAL_PREFIXES: string[];
|
|
12
25
|
declare const _default: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"dynamicImportRequired", Options, import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
|
|
@@ -5,6 +5,19 @@ const createRule_1 = require("../utils/createRule");
|
|
|
5
5
|
const minimatch_1 = require("minimatch");
|
|
6
6
|
const module_1 = require("module");
|
|
7
7
|
exports.RULE_NAME = 'enforce-dynamic-imports';
|
|
8
|
+
/**
|
|
9
|
+
* A module this plugin injects on the user's behalf must be one the plugin's
|
|
10
|
+
* own default config accepts. Several rules in the recommended config write a
|
|
11
|
+
* *static* import as part of their autofix; without these entries `--fix`
|
|
12
|
+
* would trade an auto-fixable violation for a non-fixable one, and the
|
|
13
|
+
* suggested remedy is impossible for most of them anyway (hooks must be called
|
|
14
|
+
* unconditionally and decorators must resolve statically, so neither can be
|
|
15
|
+
* loaded dynamically).
|
|
16
|
+
*
|
|
17
|
+
* `src/tests/enforce-dynamic-imports.test.ts` derives the set of specifiers the
|
|
18
|
+
* fixers emit from the rule sources and asserts every external one is listed
|
|
19
|
+
* here, so a seventh injected module cannot slip in unlisted.
|
|
20
|
+
*/
|
|
8
21
|
exports.DEFAULT_IGNORED_LIBRARIES = [
|
|
9
22
|
'react',
|
|
10
23
|
'react/**',
|
|
@@ -19,6 +32,13 @@ exports.DEFAULT_IGNORED_LIBRARIES = [
|
|
|
19
32
|
'@emotion/**',
|
|
20
33
|
'clsx',
|
|
21
34
|
'tailwind-merge',
|
|
35
|
+
// Injected by this plugin's own fixers:
|
|
36
|
+
'use-latest-callback',
|
|
37
|
+
'@blumintinc/typescript-memoize',
|
|
38
|
+
'@blumintinc/use-deep-compare',
|
|
39
|
+
'microdiff',
|
|
40
|
+
'safe-stable-stringify',
|
|
41
|
+
'fast-deep-equal', // fast-deep-equal-over-microdiff
|
|
22
42
|
];
|
|
23
43
|
exports.DEFAULT_INTERNAL_PREFIXES = ['src/', 'functions/'];
|
|
24
44
|
// Pre-built set of Node.js core module names for O(1) lookup.
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { TSESLint } from '@typescript-eslint/utils';
|
|
2
|
-
export declare const noAsyncForEach: TSESLint.RuleModule<
|
|
2
|
+
export declare const noAsyncForEach: TSESLint.RuleModule<"noAsyncForEach", [], TSESLint.RuleListener>;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.noAsyncForEach = void 0;
|
|
4
4
|
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
const createRule_1 = require("../utils/createRule");
|
|
5
6
|
const getNodeStart = (node) => node?.range?.[0] ?? Number.POSITIVE_INFINITY;
|
|
6
7
|
const getFunctionDescription = (node, fallbackName) => {
|
|
7
8
|
const declaredName = (node.type === utils_1.AST_NODE_TYPES.FunctionDeclaration ||
|
|
@@ -200,7 +201,8 @@ const analyzeCallbackAsyncStatus = (callback, scope) => {
|
|
|
200
201
|
const lastWrite = relevantWrites.reduce((latest, current) => !latest || current.start > latest.start ? current : latest, null);
|
|
201
202
|
return lastWrite && lastWrite.isAsync ? lastWrite.info : null;
|
|
202
203
|
};
|
|
203
|
-
exports.noAsyncForEach = {
|
|
204
|
+
exports.noAsyncForEach = (0, createRule_1.createRule)({
|
|
205
|
+
name: 'no-async-foreach',
|
|
204
206
|
create(context) {
|
|
205
207
|
const sourceCode = getSourceCode(context);
|
|
206
208
|
return {
|
|
@@ -236,5 +238,5 @@ exports.noAsyncForEach = {
|
|
|
236
238
|
schema: [],
|
|
237
239
|
},
|
|
238
240
|
defaultOptions: [],
|
|
239
|
-
};
|
|
241
|
+
});
|
|
240
242
|
//# sourceMappingURL=no-async-foreach.js.map
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export declare const noUselessFragment: TSESLint.RuleModule<'noUselessFragment', []>;
|
|
1
|
+
export declare const noUselessFragment: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"noUselessFragment", [], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.noUselessFragment = void 0;
|
|
4
|
+
const createRule_1 = require("../utils/createRule");
|
|
4
5
|
/**
|
|
5
6
|
* Normalizes JSX child node types into short descriptors used inside lint messages.
|
|
6
7
|
* Keeps message phrasing consistent regardless of the specific child node shape.
|
|
@@ -21,7 +22,8 @@ const describeChild = (child) => {
|
|
|
21
22
|
return 'child node';
|
|
22
23
|
}
|
|
23
24
|
};
|
|
24
|
-
exports.noUselessFragment = {
|
|
25
|
+
exports.noUselessFragment = (0, createRule_1.createRule)({
|
|
26
|
+
name: 'no-useless-fragment',
|
|
25
27
|
create(context) {
|
|
26
28
|
return {
|
|
27
29
|
JSXFragment(node) {
|
|
@@ -78,5 +80,5 @@ exports.noUselessFragment = {
|
|
|
78
80
|
fixable: 'code',
|
|
79
81
|
},
|
|
80
82
|
defaultOptions: [],
|
|
81
|
-
};
|
|
83
|
+
});
|
|
82
84
|
//# sourceMappingURL=no-useless-fragment.js.map
|
|
@@ -1,3 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export declare const preferFragmentShorthand: TSESLint.RuleModule<'preferShorthand', [
|
|
3
|
-
]>;
|
|
1
|
+
export declare const preferFragmentShorthand: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"preferShorthand", [], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.preferFragmentShorthand = void 0;
|
|
4
|
-
|
|
4
|
+
const createRule_1 = require("../utils/createRule");
|
|
5
|
+
exports.preferFragmentShorthand = (0, createRule_1.createRule)({
|
|
6
|
+
name: 'prefer-fragment-shorthand',
|
|
5
7
|
create(context) {
|
|
6
8
|
return {
|
|
7
9
|
JSXElement(node) {
|
|
@@ -38,5 +40,5 @@ exports.preferFragmentShorthand = {
|
|
|
38
40
|
fixable: 'code',
|
|
39
41
|
},
|
|
40
42
|
defaultOptions: [],
|
|
41
|
-
};
|
|
43
|
+
});
|
|
42
44
|
//# sourceMappingURL=prefer-fragment-shorthand.js.map
|
|
@@ -3,4 +3,4 @@ export type NodeWithParent = TSESTree.Node & {
|
|
|
3
3
|
parent: NodeWithParent;
|
|
4
4
|
};
|
|
5
5
|
export type ComponentNode = TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression | TSESTree.FunctionDeclaration;
|
|
6
|
-
export declare const requireMemo: TSESLint.RuleModule<
|
|
6
|
+
export declare const requireMemo: TSESLint.RuleModule<"requireMemo", [], TSESLint.RuleListener>;
|
|
@@ -5,6 +5,7 @@ exports.requireMemo = void 0;
|
|
|
5
5
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
6
6
|
const utils_1 = require("@typescript-eslint/utils");
|
|
7
7
|
const ASTHelpers_1 = require("../utils/ASTHelpers");
|
|
8
|
+
const createRule_1 = require("../utils/createRule");
|
|
8
9
|
const isComponentExplicitlyUnmemoized = (componentName) => componentName.toLowerCase().includes('unmemoized');
|
|
9
10
|
// React's universal convention: only PascalCase-initial identifiers are
|
|
10
11
|
// treated as components. camelCase names are render-prop callbacks or plain
|
|
@@ -238,7 +239,8 @@ function calculateImportPath(currentFilePath) {
|
|
|
238
239
|
const depth = parts.length - (srcIndex + 1) - 1;
|
|
239
240
|
return depth > 0 ? '../'.repeat(depth) + 'util/memo' : './util/memo';
|
|
240
241
|
}
|
|
241
|
-
exports.requireMemo = {
|
|
242
|
+
exports.requireMemo = (0, createRule_1.createRule)({
|
|
243
|
+
name: 'require-memo',
|
|
242
244
|
create: (context) => ({
|
|
243
245
|
ArrowFunctionExpression(node) {
|
|
244
246
|
checkFunction(context, node);
|
|
@@ -265,5 +267,5 @@ exports.requireMemo = {
|
|
|
265
267
|
fixable: 'code',
|
|
266
268
|
},
|
|
267
269
|
defaultOptions: [],
|
|
268
|
-
};
|
|
270
|
+
});
|
|
269
271
|
//# sourceMappingURL=require-memo.js.map
|
|
@@ -838,7 +838,7 @@ function isNameDeclaredWithin(root, name) {
|
|
|
838
838
|
* anything the parse cannot decide with certainty) still reports, so the rule
|
|
839
839
|
* cannot be silently disabled by an unresolvable name.
|
|
840
840
|
*/
|
|
841
|
-
function isPropLessImportedComponent(program, localName, filename, componentRoot) {
|
|
841
|
+
function isPropLessImportedComponent(program, localName, filename, componentRoot, cwd) {
|
|
842
842
|
const relativeImport = findRelativeImport(program, localName);
|
|
843
843
|
if (!relativeImport) {
|
|
844
844
|
return false;
|
|
@@ -849,9 +849,16 @@ function isPropLessImportedComponent(program, localName, filename, componentRoot
|
|
|
849
849
|
return false;
|
|
850
850
|
}
|
|
851
851
|
try {
|
|
852
|
+
// A relative filename is anchored at the directory ESLint was configured
|
|
853
|
+
// with, never the node process cwd. The two differ under the VS Code ESLint
|
|
854
|
+
// extension, in monorepos, and for any programmatic `new Linter({ cwd })`,
|
|
855
|
+
// and anchoring at the process cwd there resolves the sibling import
|
|
856
|
+
// against the wrong directory: the child module is not found, the
|
|
857
|
+
// prop-less relaxation silently stops applying, and the parent reports a
|
|
858
|
+
// composition it cannot satisfy (issue #1476).
|
|
852
859
|
const absolute = path_1.default.isAbsolute(filename)
|
|
853
860
|
? filename
|
|
854
|
-
: path_1.default.resolve(
|
|
861
|
+
: path_1.default.resolve(cwd, filename);
|
|
855
862
|
const resolved = resolveRelativeModule(path_1.default.dirname(absolute), relativeImport.source);
|
|
856
863
|
if (!resolved) {
|
|
857
864
|
return false;
|
|
@@ -948,6 +955,11 @@ exports.requirePropsComposition = (0, createRule_1.createRule)({
|
|
|
948
955
|
// `/src/`) so absolute POSIX and Windows paths both resolve (issue #1268).
|
|
949
956
|
// Glob matching needs forward slashes, while resolving a relative import off
|
|
950
957
|
// disk needs the platform-native path — keep both.
|
|
958
|
+
// Sibling modules are resolved from disk relative to the file under lint,
|
|
959
|
+
// so a non-absolute filename needs the directory ESLint itself was
|
|
960
|
+
// configured with. The node process cwd is only a fallback for harnesses
|
|
961
|
+
// that predate `getCwd`.
|
|
962
|
+
const cwd = typeof context.getCwd === 'function' ? context.getCwd() : process.cwd();
|
|
951
963
|
const rawFilename = context.getFilename();
|
|
952
964
|
const filename = rawFilename.replace(/\\/g, '/');
|
|
953
965
|
const matchesTargetPath = targetPaths.some((pattern) => {
|
|
@@ -1089,7 +1101,7 @@ exports.requirePropsComposition = (0, createRule_1.createRule)({
|
|
|
1089
1101
|
// the file reads, and it drops the dep from the *reported* set rather than
|
|
1090
1102
|
// suppressing the whole report — a sibling child that genuinely needs
|
|
1091
1103
|
// composition still fires.
|
|
1092
|
-
const reportableDeps = depComponents.filter((dep) => !isPropLessImportedComponent(prog, dep, rawFilename, funcNode));
|
|
1104
|
+
const reportableDeps = depComponents.filter((dep) => !isPropLessImportedComponent(prog, dep, rawFilename, funcNode, cwd));
|
|
1093
1105
|
if (reportableDeps.length < minDependencyCount) {
|
|
1094
1106
|
return;
|
|
1095
1107
|
}
|
|
@@ -66,6 +66,13 @@ exports.testFileLocationEnforcement = (0, createRule_1.createRule)({
|
|
|
66
66
|
...SUPPORTED_EXTENSIONS,
|
|
67
67
|
...additionalExtensions.filter((extension) => !SUPPORTED_EXTENSIONS.includes(extension)),
|
|
68
68
|
];
|
|
69
|
+
// Anchor the reported path at the directory ESLint was configured with, not
|
|
70
|
+
// the node process cwd. The two differ under the VS Code ESLint extension,
|
|
71
|
+
// in monorepos, and for any programmatic `new ESLint({ cwd })`, where
|
|
72
|
+
// reading the process cwd names the misplaced test by a path the reader
|
|
73
|
+
// cannot locate (issue #1476). The `typeof` guard keeps the rule working
|
|
74
|
+
// under harnesses that predate `getCwd`.
|
|
75
|
+
const cwd = typeof context.getCwd === 'function' ? context.getCwd() : process.cwd();
|
|
69
76
|
return {
|
|
70
77
|
Program(node) {
|
|
71
78
|
const filename = context.getFilename();
|
|
@@ -84,7 +91,7 @@ exports.testFileLocationEnforcement = (0, createRule_1.createRule)({
|
|
|
84
91
|
return;
|
|
85
92
|
}
|
|
86
93
|
const relativePath = path_1.default.isAbsolute(filename)
|
|
87
|
-
? path_1.default.relative(
|
|
94
|
+
? path_1.default.relative(cwd, filename) || filename
|
|
88
95
|
: filename;
|
|
89
96
|
// Naming the shortest prefix alongside the full stem keeps the guidance
|
|
90
97
|
// honest: either subject name satisfies the rule.
|
package/lib/utils/createRule.js
CHANGED
|
@@ -2,5 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createRule = void 0;
|
|
4
4
|
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
-
|
|
5
|
+
// A repo-relative path needs GitHub's `/blob/<branch>/` segment to resolve;
|
|
6
|
+
// without it every rule's `meta.docs.url` 404s, breaking the doc link the IDE
|
|
7
|
+
// renders on hover. Pinned to `main` because that is the released branch.
|
|
8
|
+
exports.createRule = utils_1.ESLintUtils.RuleCreator((name) => `https://github.com/BluMintInc/eslint-custom-rules/blob/main/docs/rules/${name}.md`);
|
|
6
9
|
//# sourceMappingURL=createRule.js.map
|
package/package.json
CHANGED
package/release-manifest.json
CHANGED
|
@@ -1,4 +1,84 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "1.20.41",
|
|
4
|
+
"date": "2026-07-31T01:39:15.741Z",
|
|
5
|
+
"rules": [
|
|
6
|
+
{
|
|
7
|
+
"name": "no-async-foreach",
|
|
8
|
+
"changeType": "fix",
|
|
9
|
+
"issues": [
|
|
10
|
+
1480
|
|
11
|
+
],
|
|
12
|
+
"summary": "build via createRule so it ships a docs URL (closes #1480)"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"name": "no-useless-fragment",
|
|
16
|
+
"changeType": "fix",
|
|
17
|
+
"issues": [
|
|
18
|
+
1481
|
|
19
|
+
],
|
|
20
|
+
"summary": "build via createRule so it ships a docs URL (closes #1481)"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"name": "prefer-fragment-shorthand",
|
|
24
|
+
"changeType": "fix",
|
|
25
|
+
"issues": [
|
|
26
|
+
1482
|
|
27
|
+
],
|
|
28
|
+
"summary": "build via createRule so it ships a docs URL (closes #1482)"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"name": "require-memo",
|
|
32
|
+
"changeType": "fix",
|
|
33
|
+
"issues": [
|
|
34
|
+
1483
|
|
35
|
+
],
|
|
36
|
+
"summary": "build via createRule so it ships a docs URL (closes #1483)"
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"version": "1.20.40",
|
|
42
|
+
"date": "2026-07-30T23:29:30.176Z",
|
|
43
|
+
"rules": [
|
|
44
|
+
{
|
|
45
|
+
"name": "avoid-utils-directory",
|
|
46
|
+
"changeType": "fix",
|
|
47
|
+
"issues": [
|
|
48
|
+
1475
|
|
49
|
+
],
|
|
50
|
+
"summary": "report the path relative to ESLint's cwd (closes #1475)"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"name": "enforce-assert-safe-object-key",
|
|
54
|
+
"changeType": "fix",
|
|
55
|
+
"issues": [
|
|
56
|
+
1473
|
|
57
|
+
],
|
|
58
|
+
"summary": "anchor the injected import at ESLint's cwd (closes #1473)"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"name": "enforce-dynamic-imports",
|
|
62
|
+
"changeType": "fix",
|
|
63
|
+
"issues": [
|
|
64
|
+
1474
|
|
65
|
+
],
|
|
66
|
+
"summary": "accept the helper modules this plugin's own fixers inject (closes #1474)"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"name": "require-props-composition",
|
|
70
|
+
"changeType": "fix",
|
|
71
|
+
"issues": [],
|
|
72
|
+
"summary": "resolve sibling components from ESLint's cwd"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"name": "test-file-location-enforcement",
|
|
76
|
+
"changeType": "fix",
|
|
77
|
+
"issues": [],
|
|
78
|
+
"summary": "name the file relative to ESLint's cwd"
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
},
|
|
2
82
|
{
|
|
3
83
|
"version": "1.20.39",
|
|
4
84
|
"date": "2026-07-30T21:18:09.189Z",
|