@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 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
- "args": "parameters",
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
@@ -1,5 +1,5 @@
1
1
  {
2
- "commit": "d84eba40b7747b35f7141d5e4f2ef9ce11db5e57",
3
- "time": "2025-12-22T21:43:58.605Z",
4
- "version": "1.9.2"
2
+ "commit": "8104213e0676ebea2ce52403f0e6559fb13d576e",
3
+ "time": "2025-12-23T03:11:07.286Z",
4
+ "version": "1.10.0"
5
5
  }
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
- return identifier3.split(WORD_BOUNDARY_REGEX);
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 = REGEX_PATTERN_MATCHER.exec(key);
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(/[.+^${}()|[\]\\]/g, String.raw`\$&`).replaceAll("*", "(.*)").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
- for (let index2 = 1;index2 < match.length; index2 += 1) {
18796
- replaced = replaced.replaceAll(new RegExp(`\\$${index2}`, "g"), match[index2] ?? "");
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 buildReplacementIdentifier(identifier3, options3) {
18807
- const words = splitIdentifierIntoWords(identifier3);
18808
- const matches = new Array;
18809
- let hasMatch = false;
18810
- const newWords = words.map((word) => {
18811
- const match = matchWord(word, options3.matchers, options3.exactMatchers);
18812
- if (match) {
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 = buildReplacementIdentifier(identifierName, normalized);
18957
+ const result = getIdentifierResult(identifierName);
18855
18958
  if (result === undefined)
18856
18959
  return;
18857
18960
  const { replaced, matches } = result;
18858
- const { parent } = node;
18859
- const [match] = matches;
18860
- if (matches.length === 1 && match !== undefined && allowPropertyAccess.has(match.shorthand) && parent !== undefined && isRecord2(parent) && parent.type === TSESTree6.AST_NODE_TYPES.MemberExpression && parent.property === node) {
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 that are allowed as property access",
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.push(openerName);
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.push(closer);
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 findPairConfig(functionName, isOpener) {
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 = findPairConfig(callName, true);
21201
+ const openerConfig = findPairConfiguration(callName, true);
21062
21202
  if (openerConfig) {
21063
21203
  handleOpener(callNode, callName, openerConfig);
21064
21204
  return;
21065
21205
  }
21066
- if (findPairConfig(callName, false)) {
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 topEntry = openerStack.at(-1);
21120
- if (topEntry) {
21121
- const expectedClosers = getExpectedClosersForOpener(topEntry.opener);
21122
- const closerDescription = formatOpenerList(expectedClosers);
21123
- context.report({
21124
- data: {
21125
- closer,
21126
- expected: closerDescription
21127
- },
21128
- messageId: "unexpectedCloser",
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
- const forOfNode = node;
21204
- if (forOfNode.await)
21205
- onAsyncYield(forOfNode);
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
- if (callee.type === "Identifier")
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=C1BEC810E1B754DD64756E2164756E21
23188
+ //# debugId=CB943D9A894DADAF64756E2164756E21