@blumintinc/eslint-plugin-blumint 1.20.197 → 1.20.199
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/array-methods-this-context.js +1 -1
- package/lib/rules/consistent-callback-naming.js +1 -1
- package/lib/rules/enforce-assert-safe-object-key.js +10 -8
- package/lib/rules/enforce-callback-memo.js +1 -1
- package/lib/rules/enforce-centralized-mock-firestore.js +1 -1
- package/lib/rules/enforce-date-ttime.js +1 -2
- package/lib/rules/enforce-early-destructuring.js +2 -4
- package/lib/rules/enforce-empty-object-check.js +92 -14
- package/lib/rules/enforce-exported-function-types.js +5 -3
- package/lib/rules/enforce-f-extension-for-entry-points.js +1 -1
- package/lib/rules/enforce-firestore-doc-ref-generic.js +4 -2
- package/lib/rules/enforce-firestore-facade.js +1 -1
- package/lib/rules/enforce-firestore-set-merge.js +1 -1
- package/lib/rules/enforce-global-constants.js +1 -1
- package/lib/rules/enforce-memoize-async.js +3 -3
- package/lib/rules/enforce-microdiff.js +1 -1
- package/lib/rules/enforce-object-literal-as-const.js +1 -1
- package/lib/rules/enforce-props-argument-name.js +1 -1
- package/lib/rules/enforce-safe-stringify.js +3 -2
- package/lib/rules/enforce-stable-hash-spread-props.js +1 -2
- package/lib/rules/enforce-typescript-markdown-code-blocks.js +1 -1
- package/lib/rules/enforce-verb-noun-naming.js +10 -4
- package/lib/rules/ensure-pointer-events-none.js +1 -1
- package/lib/rules/fast-deep-equal-over-microdiff.js +1 -1
- package/lib/rules/global-const-style.js +1 -1
- package/lib/rules/key-only-outermost-element.js +1 -1
- package/lib/rules/logical-top-to-bottom-grouping.js +1 -3
- package/lib/rules/memo-nested-react-components.js +1 -1
- package/lib/rules/no-async-foreach.js +2 -12
- package/lib/rules/no-curly-brackets-around-commented-properties.js +1 -1
- package/lib/rules/no-entire-object-hook-deps.js +55 -13
- package/lib/rules/no-firestore-object-arrays.js +1 -1
- package/lib/rules/no-inline-component-prop.js +1 -1
- package/lib/rules/no-jsx-whitespace-literal.js +1 -2
- package/lib/rules/no-margin-properties.js +1 -1
- package/lib/rules/no-object-values-on-strings.js +1 -1
- package/lib/rules/no-passthrough-getters.js +1 -1
- package/lib/rules/no-redundant-annotation-assertion.js +1 -2
- package/lib/rules/no-redundant-usecallback-wrapper.js +1 -1
- package/lib/rules/no-stablehash-react-nodes.js +1 -2
- package/lib/rules/no-stale-state-across-await.js +1 -1
- package/lib/rules/no-unnecessary-verb-suffix.js +3 -3
- package/lib/rules/no-unused-usestate.js +1 -1
- package/lib/rules/no-useless-fragment.js +1 -1
- package/lib/rules/no-useless-usememo-primitives.js +1 -1
- package/lib/rules/no-uuidv4-base62-as-key.js +1 -1
- package/lib/rules/optimize-object-boolean-conditions.js +1 -1
- package/lib/rules/parallelize-async-operations.js +1 -1
- package/lib/rules/prefer-block-comments-for-declarations.js +1 -1
- package/lib/rules/prefer-clone-deep.js +1 -1
- package/lib/rules/prefer-fragment-component.js +1 -1
- package/lib/rules/prefer-global-router-state-key.js +1 -1
- package/lib/rules/prefer-next-dynamic.js +1 -1
- package/lib/rules/prefer-params-over-parent-id.js +1 -1
- package/lib/rules/prefer-settings-object.js +1 -1
- package/lib/rules/prefer-type-over-interface.js +1 -1
- package/lib/rules/prefer-url-tostring-over-tojson.js +1 -1
- package/lib/rules/prefer-use-deep-compare-memo.js +27 -6
- package/lib/rules/prefer-usecallback-over-usememo-for-functions.js +1 -1
- package/lib/rules/prefer-utility-function-over-private-static.js +1 -1
- package/lib/rules/prevent-children-clobber.js +1 -2
- package/lib/rules/react-usememo-should-be-component.js +2 -2
- package/lib/rules/require-hooks-default-params.js +1 -1
- package/lib/rules/require-https-error-cause.js +1 -1
- package/lib/rules/require-memo.js +4 -4
- package/lib/rules/require-migration-script-metadata.js +1 -1
- package/lib/rules/use-latest-callback.js +1 -1
- package/lib/rules/warn-https-error-message-user-friendly.js +1 -1
- package/lib/utils/ASTHelpers.d.ts +5 -2
- package/lib/utils/ASTHelpers.js +7 -4
- package/lib/utils/composedFixConfig.d.ts +31 -0
- package/lib/utils/composedFixConfig.js +33 -1
- package/lib/utils/disableDirectives.js +1 -1
- package/lib/utils/syntheticRuleOptions.d.ts +124 -0
- package/lib/utils/syntheticRuleOptions.js +287 -0
- package/package.json +1 -1
- package/release-manifest.json +36 -0
package/lib/index.js
CHANGED
|
@@ -12,7 +12,7 @@ exports.ARRAY_METHODS = [
|
|
|
12
12
|
];
|
|
13
13
|
exports.arrayMethodsThisContext = (0, createRule_1.createRule)({
|
|
14
14
|
create(context) {
|
|
15
|
-
const sourceCode = context.
|
|
15
|
+
const sourceCode = context.getSourceCode();
|
|
16
16
|
return {
|
|
17
17
|
CallExpression(node) {
|
|
18
18
|
// Array method called with a class method reference
|
|
@@ -883,7 +883,7 @@ module.exports = (0, createRule_1.createRule)({
|
|
|
883
883
|
}
|
|
884
884
|
}
|
|
885
885
|
// Get references from global scope
|
|
886
|
-
const sourceCode = context.
|
|
886
|
+
const sourceCode = context.getSourceCode();
|
|
887
887
|
if (sourceCode.scopeManager?.globalScope) {
|
|
888
888
|
const globalVar = sourceCode.scopeManager.globalScope.variables.find((v) => v.name === functionName);
|
|
889
889
|
if (globalVar) {
|
|
@@ -994,7 +994,8 @@ exports.enforceAssertSafeObjectKey = (0, createRule_1.createRule)({
|
|
|
994
994
|
*/
|
|
995
995
|
const addAssertSafeImport = (fixer) => {
|
|
996
996
|
const importStatement = `import { assertSafe } from '${computeImportSpecifier()}';\n`;
|
|
997
|
-
|
|
997
|
+
const sourceCode = context.getSourceCode();
|
|
998
|
+
return (0, importInsertion_1.insertAtImportAnchor)(sourceCode, fixer, (0, importInsertion_1.importInsertionAnchor)(sourceCode), importStatement);
|
|
998
999
|
};
|
|
999
1000
|
/**
|
|
1000
1001
|
* The wrap of the key, emitted over the whole access the key belongs to
|
|
@@ -1022,7 +1023,7 @@ exports.enforceAssertSafeObjectKey = (0, createRule_1.createRule)({
|
|
|
1022
1023
|
* grouping parentheses `dropsGroupingParens` settles.
|
|
1023
1024
|
*/
|
|
1024
1025
|
const planWrap = (node, argText) => {
|
|
1025
|
-
const
|
|
1026
|
+
const sourceCode = context.getSourceCode();
|
|
1026
1027
|
const replacement = `${ASSERT_SAFE_NAME}(${argText})`;
|
|
1027
1028
|
const parens = groupingParensAround(sourceCode, node);
|
|
1028
1029
|
const outermost = parens[parens.length - 1];
|
|
@@ -1068,7 +1069,7 @@ exports.enforceAssertSafeObjectKey = (0, createRule_1.createRule)({
|
|
|
1068
1069
|
* meaning.
|
|
1069
1070
|
*/
|
|
1070
1071
|
const planArrowBreak = (node, wrap) => {
|
|
1071
|
-
const
|
|
1072
|
+
const sourceCode = context.getSourceCode();
|
|
1072
1073
|
const { line } = node.loc.start;
|
|
1073
1074
|
const original = sourceCode.lines[line - 1] ?? '';
|
|
1074
1075
|
const delta = wrap.text.length - (wrap.range[1] - wrap.range[0]);
|
|
@@ -1140,7 +1141,7 @@ exports.enforceAssertSafeObjectKey = (0, createRule_1.createRule)({
|
|
|
1140
1141
|
* which is what shipped before the width was measured at all.
|
|
1141
1142
|
*/
|
|
1142
1143
|
const planMemberBreak = (node, wrap, argText) => {
|
|
1143
|
-
const
|
|
1144
|
+
const sourceCode = context.getSourceCode();
|
|
1144
1145
|
const { text } = sourceCode;
|
|
1145
1146
|
const { line } = node.loc.start;
|
|
1146
1147
|
const original = sourceCode.lines[line - 1] ?? '';
|
|
@@ -1231,7 +1232,7 @@ exports.enforceAssertSafeObjectKey = (0, createRule_1.createRule)({
|
|
|
1231
1232
|
*/
|
|
1232
1233
|
const createFixes = (fixer, node, argText) => {
|
|
1233
1234
|
const fixes = [];
|
|
1234
|
-
const carriesImport = !importClaimed && !importsAssertSafe(context.
|
|
1235
|
+
const carriesImport = !importClaimed && !importsAssertSafe(context.getSourceCode().ast);
|
|
1235
1236
|
if (carriesImport) {
|
|
1236
1237
|
fixes.push(addAssertSafeImport(fixer));
|
|
1237
1238
|
importClaimed = true;
|
|
@@ -1313,7 +1314,7 @@ exports.enforceAssertSafeObjectKey = (0, createRule_1.createRule)({
|
|
|
1313
1314
|
* substitution behave like every other template: `` `${a}${b}` `` has
|
|
1314
1315
|
* always been wrapped whole.
|
|
1315
1316
|
*/
|
|
1316
|
-
const reportWrittenKey = (written) => reportUseAssertSafe(written, context.
|
|
1317
|
+
const reportWrittenKey = (written) => reportUseAssertSafe(written, context.getSourceCode().getText(written));
|
|
1317
1318
|
/**
|
|
1318
1319
|
* Returns true when the identifier was initialized directly from an
|
|
1319
1320
|
* assertSafe(...) call, e.g. `const safeKey = assertSafe(rawKey)`, with any
|
|
@@ -1521,12 +1522,13 @@ exports.enforceAssertSafeObjectKey = (0, createRule_1.createRule)({
|
|
|
1521
1522
|
*/
|
|
1522
1523
|
const recordKeyCovers = (keyAnnotation, recordKeyType, anchor) => {
|
|
1523
1524
|
const namesNoPrototypeField = (domain) => ![...domain].some((value) => PROTOTYPE_SURFACE_NAMES.has(value));
|
|
1525
|
+
const sourceCode = context.getSourceCode();
|
|
1524
1526
|
if (keyAnnotation.type === utils_1.AST_NODE_TYPES.TSTypeReference &&
|
|
1525
1527
|
recordKeyType.type === utils_1.AST_NODE_TYPES.TSTypeReference &&
|
|
1526
1528
|
!keyAnnotation.typeParameters &&
|
|
1527
1529
|
!recordKeyType.typeParameters &&
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
+
sourceCode.getText(keyAnnotation.typeName) ===
|
|
1531
|
+
sourceCode.getText(recordKeyType.typeName)) {
|
|
1530
1532
|
const domain = keyDomainOf(keyAnnotation, anchor, new Set());
|
|
1531
1533
|
if (domain === 'open') {
|
|
1532
1534
|
return false;
|
|
@@ -118,7 +118,7 @@ exports.default = (0, createRule_1.createRule)({
|
|
|
118
118
|
return [];
|
|
119
119
|
}
|
|
120
120
|
function referencesParentScopeVariables(functionNode, parentParams) {
|
|
121
|
-
const scopeManager = context.
|
|
121
|
+
const scopeManager = context.getSourceCode().scopeManager;
|
|
122
122
|
if (!scopeManager)
|
|
123
123
|
return false;
|
|
124
124
|
const scope = scopeManager.acquire(functionNode);
|
|
@@ -359,7 +359,7 @@ exports.enforceCentralizedMockFirestore = (0, createRule_1.createRule)({
|
|
|
359
359
|
},
|
|
360
360
|
'Program:exit'() {
|
|
361
361
|
if (mockFirestoreNodes.size > 0) {
|
|
362
|
-
const sourceCode = context.
|
|
362
|
+
const sourceCode = context.getSourceCode();
|
|
363
363
|
// Report only once for the entire file
|
|
364
364
|
context.report({
|
|
365
365
|
node: Array.from(mockFirestoreNodes)[0],
|
|
@@ -45,8 +45,7 @@ exports.enforceDateTTime = (0, createRule_1.createRule)({
|
|
|
45
45
|
},
|
|
46
46
|
defaultOptions: [],
|
|
47
47
|
create(context) {
|
|
48
|
-
const sourceCode = context
|
|
49
|
-
.sourceCode ?? context.getSourceCode();
|
|
48
|
+
const sourceCode = context.getSourceCode();
|
|
50
49
|
const parserServices = sourceCode?.parserServices ?? context.parserServices;
|
|
51
50
|
const checker = parserServices?.program?.getTypeChecker();
|
|
52
51
|
if (!parserServices || !checker) {
|
|
@@ -1207,8 +1207,7 @@ function validateHookForTransform(node, context) {
|
|
|
1207
1207
|
: null;
|
|
1208
1208
|
if (!depsArray)
|
|
1209
1209
|
return null;
|
|
1210
|
-
const sourceCode = context.
|
|
1211
|
-
context.getSourceCode();
|
|
1210
|
+
const sourceCode = context.getSourceCode();
|
|
1212
1211
|
const depTexts = dependencyElements(depsArray, sourceCode);
|
|
1213
1212
|
const depTextSet = new Set(depTexts);
|
|
1214
1213
|
const scope = context.getScope();
|
|
@@ -1239,8 +1238,7 @@ exports.enforceEarlyDestructuring = (0, createRule_1.createRule)({
|
|
|
1239
1238
|
},
|
|
1240
1239
|
defaultOptions: [],
|
|
1241
1240
|
create(context) {
|
|
1242
|
-
const sourceCode = context.
|
|
1243
|
-
context.getSourceCode();
|
|
1241
|
+
const sourceCode = context.getSourceCode();
|
|
1244
1242
|
const visitorKeys = sourceCode
|
|
1245
1243
|
.visitorKeys ??
|
|
1246
1244
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -27,6 +27,7 @@ exports.enforceEmptyObjectCheck = void 0;
|
|
|
27
27
|
const utils_1 = require("@typescript-eslint/utils");
|
|
28
28
|
const ts = __importStar(require("typescript"));
|
|
29
29
|
const createRule_1 = require("../utils/createRule");
|
|
30
|
+
const ASTHelpers_1 = require("../utils/ASTHelpers");
|
|
30
31
|
const DEFAULT_OBJECT_SUFFIXES = [
|
|
31
32
|
'Config',
|
|
32
33
|
'Configs',
|
|
@@ -776,8 +777,8 @@ function readSegmentGap(text, paren) {
|
|
|
776
777
|
* on. Splitting the span at the operator token keeps whatever the author wrote
|
|
777
778
|
* around each operand.
|
|
778
779
|
*/
|
|
779
|
-
function buildDoc(node, segmentStart, segmentEnd,
|
|
780
|
-
const { source } =
|
|
780
|
+
function buildDoc(node, segmentStart, segmentEnd, docContext) {
|
|
781
|
+
const { source } = docContext;
|
|
781
782
|
const before = readSegmentGap(source.slice(segmentStart, node.range[0]), '(');
|
|
782
783
|
const after = readSegmentGap(source.slice(node.range[1], segmentEnd), ')');
|
|
783
784
|
if (!before || !after) {
|
|
@@ -793,7 +794,7 @@ function buildDoc(node, segmentStart, segmentEnd, context) {
|
|
|
793
794
|
* the segment carried have just been accounted for, and handing them down
|
|
794
795
|
* again makes the first child look unbalanced and rejects the whole tree.
|
|
795
796
|
*/
|
|
796
|
-
const core = buildCoreDoc(node,
|
|
797
|
+
const core = buildCoreDoc(node, docContext);
|
|
797
798
|
if (!core) {
|
|
798
799
|
return null;
|
|
799
800
|
}
|
|
@@ -810,11 +811,11 @@ function buildDoc(node, segmentStart, segmentEnd, context) {
|
|
|
810
811
|
}
|
|
811
812
|
return doc;
|
|
812
813
|
}
|
|
813
|
-
function buildCoreDoc(node,
|
|
814
|
-
const { sourceCode, source, targetRange } =
|
|
814
|
+
function buildCoreDoc(node, docContext) {
|
|
815
|
+
const { sourceCode, source, targetRange } = docContext;
|
|
815
816
|
const [segmentStart, segmentEnd] = node.range;
|
|
816
817
|
if (node.range[0] === targetRange[0] && node.range[1] === targetRange[1]) {
|
|
817
|
-
return
|
|
818
|
+
return docContext.targetDoc;
|
|
818
819
|
}
|
|
819
820
|
if (node.type === utils_1.AST_NODE_TYPES.LogicalExpression) {
|
|
820
821
|
const operatorToken = sourceCode.getTokenAfter(node.left, {
|
|
@@ -824,8 +825,8 @@ function buildCoreDoc(node, context) {
|
|
|
824
825
|
if (!operatorToken) {
|
|
825
826
|
return null;
|
|
826
827
|
}
|
|
827
|
-
const left = buildDoc(node.left, segmentStart, operatorToken.range[0],
|
|
828
|
-
const right = buildDoc(node.right, operatorToken.range[1], segmentEnd,
|
|
828
|
+
const left = buildDoc(node.left, segmentStart, operatorToken.range[0], docContext);
|
|
829
|
+
const right = buildDoc(node.right, operatorToken.range[1], segmentEnd, docContext);
|
|
829
830
|
if (!left || !right) {
|
|
830
831
|
return null;
|
|
831
832
|
}
|
|
@@ -841,9 +842,9 @@ function buildCoreDoc(node, context) {
|
|
|
841
842
|
if (!questionToken || !colonToken) {
|
|
842
843
|
return null;
|
|
843
844
|
}
|
|
844
|
-
const test = buildDoc(node.test, segmentStart, questionToken.range[0],
|
|
845
|
-
const consequent = buildDoc(node.consequent, questionToken.range[1], colonToken.range[0],
|
|
846
|
-
const alternate = buildDoc(node.alternate, colonToken.range[1], segmentEnd,
|
|
845
|
+
const test = buildDoc(node.test, segmentStart, questionToken.range[0], docContext);
|
|
846
|
+
const consequent = buildDoc(node.consequent, questionToken.range[1], colonToken.range[0], docContext);
|
|
847
|
+
const alternate = buildDoc(node.alternate, colonToken.range[1], segmentEnd, docContext);
|
|
847
848
|
if (!test || !consequent || !alternate) {
|
|
848
849
|
return null;
|
|
849
850
|
}
|
|
@@ -949,13 +950,13 @@ function planWidenedFix(input) {
|
|
|
949
950
|
{ kind: 'leaf', text: `Object.keys(${identifierText}).length === 0` },
|
|
950
951
|
],
|
|
951
952
|
};
|
|
952
|
-
const
|
|
953
|
+
const docContext = {
|
|
953
954
|
sourceCode,
|
|
954
955
|
source,
|
|
955
956
|
targetRange: target.range,
|
|
956
957
|
targetDoc: needsParentheses ? { kind: 'group', inner: guard } : guard,
|
|
957
958
|
};
|
|
958
|
-
const doc = buildDoc(root, root.range[0], root.range[1],
|
|
959
|
+
const doc = buildDoc(root, root.range[0], root.range[1], docContext);
|
|
959
960
|
if (!doc) {
|
|
960
961
|
return null;
|
|
961
962
|
}
|
|
@@ -974,7 +975,7 @@ function planWidenedFix(input) {
|
|
|
974
975
|
const spliced = source.slice(root.range[0], target.range[0]) +
|
|
975
976
|
(needsParentheses
|
|
976
977
|
? `(${flattenDoc(guard)})`
|
|
977
|
-
: flattenDoc(
|
|
978
|
+
: flattenDoc(docContext.targetDoc)) +
|
|
978
979
|
source.slice(target.range[1], root.range[1]);
|
|
979
980
|
const flat = flattenDoc(doc);
|
|
980
981
|
if (flat.includes('\n') ||
|
|
@@ -1341,6 +1342,68 @@ exports.enforceEmptyObjectCheck = (0, createRule_1.createRule)({
|
|
|
1341
1342
|
]);
|
|
1342
1343
|
const processedExpressions = new WeakSet();
|
|
1343
1344
|
const processedNegations = new WeakSet();
|
|
1345
|
+
/** The binding a value expression ultimately reads from. */
|
|
1346
|
+
function rootIdentifierOf(node) {
|
|
1347
|
+
switch (node.type) {
|
|
1348
|
+
case utils_1.AST_NODE_TYPES.Identifier:
|
|
1349
|
+
return node;
|
|
1350
|
+
case utils_1.AST_NODE_TYPES.CallExpression:
|
|
1351
|
+
case utils_1.AST_NODE_TYPES.NewExpression:
|
|
1352
|
+
return rootIdentifierOf(node.callee);
|
|
1353
|
+
case utils_1.AST_NODE_TYPES.MemberExpression:
|
|
1354
|
+
return rootIdentifierOf(node.object);
|
|
1355
|
+
case utils_1.AST_NODE_TYPES.AwaitExpression:
|
|
1356
|
+
return rootIdentifierOf(node.argument);
|
|
1357
|
+
case utils_1.AST_NODE_TYPES.ChainExpression:
|
|
1358
|
+
return rootIdentifierOf(node.expression);
|
|
1359
|
+
case utils_1.AST_NODE_TYPES.TSNonNullExpression:
|
|
1360
|
+
case utils_1.AST_NODE_TYPES.TSAsExpression:
|
|
1361
|
+
return rootIdentifierOf(node.expression);
|
|
1362
|
+
default:
|
|
1363
|
+
return null;
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
function variableFor(identifier) {
|
|
1367
|
+
let scope = ASTHelpers_1.ASTHelpers.getScope(context, identifier);
|
|
1368
|
+
while (scope) {
|
|
1369
|
+
const found = scope.variables.find((candidate) => candidate.name === identifier.name);
|
|
1370
|
+
if (found) {
|
|
1371
|
+
return found;
|
|
1372
|
+
}
|
|
1373
|
+
scope = scope.upper;
|
|
1374
|
+
}
|
|
1375
|
+
return null;
|
|
1376
|
+
}
|
|
1377
|
+
/**
|
|
1378
|
+
* Whether this value originates in an IMPORTED binding.
|
|
1379
|
+
*
|
|
1380
|
+
* Consulted ONLY once the checker has returned `unknown`, which is what
|
|
1381
|
+
* makes it safe: in a file whose imports resolve, an imported callee
|
|
1382
|
+
* yields a real type and this is never reached. Reaching it means the
|
|
1383
|
+
* symbol came back `any` because the module did not resolve — a
|
|
1384
|
+
* program-completeness failure rather than evidence the value can be
|
|
1385
|
+
* `{}` (#2252).
|
|
1386
|
+
*/
|
|
1387
|
+
function tracesToImport(identifier, seen = new Set()) {
|
|
1388
|
+
const variable = variableFor(identifier);
|
|
1389
|
+
if (!variable || seen.has(variable)) {
|
|
1390
|
+
return false;
|
|
1391
|
+
}
|
|
1392
|
+
seen.add(variable);
|
|
1393
|
+
for (const def of variable.defs) {
|
|
1394
|
+
if (def.type === 'ImportBinding') {
|
|
1395
|
+
return true;
|
|
1396
|
+
}
|
|
1397
|
+
if (def.node.type === utils_1.AST_NODE_TYPES.VariableDeclarator &&
|
|
1398
|
+
def.node.init) {
|
|
1399
|
+
const root = rootIdentifierOf(def.node.init);
|
|
1400
|
+
if (root && tracesToImport(root, seen)) {
|
|
1401
|
+
return true;
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
return false;
|
|
1406
|
+
}
|
|
1344
1407
|
function isLikelyObject(identifier) {
|
|
1345
1408
|
if (checker && parserServices?.esTreeNodeToTSNodeMap) {
|
|
1346
1409
|
try {
|
|
@@ -1353,6 +1416,21 @@ exports.enforceEmptyObjectCheck = (0, createRule_1.createRule)({
|
|
|
1353
1416
|
if (analysis === 'non-object') {
|
|
1354
1417
|
return false;
|
|
1355
1418
|
}
|
|
1419
|
+
/**
|
|
1420
|
+
* The checker looked and could not tell. Falling straight through
|
|
1421
|
+
* to the naming heuristic is what made a file EXCLUDED from the
|
|
1422
|
+
* `parserOptions.project` program report on byte-identical code its
|
|
1423
|
+
* in-program twin is exempt from: the suffix says `config`, so
|
|
1424
|
+
* absence of evidence became evidence the value can be `{}`.
|
|
1425
|
+
*
|
|
1426
|
+
* The heuristic is still the right answer for a value with no
|
|
1427
|
+
* declaration to resolve — removing it outright silences 52 of this
|
|
1428
|
+
* rule's own 92 fixtures — so only the unresolved-IMPORT case is
|
|
1429
|
+
* carved out (#2252).
|
|
1430
|
+
*/
|
|
1431
|
+
if (tracesToImport(identifier)) {
|
|
1432
|
+
return false;
|
|
1433
|
+
}
|
|
1356
1434
|
}
|
|
1357
1435
|
catch {
|
|
1358
1436
|
// TypeScript parser services can throw when AST-to-TS node mapping fails; fall back to naming heuristic so linting does not crash.
|
|
@@ -484,7 +484,9 @@ exports.enforceExportedFunctionTypes = (0, createRule_1.createRule)({
|
|
|
484
484
|
* error.
|
|
485
485
|
*/
|
|
486
486
|
function findExportableTypeDeclaration(typeName) {
|
|
487
|
-
const declarations = context
|
|
487
|
+
const declarations = context
|
|
488
|
+
.getSourceCode()
|
|
489
|
+
.ast.body.filter((statement) => (statement.type === utils_1.AST_NODE_TYPES.TSTypeAliasDeclaration ||
|
|
488
490
|
statement.type === utils_1.AST_NODE_TYPES.TSInterfaceDeclaration) &&
|
|
489
491
|
statement.id.name === typeName);
|
|
490
492
|
return declarations.length === 1 ? declarations[0] : undefined;
|
|
@@ -573,7 +575,7 @@ exports.enforceExportedFunctionTypes = (0, createRule_1.createRule)({
|
|
|
573
575
|
* so an unresolved name leaves the component unchecked rather than guessing.
|
|
574
576
|
*/
|
|
575
577
|
function findModuleScopeDeclaration(name) {
|
|
576
|
-
for (const statement of context.
|
|
578
|
+
for (const statement of context.getSourceCode().ast.body) {
|
|
577
579
|
const declaration = statement.type === utils_1.AST_NODE_TYPES.ExportNamedDeclaration &&
|
|
578
580
|
statement.declaration
|
|
579
581
|
? statement.declaration
|
|
@@ -602,7 +604,7 @@ exports.enforceExportedFunctionTypes = (0, createRule_1.createRule)({
|
|
|
602
604
|
if (isBuiltInType(typeName)) {
|
|
603
605
|
return true;
|
|
604
606
|
}
|
|
605
|
-
const sourceCode = context.
|
|
607
|
+
const sourceCode = context.getSourceCode();
|
|
606
608
|
const program = sourceCode.ast;
|
|
607
609
|
// Check for imported types first - if found, return true immediately
|
|
608
610
|
// since imported types are already available to consumers
|
|
@@ -81,7 +81,7 @@ function isNodeDefiningEntryPoint(node, entryPoints) {
|
|
|
81
81
|
* for the target node.
|
|
82
82
|
*/
|
|
83
83
|
function getScopeForNode(context, node) {
|
|
84
|
-
const sourceCode = context.
|
|
84
|
+
const sourceCode = context.getSourceCode();
|
|
85
85
|
if (isEslint9OrLater(sourceCode)) {
|
|
86
86
|
return getEslint9Scope(sourceCode, node);
|
|
87
87
|
}
|
|
@@ -994,7 +994,9 @@ exports.enforceFirestoreDocRefGeneric = (0, createRule_1.createRule)({
|
|
|
994
994
|
if (fileImportsProjectModule !== undefined) {
|
|
995
995
|
return fileImportsProjectModule;
|
|
996
996
|
}
|
|
997
|
-
const found = context
|
|
997
|
+
const found = context
|
|
998
|
+
.getSourceCode()
|
|
999
|
+
.ast.body.some((statement) => statement.type === utils_1.AST_NODE_TYPES.ImportDeclaration &&
|
|
998
1000
|
isProjectModuleSpecifier(statement.source.value));
|
|
999
1001
|
fileImportsProjectModule = found;
|
|
1000
1002
|
return found;
|
|
@@ -1011,7 +1013,7 @@ exports.enforceFirestoreDocRefGeneric = (0, createRule_1.createRule)({
|
|
|
1011
1013
|
return rulesUnitTestingLocals;
|
|
1012
1014
|
}
|
|
1013
1015
|
const locals = new Set();
|
|
1014
|
-
for (const statement of context.
|
|
1016
|
+
for (const statement of context.getSourceCode().ast.body) {
|
|
1015
1017
|
if (statement.type === utils_1.AST_NODE_TYPES.ImportDeclaration &&
|
|
1016
1018
|
statement.source.value === RULES_UNIT_TESTING_MODULE) {
|
|
1017
1019
|
for (const specifier of statement.specifiers) {
|
|
@@ -159,7 +159,7 @@ exports.enforceFirestoreFacade = (0, createRule_1.createRule)({
|
|
|
159
159
|
const nonClientImportedLocals = new Set();
|
|
160
160
|
// Batches/transactions proven to originate from the client SDK.
|
|
161
161
|
const clientFirestoreVariables = new Set();
|
|
162
|
-
const sourceCode = context.
|
|
162
|
+
const sourceCode = context.getSourceCode();
|
|
163
163
|
const clearFirestoreTrackingFor = (name) => {
|
|
164
164
|
firestoreDocRefVariables.delete(name);
|
|
165
165
|
firestoreCollectionVariables.delete(name);
|
|
@@ -336,7 +336,7 @@ exports.enforceFirestoreSetMerge = (0, createRule_1.createRule)({
|
|
|
336
336
|
},
|
|
337
337
|
defaultOptions: [],
|
|
338
338
|
create(context) {
|
|
339
|
-
const sourceCode = context.
|
|
339
|
+
const sourceCode = context.getSourceCode();
|
|
340
340
|
const updateAliases = new Set();
|
|
341
341
|
/**
|
|
342
342
|
* The `setDoc` binding rides on one violation's fix, which makes that
|
|
@@ -211,7 +211,7 @@ exports.enforceGlobalConstants = (0, createRule_1.createRule)({
|
|
|
211
211
|
},
|
|
212
212
|
defaultOptions: [{}],
|
|
213
213
|
create(context, [options]) {
|
|
214
|
-
const sourceCode = context.
|
|
214
|
+
const sourceCode = context.getSourceCode();
|
|
215
215
|
const printWidth = typeof options.printWidth === 'number' && options.printWidth > 0
|
|
216
216
|
? options.printWidth
|
|
217
217
|
: DEFAULT_PRINT_WIDTH;
|
|
@@ -503,7 +503,7 @@ exports.enforceMemoizeAsync = (0, createRule_1.createRule)({
|
|
|
503
503
|
const readMemoizeImports = () => {
|
|
504
504
|
const aliases = new Map();
|
|
505
505
|
const namespaces = new Map();
|
|
506
|
-
for (const statement of context.
|
|
506
|
+
for (const statement of context.getSourceCode().ast.body) {
|
|
507
507
|
if (statement.type !== utils_1.AST_NODE_TYPES.ImportDeclaration) {
|
|
508
508
|
continue;
|
|
509
509
|
}
|
|
@@ -542,7 +542,7 @@ exports.enforceMemoizeAsync = (0, createRule_1.createRule)({
|
|
|
542
542
|
const transactionAliases = () => {
|
|
543
543
|
if (!transactionAliasCache) {
|
|
544
544
|
transactionAliasCache = new Set();
|
|
545
|
-
for (const statement of context.
|
|
545
|
+
for (const statement of context.getSourceCode().ast.body) {
|
|
546
546
|
if (statement.type !== utils_1.AST_NODE_TYPES.ImportDeclaration) {
|
|
547
547
|
continue;
|
|
548
548
|
}
|
|
@@ -731,7 +731,7 @@ exports.enforceMemoizeAsync = (0, createRule_1.createRule)({
|
|
|
731
731
|
return null;
|
|
732
732
|
}
|
|
733
733
|
const fixes = [];
|
|
734
|
-
const sourceCode = context.
|
|
734
|
+
const sourceCode = context.getSourceCode();
|
|
735
735
|
// Determine which identifier to use for the decorator
|
|
736
736
|
let decoratorIdent = 'Memoize';
|
|
737
737
|
if (hasMemoizeImport) {
|
|
@@ -485,7 +485,7 @@ exports.enforceMicrodiff = (0, createRule_1.createRule)({
|
|
|
485
485
|
},
|
|
486
486
|
defaultOptions: [],
|
|
487
487
|
create(context) {
|
|
488
|
-
const sourceCode = context.
|
|
488
|
+
const sourceCode = context.getSourceCode();
|
|
489
489
|
const importedDiffLibraries = new Map();
|
|
490
490
|
// The diff specifiers this file imports, keyed by node so a call site can
|
|
491
491
|
// ask whether the binding it resolves to is one of them.
|
|
@@ -253,7 +253,7 @@ exports.enforceObjectLiteralAsConst = (0, createRule_1.createRule)({
|
|
|
253
253
|
return;
|
|
254
254
|
}
|
|
255
255
|
// Check if the return statement is inside a function
|
|
256
|
-
const sourceCode = context.
|
|
256
|
+
const sourceCode = context.getSourceCode();
|
|
257
257
|
// Use ASTHelpers.getAncestors for ESLint v8/v9 compatibility
|
|
258
258
|
const ancestors = ASTHelpers_1.ASTHelpers.getAncestors(context, node);
|
|
259
259
|
const isInFunction = ancestors.some((ancestor) => ancestor.type === 'FunctionDeclaration' ||
|
|
@@ -353,7 +353,7 @@ exports.enforcePropsArgumentName = (0, createRule_1.createRule)({
|
|
|
353
353
|
// Returns null whenever the rename cannot be applied everywhere, so the
|
|
354
354
|
// report stands on its own rather than corrupting the source.
|
|
355
355
|
function buildParameterRenameFixes(fixer, owner, id, newName) {
|
|
356
|
-
const sourceCode = context.
|
|
356
|
+
const sourceCode = context.getSourceCode();
|
|
357
357
|
const declarationFix = renameIdentifierToken(fixer, sourceCode, id, newName);
|
|
358
358
|
if (!declarationFix) {
|
|
359
359
|
return null;
|
|
@@ -95,7 +95,8 @@ exports.enforceStableStringify = (0, createRule_1.createRule)({
|
|
|
95
95
|
return null;
|
|
96
96
|
}
|
|
97
97
|
const fixes = [];
|
|
98
|
-
const
|
|
98
|
+
const sourceCode = context.getSourceCode();
|
|
99
|
+
const program = sourceCode.ast;
|
|
99
100
|
// Add the import only when the file lacks it. Suggestions are
|
|
100
101
|
// applied one at a time with a re-lint in between, so each is
|
|
101
102
|
// computed independently against the current file; adding the
|
|
@@ -108,7 +109,7 @@ exports.enforceStableStringify = (0, createRule_1.createRule)({
|
|
|
108
109
|
// `'use client'` directive demotes the directive to a plain
|
|
109
110
|
// expression, and above a `#!` shebang leaves the file
|
|
110
111
|
// unparseable.
|
|
111
|
-
fixes.push((0, importInsertion_1.insertAtImportAnchor)(
|
|
112
|
+
fixes.push((0, importInsertion_1.insertAtImportAnchor)(sourceCode, fixer, (0, importInsertion_1.importInsertionAnchor)(sourceCode), "import stringify from 'safe-stable-stringify';\n"));
|
|
112
113
|
}
|
|
113
114
|
fixes.push(fixer.replaceText(node, STRINGIFY_NAME));
|
|
114
115
|
return fixes;
|
|
@@ -490,8 +490,7 @@ exports.enforceStableHashSpreadProps = (0, createRule_1.createRule)({
|
|
|
490
490
|
},
|
|
491
491
|
defaultOptions: [{}],
|
|
492
492
|
create(context) {
|
|
493
|
-
const sourceCode = context.
|
|
494
|
-
context.getSourceCode();
|
|
493
|
+
const sourceCode = context.getSourceCode();
|
|
495
494
|
const [options = {}] = context.options;
|
|
496
495
|
const hashImport = {
|
|
497
496
|
source: options.hashImport?.source ?? DEFAULT_HASH_IMPORT.source,
|
|
@@ -227,7 +227,7 @@ exports.enforceTypescriptMarkdownCodeBlocks = (0, createRule_1.createRule)({
|
|
|
227
227
|
}
|
|
228
228
|
return {
|
|
229
229
|
Program() {
|
|
230
|
-
const sourceCode = context.
|
|
230
|
+
const sourceCode = context.getSourceCode();
|
|
231
231
|
const text = sourceCode.getText();
|
|
232
232
|
const lines = splitLines(text);
|
|
233
233
|
let index = 0;
|
|
@@ -4026,7 +4026,7 @@ exports.enforceVerbNounNaming = (0, createRule_1.createRule)({
|
|
|
4026
4026
|
return deferredExportedNames;
|
|
4027
4027
|
}
|
|
4028
4028
|
const names = new Set();
|
|
4029
|
-
for (const statement of context.
|
|
4029
|
+
for (const statement of context.getSourceCode().ast.body) {
|
|
4030
4030
|
if (statement.type === utils_1.AST_NODE_TYPES.ExportNamedDeclaration &&
|
|
4031
4031
|
!statement.source) {
|
|
4032
4032
|
for (const specifier of statement.specifiers) {
|
|
@@ -4181,7 +4181,9 @@ exports.enforceVerbNounNaming = (0, createRule_1.createRule)({
|
|
|
4181
4181
|
const id = parent.id;
|
|
4182
4182
|
if (id.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
4183
4183
|
id.typeAnnotation?.type === utils_1.AST_NODE_TYPES.TSTypeAnnotation) {
|
|
4184
|
-
const typeText = context
|
|
4184
|
+
const typeText = context
|
|
4185
|
+
.getSourceCode()
|
|
4186
|
+
.getText(id.typeAnnotation.typeAnnotation);
|
|
4185
4187
|
if (/\bReact\.(FC|FunctionComponent)\b/.test(typeText) ||
|
|
4186
4188
|
/\b(FC|FunctionComponent)\b/.test(typeText)) {
|
|
4187
4189
|
return true;
|
|
@@ -4195,7 +4197,9 @@ exports.enforceVerbNounNaming = (0, createRule_1.createRule)({
|
|
|
4195
4197
|
const memberParent = node.parent;
|
|
4196
4198
|
if (memberParent?.type === utils_1.AST_NODE_TYPES.PropertyDefinition &&
|
|
4197
4199
|
memberParent.typeAnnotation?.type === utils_1.AST_NODE_TYPES.TSTypeAnnotation) {
|
|
4198
|
-
const typeText = context
|
|
4200
|
+
const typeText = context
|
|
4201
|
+
.getSourceCode()
|
|
4202
|
+
.getText(memberParent.typeAnnotation.typeAnnotation);
|
|
4199
4203
|
if (/\bReact\.(FC|FunctionComponent)\b/.test(typeText) ||
|
|
4200
4204
|
/\b(FC|FunctionComponent)\b/.test(typeText)) {
|
|
4201
4205
|
return true;
|
|
@@ -4203,7 +4207,9 @@ exports.enforceVerbNounNaming = (0, createRule_1.createRule)({
|
|
|
4203
4207
|
}
|
|
4204
4208
|
// Handle FunctionDeclaration/FunctionExpression/ArrowFunction return type: function Foo(): React.JSX.Element { ... }
|
|
4205
4209
|
if (node.returnType?.type === utils_1.AST_NODE_TYPES.TSTypeAnnotation) {
|
|
4206
|
-
const typeText = context
|
|
4210
|
+
const typeText = context
|
|
4211
|
+
.getSourceCode()
|
|
4212
|
+
.getText(node.returnType.typeAnnotation);
|
|
4207
4213
|
return (/\bReact\.(FC|FunctionComponent|JSX\.Element|ReactElement)\b/.test(typeText) ||
|
|
4208
4214
|
/\b(FC|FunctionComponent|JSX\.Element|ReactElement)\b/.test(typeText));
|
|
4209
4215
|
}
|
|
@@ -539,7 +539,7 @@ exports.ensurePointerEventsNone = (0, createRule_1.createRule)({
|
|
|
539
539
|
// decides what the opaque value resolves to.
|
|
540
540
|
if (stylesWithUnreadablePointerEvents.get(node))
|
|
541
541
|
return null;
|
|
542
|
-
return appendPointerEventsNone(fixer, context.
|
|
542
|
+
return appendPointerEventsNone(fixer, context.getSourceCode(), node, printWidth);
|
|
543
543
|
},
|
|
544
544
|
});
|
|
545
545
|
}
|
|
@@ -113,7 +113,7 @@ exports.fastDeepEqualOverMicrodiff = (0, createRule_1.createRule)({
|
|
|
113
113
|
},
|
|
114
114
|
defaultOptions: [],
|
|
115
115
|
create(context) {
|
|
116
|
-
const sourceCode = context.
|
|
116
|
+
const sourceCode = context.getSourceCode();
|
|
117
117
|
let hasFastDeepEqualImport = false;
|
|
118
118
|
let hasMicrodiffImport = false;
|
|
119
119
|
let microdiffImportName = 'diff';
|
|
@@ -587,7 +587,7 @@ exports.default = (0, createRule_1.createRule)({
|
|
|
587
587
|
if (!init || isDynamicValue(init) || isBindingAlias(init)) {
|
|
588
588
|
return;
|
|
589
589
|
}
|
|
590
|
-
const sourceCode = context.
|
|
590
|
+
const sourceCode = context.getSourceCode();
|
|
591
591
|
const initText = sourceCode.getText(init);
|
|
592
592
|
const typeAnnotation = declaration.id.typeAnnotation;
|
|
593
593
|
const typeText = typeAnnotation
|
|
@@ -137,7 +137,7 @@ exports.keyOnlyOutermostElement = (0, createRule_1.createRule)({
|
|
|
137
137
|
},
|
|
138
138
|
defaultOptions: [],
|
|
139
139
|
create(context) {
|
|
140
|
-
const sourceCode = context.
|
|
140
|
+
const sourceCode = context.getSourceCode();
|
|
141
141
|
// Track JSXElements that are direct children of a map callback
|
|
142
142
|
const mapCallbackElements = new Set();
|
|
143
143
|
// Track JSXFragments that are direct children of a map callback
|
|
@@ -2087,9 +2087,7 @@ exports.logicalTopToBottomGrouping = (0, createRule_1.createRule)({
|
|
|
2087
2087
|
},
|
|
2088
2088
|
defaultOptions: [],
|
|
2089
2089
|
create(context) {
|
|
2090
|
-
|
|
2091
|
-
// compatible with ESLint versions that omit the property.
|
|
2092
|
-
const sourceCode = context.sourceCode ?? context.getSourceCode();
|
|
2090
|
+
const sourceCode = context.getSourceCode();
|
|
2093
2091
|
const ruleContext = {
|
|
2094
2092
|
context,
|
|
2095
2093
|
sourceCode,
|
|
@@ -671,7 +671,7 @@ See: https://react.dev/learn/your-first-component#nesting-and-organizing-compone
|
|
|
671
671
|
if (ignorePatterns.length && shouldIgnoreFile(filename, ignorePatterns)) {
|
|
672
672
|
return {};
|
|
673
673
|
}
|
|
674
|
-
const sourceCode = context.
|
|
674
|
+
const sourceCode = context.getSourceCode();
|
|
675
675
|
const reactImports = collectReactImports(sourceCode);
|
|
676
676
|
const reportNestedComponentViolation = (node, componentName, locationDescription) => {
|
|
677
677
|
context.report({
|