@pobammer-ts/eslint-cease-nonsense-rules 1.9.2 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -6
- package/dist/build-metadata.json +3 -3
- package/dist/index.js +218 -88
- package/dist/index.js.map +8 -8
- package/dist/rules/no-shorthand-names.d.ts +1 -0
- package/dist/rules/no-shorthand-names.d.ts.map +1 -1
- package/dist/rules/require-paired-calls.d.ts +18 -2
- package/dist/rules/require-paired-calls.d.ts.map +1 -1
- package/dist/rules/strict-component-boundaries.d.ts.map +1 -1
- package/dist/rules/use-exhaustive-dependencies.d.ts.map +1 -1
- package/dist/rules/use-hook-at-top-level.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -838,13 +838,19 @@ const doubled = items.map((x) => x * 2);
|
|
|
838
838
|
|
|
839
839
|
Bans shorthand variable names in favor of descriptive full names.
|
|
840
840
|
|
|
841
|
+
**Features**
|
|
842
|
+
|
|
843
|
+
- Matches shorthands within compound identifiers (e.g., `plrData` → `playerData`)
|
|
844
|
+
- Supports glob patterns (`*`, `?`) for flexible matching
|
|
845
|
+
- Supports regex patterns (`/pattern/flags`) for advanced matching
|
|
846
|
+
- Automatically ignores import specifiers (external packages control their naming)
|
|
847
|
+
|
|
841
848
|
**Default mappings**
|
|
842
849
|
|
|
843
850
|
- `plr` → `player` (or `localPlayer` for `Players.LocalPlayer`)
|
|
844
851
|
- `args` → `parameters`
|
|
845
852
|
- `dt` → `deltaTime`
|
|
846
853
|
- `char` → `character`
|
|
847
|
-
- `btn` → `button`
|
|
848
854
|
|
|
849
855
|
**Configuration**
|
|
850
856
|
|
|
@@ -853,16 +859,52 @@ Bans shorthand variable names in favor of descriptive full names.
|
|
|
853
859
|
"cease-nonsense/no-shorthand-names": ["error", {
|
|
854
860
|
"shorthands": {
|
|
855
861
|
"plr": "player",
|
|
856
|
-
"
|
|
857
|
-
"dt": "deltaTime",
|
|
858
|
-
"char": "character",
|
|
859
|
-
"btn": "button"
|
|
862
|
+
"*Props": "*Properties"
|
|
860
863
|
},
|
|
861
|
-
"allowPropertyAccess": ["char"] // Allow as property
|
|
864
|
+
"allowPropertyAccess": ["char", "Props"], // Allow as property/qualified name
|
|
865
|
+
"ignoreShorthands": ["PropsWithoutRef"] // Ignore completely
|
|
862
866
|
}]
|
|
863
867
|
}
|
|
864
868
|
```
|
|
865
869
|
|
|
870
|
+
**Options**
|
|
871
|
+
|
|
872
|
+
- `shorthands`: Map of shorthand patterns to replacements (exact, glob `*`/`?`, or regex `/pattern/flags`)
|
|
873
|
+
- `allowPropertyAccess`: Words allowed in property access (`obj.prop`) or type qualified names (`React.Props`)
|
|
874
|
+
- `ignoreShorthands`: Words to ignore completely, regardless of context (supports same pattern syntax)
|
|
875
|
+
|
|
876
|
+
**Pattern syntax**
|
|
877
|
+
|
|
878
|
+
Glob patterns use `*` (any characters) and `?` (single character):
|
|
879
|
+
|
|
880
|
+
```typescript
|
|
881
|
+
{
|
|
882
|
+
"shorthands": {
|
|
883
|
+
"str*": "string*", // strValue → stringValue
|
|
884
|
+
"*Props": "*Properties", // DataProps → DataProperties
|
|
885
|
+
"*Btn*": "*Button*" // myBtnClick → myButtonClick
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
```
|
|
889
|
+
|
|
890
|
+
Regex patterns use `/pattern/flags` syntax:
|
|
891
|
+
|
|
892
|
+
```typescript
|
|
893
|
+
{
|
|
894
|
+
"shorthands": {
|
|
895
|
+
"/^str(.*)$/": "string$1", // strName → stringName
|
|
896
|
+
"/^props$/i": "properties" // Props or props → properties
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
```
|
|
900
|
+
|
|
901
|
+
**Compound identifier matching**
|
|
902
|
+
|
|
903
|
+
Identifiers are split at camelCase/PascalCase boundaries, and each word is checked independently:
|
|
904
|
+
|
|
905
|
+
- `propsData` with `{ "props": "properties" }` → `propertiesData`
|
|
906
|
+
- `UnitBoxBadgeInfoProps` with `{ "Props": "Properties" }` → `UnitBoxBadgeInfoProperties`
|
|
907
|
+
|
|
866
908
|
**❌ Bad**
|
|
867
909
|
|
|
868
910
|
```typescript
|
package/dist/build-metadata.json
CHANGED
package/dist/index.js
CHANGED
|
@@ -18728,6 +18728,7 @@ var no_print_default = noPrint;
|
|
|
18728
18728
|
import { TSESTree as TSESTree6 } from "@typescript-eslint/types";
|
|
18729
18729
|
var isRuleOptions = Compile(build_default.Object({
|
|
18730
18730
|
allowPropertyAccess: build_default.Optional(build_default.Array(build_default.String())),
|
|
18731
|
+
ignoreShorthands: build_default.Optional(build_default.Array(build_default.String())),
|
|
18731
18732
|
shorthands: build_default.Optional(build_default.Record(build_default.String(), build_default.String()))
|
|
18732
18733
|
}));
|
|
18733
18734
|
function isRecord2(value) {
|
|
@@ -18735,6 +18736,7 @@ function isRecord2(value) {
|
|
|
18735
18736
|
}
|
|
18736
18737
|
var DEFAULT_OPTIONS2 = {
|
|
18737
18738
|
allowPropertyAccess: ["char"],
|
|
18739
|
+
ignoreShorthands: [],
|
|
18738
18740
|
shorthands: {
|
|
18739
18741
|
args: "parameters",
|
|
18740
18742
|
char: "character",
|
|
@@ -18744,32 +18746,78 @@ var DEFAULT_OPTIONS2 = {
|
|
|
18744
18746
|
};
|
|
18745
18747
|
var REGEX_PATTERN_MATCHER = regex2("^/(?<first>.+)/(?<second>[gimsuy]*)$");
|
|
18746
18748
|
var WORD_BOUNDARY_REGEX = /(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|(?<=[a-zA-Z])(?=\d)|(?<=\d)(?=[a-zA-Z])/;
|
|
18749
|
+
var FUNT_PATTERN = regex2("[.+^${}()|[\\]\\\\]", "g");
|
|
18750
|
+
var SPLIT_CACHE = new Map;
|
|
18751
|
+
var MAX_SPLIT_CACHE_SIZE = 1024;
|
|
18747
18752
|
function splitIdentifierIntoWords(identifier3) {
|
|
18748
|
-
|
|
18753
|
+
const cached = SPLIT_CACHE.get(identifier3);
|
|
18754
|
+
if (cached !== undefined)
|
|
18755
|
+
return cached;
|
|
18756
|
+
const words = identifier3.split(WORD_BOUNDARY_REGEX);
|
|
18757
|
+
if (SPLIT_CACHE.size >= MAX_SPLIT_CACHE_SIZE) {
|
|
18758
|
+
const firstKey = SPLIT_CACHE.keys().next().value;
|
|
18759
|
+
if (firstKey !== undefined)
|
|
18760
|
+
SPLIT_CACHE.delete(firstKey);
|
|
18761
|
+
}
|
|
18762
|
+
SPLIT_CACHE.set(identifier3, words);
|
|
18763
|
+
return words;
|
|
18764
|
+
}
|
|
18765
|
+
function countCaptureGroups(replacement) {
|
|
18766
|
+
const matches = replacement.match(/\$(\d+)/g);
|
|
18767
|
+
if (matches === null)
|
|
18768
|
+
return 0;
|
|
18769
|
+
let maxGroup = 0;
|
|
18770
|
+
for (const dollarRef of matches) {
|
|
18771
|
+
const groupNum = Number.parseInt(dollarRef.slice(1), 10);
|
|
18772
|
+
if (groupNum > maxGroup)
|
|
18773
|
+
maxGroup = groupNum;
|
|
18774
|
+
}
|
|
18775
|
+
return maxGroup;
|
|
18776
|
+
}
|
|
18777
|
+
var REPLACEMENT_PATTERN_CACHE = new Map;
|
|
18778
|
+
function getReplacementPattern(index2) {
|
|
18779
|
+
let pattern4 = REPLACEMENT_PATTERN_CACHE.get(index2);
|
|
18780
|
+
if (pattern4 === undefined) {
|
|
18781
|
+
pattern4 = new RegExp(`\\$${index2}`, "g");
|
|
18782
|
+
REPLACEMENT_PATTERN_CACHE.set(index2, pattern4);
|
|
18783
|
+
}
|
|
18784
|
+
return pattern4;
|
|
18785
|
+
}
|
|
18786
|
+
function buildReplacementPatterns(replacement) {
|
|
18787
|
+
const count = countCaptureGroups(replacement);
|
|
18788
|
+
if (count === 0)
|
|
18789
|
+
return [];
|
|
18790
|
+
const patterns2 = new Array(count);
|
|
18791
|
+
for (let index2 = 1;index2 <= count; index2 += 1) {
|
|
18792
|
+
patterns2[index2 - 1] = getReplacementPattern(index2);
|
|
18793
|
+
}
|
|
18794
|
+
return patterns2;
|
|
18749
18795
|
}
|
|
18750
18796
|
function createMatcher(key, replacement) {
|
|
18751
18797
|
if (key.startsWith("/")) {
|
|
18752
|
-
const match =
|
|
18753
|
-
if (match) {
|
|
18798
|
+
const match = key.match(REGEX_PATTERN_MATCHER);
|
|
18799
|
+
if (match?.groups) {
|
|
18754
18800
|
return {
|
|
18755
18801
|
matcher: {
|
|
18756
18802
|
original: key,
|
|
18757
18803
|
pattern: new RegExp(`^${match.groups.first}$`, match.groups.second),
|
|
18758
|
-
replacement
|
|
18804
|
+
replacement,
|
|
18805
|
+
replacementPatterns: buildReplacementPatterns(replacement)
|
|
18759
18806
|
},
|
|
18760
18807
|
type: "pattern"
|
|
18761
18808
|
};
|
|
18762
18809
|
}
|
|
18763
18810
|
}
|
|
18764
18811
|
if (key.includes("*") || key.includes("?")) {
|
|
18765
|
-
const regexPattern = key.replaceAll(
|
|
18812
|
+
const regexPattern = key.replaceAll(FUNT_PATTERN, String.raw`\$&`).replaceAll("*", "(.*)").replaceAll("?", "(.)");
|
|
18766
18813
|
let captureIndex = 0;
|
|
18767
18814
|
const regexReplacement = replacement.replaceAll("*", () => `$${++captureIndex}`);
|
|
18768
18815
|
return {
|
|
18769
18816
|
matcher: {
|
|
18770
18817
|
original: key,
|
|
18771
18818
|
pattern: new RegExp(`^${regexPattern}$`),
|
|
18772
|
-
replacement: regexReplacement
|
|
18819
|
+
replacement: regexReplacement,
|
|
18820
|
+
replacementPatterns: buildReplacementPatterns(regexReplacement)
|
|
18773
18821
|
},
|
|
18774
18822
|
type: "pattern"
|
|
18775
18823
|
};
|
|
@@ -18784,6 +18832,7 @@ function matchWord(word, matchers, exactMatchers) {
|
|
|
18784
18832
|
const exactReplacement = exactMatchers.get(word);
|
|
18785
18833
|
if (exactReplacement !== undefined) {
|
|
18786
18834
|
return {
|
|
18835
|
+
matchedWord: word,
|
|
18787
18836
|
replacement: exactReplacement,
|
|
18788
18837
|
shorthand: word
|
|
18789
18838
|
};
|
|
@@ -18792,10 +18841,13 @@ function matchWord(word, matchers, exactMatchers) {
|
|
|
18792
18841
|
const match = word.match(matcher.pattern);
|
|
18793
18842
|
if (match) {
|
|
18794
18843
|
let replaced = matcher.replacement;
|
|
18795
|
-
|
|
18796
|
-
|
|
18844
|
+
let captureIndex = 1;
|
|
18845
|
+
for (const replacementPattern of matcher.replacementPatterns) {
|
|
18846
|
+
replaced = replaced.replaceAll(replacementPattern, match[captureIndex] ?? "");
|
|
18847
|
+
captureIndex += 1;
|
|
18797
18848
|
}
|
|
18798
18849
|
return {
|
|
18850
|
+
matchedWord: word,
|
|
18799
18851
|
replacement: replaced,
|
|
18800
18852
|
shorthand: matcher.original
|
|
18801
18853
|
};
|
|
@@ -18803,22 +18855,13 @@ function matchWord(word, matchers, exactMatchers) {
|
|
|
18803
18855
|
}
|
|
18804
18856
|
return;
|
|
18805
18857
|
}
|
|
18806
|
-
function
|
|
18807
|
-
|
|
18808
|
-
|
|
18809
|
-
|
|
18810
|
-
|
|
18811
|
-
|
|
18812
|
-
|
|
18813
|
-
hasMatch = true;
|
|
18814
|
-
matches.push(match);
|
|
18815
|
-
return match.replacement;
|
|
18816
|
-
}
|
|
18817
|
-
return word;
|
|
18818
|
-
});
|
|
18819
|
-
if (!hasMatch)
|
|
18820
|
-
return;
|
|
18821
|
-
return { matches, replaced: newWords.join("") };
|
|
18858
|
+
function isWordIgnored(word, ignoreMatchers, ignoreExact) {
|
|
18859
|
+
if (ignoreExact.has(word))
|
|
18860
|
+
return true;
|
|
18861
|
+
for (const matcher of ignoreMatchers)
|
|
18862
|
+
if (matcher.pattern.test(word))
|
|
18863
|
+
return true;
|
|
18864
|
+
return false;
|
|
18822
18865
|
}
|
|
18823
18866
|
function normalizeOptions2(rawOptions) {
|
|
18824
18867
|
const mergedShorthands = { ...DEFAULT_OPTIONS2.shorthands };
|
|
@@ -18836,29 +18879,112 @@ function normalizeOptions2(rawOptions) {
|
|
|
18836
18879
|
matchers.push(result.matcher);
|
|
18837
18880
|
}
|
|
18838
18881
|
const allowPropertyAccessSource = rawOptions?.allowPropertyAccess ?? DEFAULT_OPTIONS2.allowPropertyAccess;
|
|
18882
|
+
const ignoreMatchers = new Array;
|
|
18883
|
+
const ignoreExact = new Set;
|
|
18884
|
+
for (const pattern4 of rawOptions?.ignoreShorthands ?? []) {
|
|
18885
|
+
const result = createMatcher(pattern4, "");
|
|
18886
|
+
if (result.type === "exact")
|
|
18887
|
+
ignoreExact.add(result.original);
|
|
18888
|
+
else
|
|
18889
|
+
ignoreMatchers.push(result.matcher);
|
|
18890
|
+
}
|
|
18839
18891
|
return {
|
|
18840
18892
|
allowPropertyAccess: new Set(allowPropertyAccessSource),
|
|
18841
18893
|
exactMatchers,
|
|
18894
|
+
ignoreExact,
|
|
18895
|
+
ignoreMatchers,
|
|
18842
18896
|
matchers,
|
|
18843
18897
|
selector: "Identifier"
|
|
18844
18898
|
};
|
|
18845
18899
|
}
|
|
18900
|
+
var IMPORT_PARENT_TYPES = new Set(["ImportSpecifier", "ImportDefaultSpecifier", "ImportNamespaceSpecifier"]);
|
|
18846
18901
|
var noShorthandNames = {
|
|
18847
18902
|
create(context) {
|
|
18848
18903
|
const validatedOptions = isRuleOptions.Check(context.options[0]) ? context.options[0] : undefined;
|
|
18849
18904
|
const normalized = normalizeOptions2(validatedOptions);
|
|
18850
|
-
const { allowPropertyAccess, selector } = normalized;
|
|
18905
|
+
const { allowPropertyAccess, ignoreMatchers, ignoreExact, selector, matchers, exactMatchers } = normalized;
|
|
18906
|
+
const identifierResultCache = new Map;
|
|
18907
|
+
const ignoredWordCache = new Map;
|
|
18908
|
+
function cachedIsWordIgnored(word) {
|
|
18909
|
+
const cached = ignoredWordCache.get(word);
|
|
18910
|
+
if (cached !== undefined)
|
|
18911
|
+
return cached;
|
|
18912
|
+
const result = isWordIgnored(word, ignoreMatchers, ignoreExact);
|
|
18913
|
+
ignoredWordCache.set(word, result);
|
|
18914
|
+
return result;
|
|
18915
|
+
}
|
|
18916
|
+
function getIdentifierResult(identifier3) {
|
|
18917
|
+
if (identifierResultCache.has(identifier3))
|
|
18918
|
+
return identifierResultCache.get(identifier3);
|
|
18919
|
+
const words = splitIdentifierIntoWords(identifier3);
|
|
18920
|
+
const matches = new Array;
|
|
18921
|
+
let hasMatch = false;
|
|
18922
|
+
for (const word of words) {
|
|
18923
|
+
const match = matchWord(word, matchers, exactMatchers);
|
|
18924
|
+
if (match) {
|
|
18925
|
+
hasMatch = true;
|
|
18926
|
+
matches.push(match);
|
|
18927
|
+
}
|
|
18928
|
+
}
|
|
18929
|
+
if (!hasMatch) {
|
|
18930
|
+
identifierResultCache.set(identifier3, undefined);
|
|
18931
|
+
return;
|
|
18932
|
+
}
|
|
18933
|
+
let replaced = "";
|
|
18934
|
+
let matchIndex = 0;
|
|
18935
|
+
for (const word of words) {
|
|
18936
|
+
const currentMatch = matches[matchIndex];
|
|
18937
|
+
if (currentMatch !== undefined && currentMatch.matchedWord === word) {
|
|
18938
|
+
replaced += currentMatch.replacement;
|
|
18939
|
+
matchIndex += 1;
|
|
18940
|
+
} else {
|
|
18941
|
+
replaced += word;
|
|
18942
|
+
}
|
|
18943
|
+
}
|
|
18944
|
+
const result = { matches, replaced };
|
|
18945
|
+
identifierResultCache.set(identifier3, result);
|
|
18946
|
+
return result;
|
|
18947
|
+
}
|
|
18851
18948
|
return {
|
|
18852
18949
|
[selector](node) {
|
|
18950
|
+
const { parent } = node;
|
|
18951
|
+
if (parent !== undefined && isRecord2(parent)) {
|
|
18952
|
+
const parentType = parent.type;
|
|
18953
|
+
if (IMPORT_PARENT_TYPES.has(parentType))
|
|
18954
|
+
return;
|
|
18955
|
+
}
|
|
18853
18956
|
const identifierName = node.name;
|
|
18854
|
-
const result =
|
|
18957
|
+
const result = getIdentifierResult(identifierName);
|
|
18855
18958
|
if (result === undefined)
|
|
18856
18959
|
return;
|
|
18857
18960
|
const { replaced, matches } = result;
|
|
18858
|
-
|
|
18859
|
-
|
|
18860
|
-
|
|
18961
|
+
if (cachedIsWordIgnored(identifierName))
|
|
18962
|
+
return;
|
|
18963
|
+
let allIgnored = true;
|
|
18964
|
+
for (const match of matches) {
|
|
18965
|
+
if (!cachedIsWordIgnored(match.matchedWord)) {
|
|
18966
|
+
allIgnored = false;
|
|
18967
|
+
break;
|
|
18968
|
+
}
|
|
18969
|
+
}
|
|
18970
|
+
if (allIgnored)
|
|
18861
18971
|
return;
|
|
18972
|
+
if (parent !== undefined && isRecord2(parent)) {
|
|
18973
|
+
const parentType = parent.type;
|
|
18974
|
+
const isPropertyAccess = parentType === "MemberExpression" && parent.property === node || parentType === "TSQualifiedName" && parent.right === node;
|
|
18975
|
+
if (isPropertyAccess) {
|
|
18976
|
+
if (allowPropertyAccess.has(identifierName))
|
|
18977
|
+
return;
|
|
18978
|
+
let allWordsAllowed = true;
|
|
18979
|
+
for (const match of matches) {
|
|
18980
|
+
if (!allowPropertyAccess.has(match.matchedWord)) {
|
|
18981
|
+
allWordsAllowed = false;
|
|
18982
|
+
break;
|
|
18983
|
+
}
|
|
18984
|
+
}
|
|
18985
|
+
if (allWordsAllowed)
|
|
18986
|
+
return;
|
|
18987
|
+
}
|
|
18862
18988
|
}
|
|
18863
18989
|
if (identifierName === "plr" && parent?.type === TSESTree6.AST_NODE_TYPES.VariableDeclarator && parent.id === node) {
|
|
18864
18990
|
const { init } = parent;
|
|
@@ -18893,7 +19019,12 @@ var noShorthandNames = {
|
|
|
18893
19019
|
additionalProperties: false,
|
|
18894
19020
|
properties: {
|
|
18895
19021
|
allowPropertyAccess: {
|
|
18896
|
-
description: "Shorthand names
|
|
19022
|
+
description: "Shorthand names allowed as property access or qualified names",
|
|
19023
|
+
items: { type: "string" },
|
|
19024
|
+
type: "array"
|
|
19025
|
+
},
|
|
19026
|
+
ignoreShorthands: {
|
|
19027
|
+
description: "Shorthand patterns to ignore completely (supports exact, glob, regex)",
|
|
18897
19028
|
items: { type: "string" },
|
|
18898
19029
|
type: "array"
|
|
18899
19030
|
},
|
|
@@ -20620,6 +20751,17 @@ function resolveContinueTargetLoop(statement) {
|
|
|
20620
20751
|
function cloneEntry(value) {
|
|
20621
20752
|
return { ...value, loopAncestors: [...value.loopAncestors] };
|
|
20622
20753
|
}
|
|
20754
|
+
var messages = {
|
|
20755
|
+
asyncViolation: "Cannot use {{asyncType}} between '{{opener}}' and '{{closer}}' (requireSync: true)",
|
|
20756
|
+
conditionalOpener: "Conditional opener '{{opener}}' at {{location}} may not have matching closer on all paths",
|
|
20757
|
+
maxNestingExceeded: "Maximum nesting depth of {{max}} exceeded for paired calls",
|
|
20758
|
+
multipleOpeners: "Multiple consecutive calls to '{{opener}}' without matching closers (allowMultipleOpeners: false)",
|
|
20759
|
+
robloxYieldViolation: "Yielding function '{{yieldingFunction}}' auto-closes all profiles - subsequent '{{closer}}' will error",
|
|
20760
|
+
unexpectedCloser: "Unexpected call to '{{closer}}' - expected one of: {{expected}}",
|
|
20761
|
+
unpairedCloser: "Unexpected call to '{{closer}}' - no matching opener on stack",
|
|
20762
|
+
unpairedOpener: "Unpaired call to '{{opener}}' - missing '{{closer}}' on {{paths}}",
|
|
20763
|
+
wrongOrder: "Closer '{{closer}}' called out of order - expected to close '{{expected}}' but '{{actual}}' is still open"
|
|
20764
|
+
};
|
|
20623
20765
|
var rule = {
|
|
20624
20766
|
create(context) {
|
|
20625
20767
|
const [rawOptions] = context.options;
|
|
@@ -20656,12 +20798,14 @@ var rule = {
|
|
|
20656
20798
|
if (closerToOpenersCache.has(closer))
|
|
20657
20799
|
return closerToOpenersCache.get(closer) ?? [];
|
|
20658
20800
|
const names = new Array;
|
|
20801
|
+
let size = 0;
|
|
20659
20802
|
for (const pair of options3.pairs) {
|
|
20660
20803
|
if (!getValidClosers(pair).includes(closer))
|
|
20661
20804
|
continue;
|
|
20662
|
-
for (const openerName of getAllOpeners(pair))
|
|
20805
|
+
for (const openerName of getAllOpeners(pair)) {
|
|
20663
20806
|
if (!names.includes(openerName))
|
|
20664
|
-
names
|
|
20807
|
+
names[size++] = openerName;
|
|
20808
|
+
}
|
|
20665
20809
|
}
|
|
20666
20810
|
closerToOpenersCache.set(closer, names);
|
|
20667
20811
|
return names;
|
|
@@ -20670,6 +20814,7 @@ var rule = {
|
|
|
20670
20814
|
if (openerToClosersCache.has(opener))
|
|
20671
20815
|
return openerToClosersCache.get(opener) ?? [];
|
|
20672
20816
|
const closers = new Array;
|
|
20817
|
+
let size = 0;
|
|
20673
20818
|
for (const pair of options3.pairs) {
|
|
20674
20819
|
const allOpeners = getAllOpeners(pair);
|
|
20675
20820
|
if (!allOpeners.includes(opener))
|
|
@@ -20677,7 +20822,7 @@ var rule = {
|
|
|
20677
20822
|
const validClosers = getValidClosers(pair);
|
|
20678
20823
|
for (const closer of validClosers)
|
|
20679
20824
|
if (!closers.includes(closer))
|
|
20680
|
-
closers
|
|
20825
|
+
closers[size++] = closer;
|
|
20681
20826
|
}
|
|
20682
20827
|
openerToClosersCache.set(opener, closers);
|
|
20683
20828
|
return closers;
|
|
@@ -20713,13 +20858,8 @@ var rule = {
|
|
|
20713
20858
|
function saveSnapshot(node) {
|
|
20714
20859
|
stackSnapshots.set(node, cloneStack());
|
|
20715
20860
|
}
|
|
20716
|
-
function
|
|
20717
|
-
return options3.pairs.find((pair) =>
|
|
20718
|
-
if (isOpener)
|
|
20719
|
-
return getAllOpeners(pair).includes(functionName);
|
|
20720
|
-
const validClosers = getValidClosers(pair);
|
|
20721
|
-
return validClosers.includes(functionName);
|
|
20722
|
-
});
|
|
20861
|
+
function findPairConfiguration(functionName, isOpener) {
|
|
20862
|
+
return options3.pairs.find((pair) => (isOpener ? getAllOpeners(pair) : getValidClosers(pair)).includes(functionName));
|
|
20723
20863
|
}
|
|
20724
20864
|
function isRobloxYieldingFunction(functionName, configuration) {
|
|
20725
20865
|
if (configuration.platform !== "roblox")
|
|
@@ -21058,12 +21198,12 @@ var rule = {
|
|
|
21058
21198
|
const callName = getCallName(callNode);
|
|
21059
21199
|
if (callName === undefined || callName === "")
|
|
21060
21200
|
return;
|
|
21061
|
-
const openerConfig =
|
|
21201
|
+
const openerConfig = findPairConfiguration(callName, true);
|
|
21062
21202
|
if (openerConfig) {
|
|
21063
21203
|
handleOpener(callNode, callName, openerConfig);
|
|
21064
21204
|
return;
|
|
21065
21205
|
}
|
|
21066
|
-
if (
|
|
21206
|
+
if (findPairConfiguration(callName, false)) {
|
|
21067
21207
|
handleCloser(callNode, callName);
|
|
21068
21208
|
return;
|
|
21069
21209
|
}
|
|
@@ -21115,31 +21255,31 @@ var rule = {
|
|
|
21115
21255
|
messageId: "unpairedCloser",
|
|
21116
21256
|
node
|
|
21117
21257
|
});
|
|
21258
|
+
return;
|
|
21259
|
+
}
|
|
21260
|
+
const topEntry = openerStack.at(-1);
|
|
21261
|
+
if (topEntry) {
|
|
21262
|
+
const expectedClosers = getExpectedClosersForOpener(topEntry.opener);
|
|
21263
|
+
const closerDescription = formatOpenerList(expectedClosers);
|
|
21264
|
+
context.report({
|
|
21265
|
+
data: {
|
|
21266
|
+
closer,
|
|
21267
|
+
expected: closerDescription
|
|
21268
|
+
},
|
|
21269
|
+
messageId: "unexpectedCloser",
|
|
21270
|
+
node
|
|
21271
|
+
});
|
|
21118
21272
|
} else {
|
|
21119
|
-
const
|
|
21120
|
-
|
|
21121
|
-
|
|
21122
|
-
|
|
21123
|
-
|
|
21124
|
-
|
|
21125
|
-
|
|
21126
|
-
|
|
21127
|
-
|
|
21128
|
-
|
|
21129
|
-
node
|
|
21130
|
-
});
|
|
21131
|
-
} else {
|
|
21132
|
-
const openerCandidates = getConfiguredOpenersForCloser(closer);
|
|
21133
|
-
const openerDescription = formatOpenerList(openerCandidates);
|
|
21134
|
-
context.report({
|
|
21135
|
-
data: {
|
|
21136
|
-
closer,
|
|
21137
|
-
opener: openerDescription
|
|
21138
|
-
},
|
|
21139
|
-
messageId: "unpairedCloser",
|
|
21140
|
-
node
|
|
21141
|
-
});
|
|
21142
|
-
}
|
|
21273
|
+
const openerCandidates = getConfiguredOpenersForCloser(closer);
|
|
21274
|
+
const openerDescription = formatOpenerList(openerCandidates);
|
|
21275
|
+
context.report({
|
|
21276
|
+
data: {
|
|
21277
|
+
closer,
|
|
21278
|
+
opener: openerDescription
|
|
21279
|
+
},
|
|
21280
|
+
messageId: "unpairedCloser",
|
|
21281
|
+
node
|
|
21282
|
+
});
|
|
21143
21283
|
}
|
|
21144
21284
|
return;
|
|
21145
21285
|
}
|
|
@@ -21200,10 +21340,9 @@ var rule = {
|
|
|
21200
21340
|
ForInStatement: onLoopEnter,
|
|
21201
21341
|
"ForInStatement:exit": onLoopExit,
|
|
21202
21342
|
ForOfStatement: (node) => {
|
|
21203
|
-
|
|
21204
|
-
|
|
21205
|
-
|
|
21206
|
-
onLoopEnter(forOfNode);
|
|
21343
|
+
if (node.await)
|
|
21344
|
+
onAsyncYield(node);
|
|
21345
|
+
onLoopEnter(node);
|
|
21207
21346
|
},
|
|
21208
21347
|
"ForOfStatement:exit": onLoopExit,
|
|
21209
21348
|
ForStatement: onLoopEnter,
|
|
@@ -21232,6 +21371,7 @@ var rule = {
|
|
|
21232
21371
|
YieldExpression: onAsyncYield
|
|
21233
21372
|
};
|
|
21234
21373
|
},
|
|
21374
|
+
defaultOptions: [],
|
|
21235
21375
|
meta: {
|
|
21236
21376
|
docs: {
|
|
21237
21377
|
description: "Enforces balanced opener/closer function calls across all execution paths",
|
|
@@ -21239,17 +21379,7 @@ var rule = {
|
|
|
21239
21379
|
url: "https://github.com/howmanysmall/eslint-idiot-lint/tree/main/docs/rules/require-paired-calls.md"
|
|
21240
21380
|
},
|
|
21241
21381
|
fixable: "code",
|
|
21242
|
-
messages
|
|
21243
|
-
asyncViolation: "Cannot use {{asyncType}} between '{{opener}}' and '{{closer}}' (requireSync: true)",
|
|
21244
|
-
conditionalOpener: "Conditional opener '{{opener}}' at {{location}} may not have matching closer on all paths",
|
|
21245
|
-
maxNestingExceeded: "Maximum nesting depth of {{max}} exceeded for paired calls",
|
|
21246
|
-
multipleOpeners: "Multiple consecutive calls to '{{opener}}' without matching closers (allowMultipleOpeners: false)",
|
|
21247
|
-
robloxYieldViolation: "Yielding function '{{yieldingFunction}}' auto-closes all profiles - subsequent '{{closer}}' will error",
|
|
21248
|
-
unexpectedCloser: "Unexpected call to '{{closer}}' - expected one of: {{expected}}",
|
|
21249
|
-
unpairedCloser: "Unexpected call to '{{closer}}' - no matching opener on stack",
|
|
21250
|
-
unpairedOpener: "Unpaired call to '{{opener}}' - missing '{{closer}}' on {{paths}}",
|
|
21251
|
-
wrongOrder: "Closer '{{closer}}' called out of order - expected to close '{{expected}}' but '{{actual}}' is still open"
|
|
21252
|
-
},
|
|
21382
|
+
messages,
|
|
21253
21383
|
schema: [
|
|
21254
21384
|
{
|
|
21255
21385
|
additionalProperties: false,
|
|
@@ -21999,8 +22129,9 @@ function isStableValue(variable, identifierName, stableHooks) {
|
|
|
21999
22129
|
return true;
|
|
22000
22130
|
if (type3 === "Variable" && node.type === TSESTree10.AST_NODE_TYPES.VariableDeclarator) {
|
|
22001
22131
|
const { parent } = node;
|
|
22002
|
-
if (!parent || parent.type !== TSESTree10.AST_NODE_TYPES.VariableDeclaration || parent.kind !== "const")
|
|
22132
|
+
if (!parent || parent.type !== TSESTree10.AST_NODE_TYPES.VariableDeclaration || parent.kind !== "const") {
|
|
22003
22133
|
continue;
|
|
22134
|
+
}
|
|
22004
22135
|
const init = node.init;
|
|
22005
22136
|
if (init && isStableHookValue(init, node, identifierName, stableHooks))
|
|
22006
22137
|
return true;
|
|
@@ -22575,8 +22706,9 @@ function isHookCall(node) {
|
|
|
22575
22706
|
const { callee } = node;
|
|
22576
22707
|
if (callee.type === TSESTree11.AST_NODE_TYPES.Identifier)
|
|
22577
22708
|
return isReactHook(callee.name);
|
|
22578
|
-
if (callee.type === TSESTree11.AST_NODE_TYPES.MemberExpression && callee.property.type === TSESTree11.AST_NODE_TYPES.Identifier)
|
|
22709
|
+
if (callee.type === TSESTree11.AST_NODE_TYPES.MemberExpression && callee.property.type === TSESTree11.AST_NODE_TYPES.Identifier) {
|
|
22579
22710
|
return isReactHook(callee.property.name);
|
|
22711
|
+
}
|
|
22580
22712
|
return false;
|
|
22581
22713
|
}
|
|
22582
22714
|
var FUNCTION_BOUNDARIES2 = new Set([
|
|
@@ -22610,9 +22742,7 @@ function isRecursiveCall(node, functionName) {
|
|
|
22610
22742
|
if (!functionName)
|
|
22611
22743
|
return false;
|
|
22612
22744
|
const { callee } = node;
|
|
22613
|
-
|
|
22614
|
-
return callee.name === functionName;
|
|
22615
|
-
return false;
|
|
22745
|
+
return callee.type === "Identifier" && callee.name === functionName;
|
|
22616
22746
|
}
|
|
22617
22747
|
var useHookAtTopLevel = {
|
|
22618
22748
|
create(context) {
|
|
@@ -22913,7 +23043,7 @@ function createNoInstanceMethodsOptions(options3 = {}) {
|
|
|
22913
23043
|
};
|
|
22914
23044
|
}
|
|
22915
23045
|
function createNoShorthandOptions(options3 = {}) {
|
|
22916
|
-
return { allowPropertyAccess: [], shorthands: {}, ...options3 };
|
|
23046
|
+
return { allowPropertyAccess: [], ignoreShorthands: [], shorthands: {}, ...options3 };
|
|
22917
23047
|
}
|
|
22918
23048
|
function createEffectFunctionOptions(options3 = {}) {
|
|
22919
23049
|
return { environment: "standard", hooks: [], ...options3 };
|
|
@@ -23055,4 +23185,4 @@ export {
|
|
|
23055
23185
|
createBanInstancesOptions
|
|
23056
23186
|
};
|
|
23057
23187
|
|
|
23058
|
-
//# debugId=
|
|
23188
|
+
//# debugId=CB943D9A894DADAF64756E2164756E21
|