@flint.fyi/ts 0.23.0 → 0.23.2

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/dist/index.d.mts CHANGED
@@ -958,13 +958,6 @@ declare const ts: import("@flint.fyi/core").Plugin<import("@flint.fyi/core").Rul
958
958
  readonly pluginId: string;
959
959
  readonly url: string;
960
960
  }, "implicitExports", undefined>, import("@flint.fyi/core").Rule<{
961
- readonly description: "Reports using `module` keyword instead of `namespace` for TypeScript namespaces.";
962
- readonly id: "namespaceKeywords";
963
- readonly presets: readonly ["stylistic", "stylisticStrict"];
964
- } & {
965
- readonly pluginId: string;
966
- readonly url: string;
967
- }, "preferNamespace", undefined>, import("@flint.fyi/core").Rule<{
968
961
  readonly description: "Reports extending the prototype of native JavaScript objects.";
969
962
  readonly id: "nativeObjectExtensions";
970
963
  readonly presets: readonly ["javascript"];
@@ -1203,13 +1196,6 @@ declare const ts: import("@flint.fyi/core").Plugin<import("@flint.fyi/core").Rul
1203
1196
  readonly pluginId: string;
1204
1197
  readonly url: string;
1205
1198
  }, "noOctalEscape", undefined>, import("@flint.fyi/core").Rule<{
1206
- readonly description: "Reports using legacy octal numeric literals.";
1207
- readonly id: "octalNumbers";
1208
- readonly presets: readonly ["javascript"];
1209
- } & {
1210
- readonly pluginId: string;
1211
- readonly url: string;
1212
- }, "noOctalNumber", undefined>, import("@flint.fyi/core").Rule<{
1213
1199
  readonly description: "Prefer assignment operator shorthand where possible.";
1214
1200
  readonly id: "operatorAssignmentShorthand";
1215
1201
  readonly presets: readonly ["stylistic", "stylisticStrict"];
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { RuleCreator, createPlugin } from "@flint.fyi/core";
2
2
  import { declarationIncludesGlobal, forEachChild, getModifyingReferences, getScopeManager, getStaticNumberValue, getStaticStringValue, getStaticValue, getTSNodeRange, hasSameTokens, isBuiltinArrayMethod, isFunction, isGlobalDeclaration, isGlobalDeclarationOfName, isGlobalVariable, isInlineArrayCreation, typescriptLanguage, unwrapParentParenthesizedExpressions, unwrapParenthesizedNode } from "@flint.fyi/typescript-language";
3
- import ts$1, { NodeFlags, SignatureKind, SymbolFlags, SyntaxKind, TypeFlags, getLeadingCommentRanges, getTrailingCommentRanges, isArrayLiteralExpression, isBigIntLiteral, isElementAccessExpression, isFunctionLike, isIdentifier, isInterfaceDeclaration, isLiteralExpression, isNewExpression, isNumericLiteral, isParenthesizedExpression, isPrefixUnaryExpression, isPropertyAccessExpression, isSpreadElement, isStringLiteral, isVariableDeclaration } from "typescript";
3
+ import ts$1, { NodeFlags, SignatureKind, SymbolFlags, SyntaxKind, TypeFlags, getLeadingCommentRanges, getTrailingCommentRanges, isArrayLiteralExpression, isBigIntLiteral, isElementAccessExpression, isExpressionWithTypeArguments, isFunctionLike, isIdentifier, isInterfaceDeclaration, isLiteralExpression, isNewExpression, isNumericLiteral, isParenthesizedExpression, isPrefixUnaryExpression, isPropertyAccessExpression, isShorthandPropertyAssignment, isSpreadElement, isStringLiteral, isTypeNode, isTypeParameterDeclaration, isVariableDeclaration } from "typescript";
4
4
  import * as tsutils from "ts-api-utils";
5
5
  import { isNodeFlagSet, isNullKeyword } from "ts-api-utils";
6
6
  import { nullThrows, pathKey } from "@flint.fyi/utils";
@@ -1686,9 +1686,7 @@ function isDirectEqualityCheck(node, operators, parameterName) {
1686
1686
  case SyntaxKind.ArrowFunction:
1687
1687
  body = node.body.kind === SyntaxKind.Block ? getDirectReturnExpression(node.body) : node.body;
1688
1688
  break;
1689
- case SyntaxKind.FunctionExpression:
1690
- body = getDirectReturnExpression(node.body);
1691
- break;
1689
+ case SyntaxKind.FunctionExpression: body = getDirectReturnExpression(node.body);
1692
1690
  }
1693
1691
  if (body?.kind !== SyntaxKind.BinaryExpression) return false;
1694
1692
  const { left, operatorToken, right } = body;
@@ -2273,10 +2271,7 @@ var arrayTypes_default = ruleCreator.createRule(typescriptLanguage, {
2273
2271
  if (node.parent.kind === SyntaxKind.TypeOperator && node.parent.operator === SyntaxKind.ReadonlyKeyword) return;
2274
2272
  switch (options.style) {
2275
2273
  case "array": return;
2276
- case "array-simple":
2277
- if (isSimpleType(node.elementType)) return;
2278
- break;
2279
- case "generic": break;
2274
+ case "array-simple": if (isSimpleType(node.elementType)) return;
2280
2275
  }
2281
2276
  context.report({
2282
2277
  message: "preferGenericSyntax",
@@ -2288,10 +2283,7 @@ var arrayTypes_default = ruleCreator.createRule(typescriptLanguage, {
2288
2283
  const arrayType = node.type;
2289
2284
  switch (options.style) {
2290
2285
  case "array": return;
2291
- case "array-simple":
2292
- if (isSimpleType(arrayType.elementType)) return;
2293
- break;
2294
- case "generic": break;
2286
+ case "array-simple": if (isSimpleType(arrayType.elementType)) return;
2295
2287
  }
2296
2288
  context.report({
2297
2289
  message: "preferReadonlyGenericSyntax",
@@ -3053,9 +3045,7 @@ var catchCallbackTypes_default = ruleCreator.createRule(typescriptLanguage, {
3053
3045
  case "catch":
3054
3046
  if (node.arguments.length >= 1) checkCallbackParameter(node.arguments[0], sourceFile, typeChecker);
3055
3047
  break;
3056
- case "then":
3057
- if (node.arguments.length >= 2) checkCallbackParameter(node.arguments[1], sourceFile, typeChecker);
3058
- break;
3048
+ case "then": if (node.arguments.length >= 2) checkCallbackParameter(node.arguments[1], sourceFile, typeChecker);
3059
3049
  }
3060
3050
  } } };
3061
3051
  }
@@ -3437,9 +3427,7 @@ var classMethodsThis_default = ruleCreator.createRule(typescriptLanguage, {
3437
3427
  case SyntaxKind.PropertyDeclaration:
3438
3428
  checkPropertyInitializerFunction(member, node, sourceFile, options);
3439
3429
  break;
3440
- case SyntaxKind.SetAccessor:
3441
- checkAccessor(member, node, sourceFile, options, "setter");
3442
- break;
3430
+ case SyntaxKind.SetAccessor: checkAccessor(member, node, sourceFile, options, "setter");
3443
3431
  }
3444
3432
  }
3445
3433
  return { visitors: {
@@ -3894,12 +3882,10 @@ var dateNowTimestamps_default = ruleCreator.createRule(typescriptLanguage, {
3894
3882
  range: getTSNodeRange(node.parent, sourceFile)
3895
3883
  });
3896
3884
  break;
3897
- case SyntaxKind.PrefixUnaryExpression:
3898
- if (node.parent.operator === SyntaxKind.MinusToken || node.parent.operator === SyntaxKind.PlusToken) context.report({
3899
- message: "preferDateNow",
3900
- range: getTSNodeRange(node, sourceFile)
3901
- });
3902
- break;
3885
+ case SyntaxKind.PrefixUnaryExpression: if (node.parent.operator === SyntaxKind.MinusToken || node.parent.operator === SyntaxKind.PlusToken) context.report({
3886
+ message: "preferDateNow",
3887
+ range: getTSNodeRange(node, sourceFile)
3888
+ });
3903
3889
  }
3904
3890
  }
3905
3891
  } };
@@ -5859,9 +5845,7 @@ var exportUniqueNames_default = ruleCreator.createRule(typescriptLanguage, {
5859
5845
  case SyntaxKind.ExportDeclaration:
5860
5846
  checkExportDeclaration(statement);
5861
5847
  break;
5862
- case SyntaxKind.VariableStatement:
5863
- checkVariableStatement(statement);
5864
- break;
5848
+ case SyntaxKind.VariableStatement: checkVariableStatement(statement);
5865
5849
  }
5866
5850
  } } };
5867
5851
  }
@@ -6001,7 +5985,6 @@ var fetchMethodBodies_default = ruleCreator.createRule(typescriptLanguage, {
6001
5985
  case "method":
6002
5986
  if (property.initializer.kind !== SyntaxKind.StringLiteral) return;
6003
5987
  methodText = property.initializer.text;
6004
- break;
6005
5988
  }
6006
5989
  break;
6007
5990
  case SyntaxKind.SpreadAssignment: return;
@@ -6750,9 +6733,7 @@ function getCalleeName(node) {
6750
6733
  if (node.expression.kind === SyntaxKind.Identifier && globalCandidates.has(node.expression.text) && node.argumentExpression.kind === SyntaxKind.StringLiteral) return node.argumentExpression.text;
6751
6734
  break;
6752
6735
  case SyntaxKind.Identifier: return node.text;
6753
- case SyntaxKind.PropertyAccessExpression:
6754
- if (node.expression.kind === SyntaxKind.Identifier && globalCandidates.has(node.expression.text)) return node.name.text;
6755
- break;
6736
+ case SyntaxKind.PropertyAccessExpression: if (node.expression.kind === SyntaxKind.Identifier && globalCandidates.has(node.expression.text)) return node.name.text;
6756
6737
  }
6757
6738
  }
6758
6739
  function isBind(node) {
@@ -6842,9 +6823,7 @@ var impliedEvals_default = ruleCreator.createRule(typescriptLanguage, {
6842
6823
  checkCalleeFunction(node, services);
6843
6824
  break;
6844
6825
  case void 0: return;
6845
- default:
6846
- checkCalleeEval(node, calleeName, services);
6847
- break;
6826
+ default: checkCalleeEval(node, calleeName, services);
6848
6827
  }
6849
6828
  }
6850
6829
  return { visitors: {
@@ -7744,40 +7723,6 @@ var namespaceImplicitAmbientImports_default = ruleCreator.createRule(typescriptL
7744
7723
  }
7745
7724
  });
7746
7725
  //#endregion
7747
- //#region src/rules/namespaceKeywords.ts
7748
- var namespaceKeywords_default = ruleCreator.createRule(typescriptLanguage, {
7749
- about: {
7750
- description: "Reports using `module` keyword instead of `namespace` for TypeScript namespaces.",
7751
- id: "namespaceKeywords",
7752
- presets: ["stylistic", "stylisticStrict"]
7753
- },
7754
- messages: { preferNamespace: {
7755
- primary: "The `namespace` keyword is preferred over `module` for TypeScript namespaces.",
7756
- secondary: [
7757
- "TypeScript originally used the `module` keyword to declare internal modules (namespaces).",
7758
- "The `namespace` keyword was later introduced to avoid confusion with ES6 modules.",
7759
- "Using `namespace` makes it clear you are defining a TypeScript namespace, not an ES6 module."
7760
- ],
7761
- suggestions: ["Replace `module` with `namespace`."]
7762
- } },
7763
- setup(context) {
7764
- return { visitors: { ModuleDeclaration: (node, { sourceFile }) => {
7765
- if (node.name.kind === SyntaxKind.StringLiteral) return;
7766
- const moduleKeywordToken = node.getChildren(sourceFile).find((child) => child.kind === SyntaxKind.ModuleKeyword);
7767
- if (!moduleKeywordToken) return;
7768
- const range = getTSNodeRange(moduleKeywordToken, sourceFile);
7769
- context.report({
7770
- fix: {
7771
- range,
7772
- text: "namespace"
7773
- },
7774
- message: "preferNamespace",
7775
- range
7776
- });
7777
- } } };
7778
- }
7779
- });
7780
- //#endregion
7781
7726
  //#region src/rules/nativeObjectExtensions.ts
7782
7727
  const nativeConstructors = /* @__PURE__ */ new Set([
7783
7728
  "AggregateError",
@@ -8638,13 +8583,11 @@ var nonNullAssertionPlacement_default = ruleCreator.createRule(typescriptLanguag
8638
8583
  suggestions
8639
8584
  });
8640
8585
  break;
8641
- default:
8642
- context.report({
8643
- message: "confusingEqual",
8644
- range,
8645
- suggestions
8646
- });
8647
- break;
8586
+ default: context.report({
8587
+ message: "confusingEqual",
8588
+ range,
8589
+ suggestions
8590
+ });
8648
8591
  }
8649
8592
  } } };
8650
8593
  }
@@ -9288,12 +9231,10 @@ var numericErasingOperations_default = ruleCreator.createRule(typescriptLanguage
9288
9231
  range: getTSNodeRange(node, sourceFile)
9289
9232
  });
9290
9233
  break;
9291
- case SyntaxKind.SlashToken:
9292
- if (isZeroLiteral(node.left) && !isZeroLiteral(node.right)) context.report({
9293
- message: "erasingOperation",
9294
- range: getTSNodeRange(node, sourceFile)
9295
- });
9296
- break;
9234
+ case SyntaxKind.SlashToken: if (isZeroLiteral(node.left) && !isZeroLiteral(node.right)) context.report({
9235
+ message: "erasingOperation",
9236
+ range: getTSNodeRange(node, sourceFile)
9237
+ });
9297
9238
  }
9298
9239
  } } };
9299
9240
  }
@@ -10083,55 +10024,6 @@ var octalEscapes_default = ruleCreator.createRule(typescriptLanguage, {
10083
10024
  }
10084
10025
  });
10085
10026
  //#endregion
10086
- //#region src/rules/octalNumbers.ts
10087
- var octalNumbers_default = ruleCreator.createRule(typescriptLanguage, {
10088
- about: {
10089
- description: "Reports using legacy octal numeric literals.",
10090
- id: "octalNumbers",
10091
- presets: ["javascript"]
10092
- },
10093
- messages: { noOctalNumber: {
10094
- primary: "This legacy octal numeric literal evaluates to {{ raw }}. Did you mean that value, or to use a modern octal syntax such as {{ equivalent }}?",
10095
- secondary: [
10096
- "Legacy octal numeric literals (e.g., `077`, `0123`) are a deprecated feature in JavaScript that can lead to confusion and errors.",
10097
- "They are forbidden in strict mode and are less readable than their modern alternatives.",
10098
- "The digit `0` by itself is allowed as it represents zero, not an octal literal."
10099
- ],
10100
- suggestions: ["Use the explicit octal syntax (e.g., `0o77`) introduced in ES6, which is clearer and works in both strict and non-strict modes.", "Remove the leading `0` if you intended to use the decimal value."]
10101
- } },
10102
- setup(context) {
10103
- return { visitors: { NumericLiteral: (node, { sourceFile }) => {
10104
- const text = node.getText(sourceFile);
10105
- if (text.length > 1 && text.startsWith("0") && nullThrows(text[1], "Second character is expected to be present by prior length check") >= "0" && nullThrows(text[1], "Second character is expected to be present by prior length check") <= "7" && !/^0[xobi]/i.test(text)) {
10106
- const range = {
10107
- begin: node.getStart(sourceFile),
10108
- end: node.getEnd()
10109
- };
10110
- const octalValue = parseInt(text, 8);
10111
- const modernOctalSyntax = `0o${text.slice(1)}`;
10112
- const decimalWithoutLeadingZero = text.slice(1);
10113
- context.report({
10114
- data: {
10115
- equivalent: modernOctalSyntax,
10116
- raw: octalValue.toString()
10117
- },
10118
- message: "noOctalNumber",
10119
- range,
10120
- suggestions: [{
10121
- id: "useModernOctalSyntax",
10122
- range,
10123
- text: modernOctalSyntax
10124
- }, {
10125
- id: "removeLeadingZero",
10126
- range,
10127
- text: decimalWithoutLeadingZero
10128
- }]
10129
- });
10130
- }
10131
- } } };
10132
- }
10133
- });
10134
- //#endregion
10135
10027
  //#region src/rules/operatorAssignmentShorthand.ts
10136
10028
  const operatorTexts = /* @__PURE__ */ new Map([
10137
10029
  [SyntaxKind.AmpersandToken, "&"],
@@ -11285,9 +11177,7 @@ function elementsToCharacterClass(elements) {
11285
11177
  case "CharacterClassRange":
11286
11178
  case "CharacterSet":
11287
11179
  case "ClassStringDisjunction":
11288
- case "ExpressionCharacterClass":
11289
- parts.push(element.raw);
11290
- break;
11180
+ case "ExpressionCharacterClass": parts.push(element.raw);
11291
11181
  }
11292
11182
  if (!parts.length) return "[]";
11293
11183
  if (parts[0]?.[0] === "^") parts[0] = `\\${parts[0]}`;
@@ -11511,7 +11401,9 @@ function processCharacterClass(node) {
11511
11401
  } else continue;
11512
11402
  const group = groups.find((gp) => {
11513
11403
  if (!(gp.min.value - 1 <= data.max.value && data.min.value <= gp.max.value + 1)) return false;
11514
- return inRange(ALPHANUMERIC_RANGES, Math.min(gp.min.value, data.min.value), Math.max(gp.max.value, data.max.value));
11404
+ const min = Math.min(gp.min.value, data.min.value);
11405
+ const max = Math.max(gp.max.value, data.max.value);
11406
+ return inRange(ALPHANUMERIC_RANGES, min, max);
11515
11407
  });
11516
11408
  if (group) {
11517
11409
  if (data.min.value < group.min.value) group.min = data.min;
@@ -12186,17 +12078,19 @@ function findIssues$2(pattern, flags) {
12186
12078
  const groups = [];
12187
12079
  for (const element of ccNode.elements) {
12188
12080
  let data;
12189
- if (element.type === "Character") if (checkInAllowedRange(element.value)) data = {
12190
- max: element,
12191
- min: element
12192
- };
12193
- else continue;
12194
- else if (element.type === "CharacterClassRange") if (checkInAllowedRange(element.min.value, element.min.value, element.max.value)) data = {
12195
- max: element.max,
12196
- min: element.min
12197
- };
12198
- else continue;
12199
- else continue;
12081
+ if (element.type === "Character") {
12082
+ if (checkInAllowedRange(element.value)) data = {
12083
+ max: element,
12084
+ min: element
12085
+ };
12086
+ else continue;
12087
+ } else if (element.type === "CharacterClassRange") {
12088
+ if (checkInAllowedRange(element.min.value, element.min.value, element.max.value)) data = {
12089
+ max: element.max,
12090
+ min: element.min
12091
+ };
12092
+ else continue;
12093
+ } else continue;
12200
12094
  const group = groups.find((gp) => {
12201
12095
  if (!(gp.min.value - 1 <= data.max.value && data.min.value <= gp.max.value + 1)) return false;
12202
12096
  const min = Math.min(gp.min.value, data.min.value);
@@ -12539,9 +12433,10 @@ function findEmptyAlternativesInGroup(pattern, groupStart, groupEnd, results) {
12539
12433
  "?!",
12540
12434
  "?:",
12541
12435
  "?="
12542
- ].includes(pattern.slice(groupStart, groupStart + 2)) || ["?<!", "?<="].includes(pattern.slice(groupStart, groupStart + 3))) if (pattern.slice(groupStart, groupStart + 3).startsWith("?<")) contentStart = groupStart + 3;
12543
- else contentStart = groupStart + 2;
12544
- else if (pattern[groupStart] === "?" && pattern[groupStart + 1] === "<") {
12436
+ ].includes(pattern.slice(groupStart, groupStart + 2)) || ["?<!", "?<="].includes(pattern.slice(groupStart, groupStart + 3))) {
12437
+ if (pattern.slice(groupStart, groupStart + 3).startsWith("?<")) contentStart = groupStart + 3;
12438
+ else contentStart = groupStart + 2;
12439
+ } else if (pattern[groupStart] === "?" && pattern[groupStart + 1] === "<") {
12545
12440
  const closeAngle = pattern.indexOf(">", groupStart + 2);
12546
12441
  if (closeAngle !== -1 && closeAngle < groupEnd) contentStart = closeAngle + 1;
12547
12442
  }
@@ -12558,9 +12453,7 @@ function findEmptyAlternativesInGroup(pattern, groupStart, groupEnd, results) {
12558
12453
  case "\\":
12559
12454
  i++;
12560
12455
  break;
12561
- case "|":
12562
- pipePositions.push(i);
12563
- break;
12456
+ case "|": pipePositions.push(i);
12564
12457
  }
12565
12458
  if (!pipePositions.length) return;
12566
12459
  const alternativeBoundaries = [];
@@ -12851,14 +12744,11 @@ function* extractLazyEndQuantifiers(alternatives) {
12851
12744
  case "Group":
12852
12745
  yield* extractLazyEndQuantifiers(last.alternatives);
12853
12746
  break;
12854
- case "Quantifier":
12855
- if (!last.greedy && last.min !== last.max) yield last;
12856
- else if (last.max === 1) {
12857
- const element = last.element;
12858
- if (element.type === "Group" || element.type === "CapturingGroup") yield* extractLazyEndQuantifiers(element.alternatives);
12859
- }
12860
- break;
12861
- default: break;
12747
+ case "Quantifier": if (!last.greedy && last.min !== last.max) yield last;
12748
+ else if (last.max === 1) {
12749
+ const element = last.element;
12750
+ if (element.type === "Group" || element.type === "CapturingGroup") yield* extractLazyEndQuantifiers(element.alternatives);
12751
+ }
12862
12752
  }
12863
12753
  }
12864
12754
  }
@@ -13316,9 +13206,10 @@ function simplifyCharacterClass(pattern, charClass) {
13316
13206
  const elements = charClass.elements;
13317
13207
  const keptCharacters = /* @__PURE__ */ new Set();
13318
13208
  const rangesToKeep = [];
13319
- for (const element of elements) if (element.type === "Character") if (isLetter$1(element.value)) keptCharacters.add(toLowerCase(element.value));
13320
- else keptCharacters.add(element.value);
13321
- else if (element.type === "CharacterClassRange") {
13209
+ for (const element of elements) if (element.type === "Character") {
13210
+ if (isLetter$1(element.value)) keptCharacters.add(toLowerCase(element.value));
13211
+ else keptCharacters.add(element.value);
13212
+ } else if (element.type === "CharacterClassRange") {
13322
13213
  const min = element.min.value;
13323
13214
  const max = element.max.value;
13324
13215
  const minIsUpper = min >= 65 && min <= 90;
@@ -13587,9 +13478,7 @@ function checkPattern(pattern, flags) {
13587
13478
  checkHexadecimalEscape(charNode);
13588
13479
  break;
13589
13480
  case "unicode":
13590
- case "unicodeCodePoint":
13591
- checkUnicodeEscape(charNode);
13592
- break;
13481
+ case "unicodeCodePoint": checkUnicodeEscape(charNode);
13593
13482
  }
13594
13483
  }
13595
13484
  });
@@ -13685,9 +13574,7 @@ function escapeForRegexLiteral(pattern) {
13685
13574
  result += char;
13686
13575
  escaped = true;
13687
13576
  break;
13688
- default:
13689
- result += char;
13690
- break;
13577
+ default: result += char;
13691
13578
  }
13692
13579
  }
13693
13580
  return result;
@@ -13899,9 +13786,7 @@ function* extractInvalidQuantifiers(alternatives, kind) {
13899
13786
  case "Group":
13900
13787
  yield* extractInvalidQuantifiers(last.alternatives, kind);
13901
13788
  break;
13902
- case "Quantifier":
13903
- if (last.min !== last.max && !hasCapturingGroupDescendant(last.element)) yield last;
13904
- break;
13789
+ case "Quantifier": if (last.min !== last.max && !hasCapturingGroupDescendant(last.element)) yield last;
13905
13790
  }
13906
13791
  }
13907
13792
  }
@@ -14016,17 +13901,14 @@ function isMatchAnyCharacterClass(node, flags) {
14016
13901
  type: "CharacterSet"
14017
13902
  });
14018
13903
  break;
14019
- case "word":
14020
- if (element.negate) negativeElements.push({
14021
- kind: "word",
14022
- type: "CharacterSet"
14023
- });
14024
- else positiveElements.push({
14025
- kind: "word",
14026
- type: "CharacterSet"
14027
- });
14028
- break;
14029
- default: break;
13904
+ case "word": if (element.negate) negativeElements.push({
13905
+ kind: "word",
13906
+ type: "CharacterSet"
13907
+ });
13908
+ else positiveElements.push({
13909
+ kind: "word",
13910
+ type: "CharacterSet"
13911
+ });
14030
13912
  }
14031
13913
  else if (element.type === "CharacterClassRange" && element.min.value === 0 && (element.max.value === 65535 || element.max.value === 1114111 || flags.unicode && element.max.value >= 1114111)) return true;
14032
13914
  for (const positive of positiveElements) if (negativeElements.find((negative) => negative.kind === positive.kind)) return true;
@@ -14459,12 +14341,15 @@ function* findZeroWidthJoins(characters) {
14459
14341
  for (const [index, char] of characters.entries()) {
14460
14342
  const previous = characters[index - 1];
14461
14343
  const next = characters[index + 1];
14462
- if (previous && next && char.value === 8205 && previous.value !== 8205 && next.value !== 8205) if (sequence) if (sequence.at(-1) === previous) sequence.push(char, next);
14463
- else {
14464
- yield sequence;
14465
- sequence = characters.slice(index - 1, index + 2);
14344
+ if (previous && next && char.value === 8205 && previous.value !== 8205 && next.value !== 8205) {
14345
+ if (sequence) {
14346
+ if (sequence.at(-1) === previous) sequence.push(char, next);
14347
+ else {
14348
+ yield sequence;
14349
+ sequence = characters.slice(index - 1, index + 2);
14350
+ }
14351
+ } else sequence = characters.slice(index - 1, index + 2);
14466
14352
  }
14467
- else sequence = characters.slice(index - 1, index + 2);
14468
14353
  }
14469
14354
  if (sequence) yield sequence;
14470
14355
  }
@@ -14512,7 +14397,6 @@ function* iterateCharacterSequence(nodes) {
14512
14397
  sequence.push(node.min);
14513
14398
  yield sequence;
14514
14399
  sequence = [node.max];
14515
- break;
14516
14400
  }
14517
14401
  if (sequence.length) yield sequence;
14518
14402
  }
@@ -15927,9 +15811,7 @@ function findReachableQuantifiers(pattern) {
15927
15811
  case "Group":
15928
15812
  for (const innerAlternative of element.alternatives) walkAlternative(innerAlternative);
15929
15813
  break;
15930
- case "Quantifier":
15931
- if (element.max === Infinity && element.min === 0) quantifiers.push(element);
15932
- break;
15814
+ case "Quantifier": if (element.max === Infinity && element.min === 0) quantifiers.push(element);
15933
15815
  }
15934
15816
  if (!canMatchEmpty(element)) return;
15935
15817
  }
@@ -15948,19 +15830,15 @@ function generateAttackString(quantifier) {
15948
15830
  if (first.type === "Character") character = String.fromCharCode(first.value);
15949
15831
  break;
15950
15832
  }
15951
- case "CharacterSet":
15952
- switch (quantifier.element.kind) {
15953
- case "any":
15954
- character = "x";
15955
- break;
15956
- case "digit":
15957
- character = "0";
15958
- break;
15959
- case "space":
15960
- character = " ";
15961
- break;
15962
- }
15963
- break;
15833
+ case "CharacterSet": switch (quantifier.element.kind) {
15834
+ case "any":
15835
+ character = "x";
15836
+ break;
15837
+ case "digit":
15838
+ character = "0";
15839
+ break;
15840
+ case "space": character = " ";
15841
+ }
15964
15842
  }
15965
15843
  return (character ?? "a").repeat(20);
15966
15844
  }
@@ -17929,9 +17807,7 @@ function isOptionalAssertion(quantifierElement, assertion) {
17929
17807
  }
17930
17808
  }
17931
17809
  break;
17932
- case "Quantifier":
17933
- if (parent !== quantifierElement && parent.max > 1 && canConsumeCharacters(parent.element)) return false;
17934
- break;
17810
+ case "Quantifier": if (parent !== quantifierElement && parent.max > 1 && canConsumeCharacters(parent.element)) return false;
17935
17811
  }
17936
17812
  current = parent;
17937
17813
  }
@@ -20468,15 +20344,13 @@ var tsComments_default = ruleCreator.createRule(typescriptLanguage, {
20468
20344
  case true:
20469
20345
  reportCommentDirective(comment, directive, { directive }, "directiveComment", "preferExpectError");
20470
20346
  return;
20471
- default:
20472
- if (typeof config === "object" && config.descriptionFormat) {
20473
- const format = descriptionFormats.get(directive);
20474
- if (format && !format.test(description)) reportCommentDirective(comment, directive, {
20475
- directive,
20476
- format: format.source
20477
- }, "descriptionNotMatchPattern");
20478
- }
20479
- break;
20347
+ default: if (typeof config === "object" && config.descriptionFormat) {
20348
+ const format = descriptionFormats.get(directive);
20349
+ if (format && !format.test(description)) reportCommentDirective(comment, directive, {
20350
+ directive,
20351
+ format: format.source
20352
+ }, "descriptionNotMatchPattern");
20353
+ }
20480
20354
  }
20481
20355
  }
20482
20356
  } } };
@@ -20558,13 +20432,18 @@ function getImportSpecifiers(node) {
20558
20432
  const specifiers = [];
20559
20433
  if (importClause.name) specifiers.push(importClause.name);
20560
20434
  const namedBindings = importClause.namedBindings;
20561
- if (namedBindings) if (namedBindings.kind === SyntaxKind.NamespaceImport) specifiers.push(namedBindings);
20562
- else specifiers.push(...namedBindings.elements);
20435
+ if (namedBindings) {
20436
+ if (namedBindings.kind === SyntaxKind.NamespaceImport) specifiers.push(namedBindings);
20437
+ else specifiers.push(...namedBindings.elements);
20438
+ }
20563
20439
  return specifiers;
20564
20440
  }
20565
20441
  function getReferencedSymbol(typeChecker, node) {
20566
- const symbol = typeChecker.getSymbolAtLocation(node);
20567
- return symbol?.flags && (symbol.flags & ts$1.SymbolFlags.Alias) !== 0 ? typeChecker.getAliasedSymbol(symbol) : symbol;
20442
+ let symbol;
20443
+ const parent = node.parent;
20444
+ if (isShorthandPropertyAssignment(parent)) symbol = typeChecker.getShorthandAssignmentValueSymbol(parent);
20445
+ else symbol = typeChecker.getSymbolAtLocation(node);
20446
+ return symbol?.flags && (symbol.flags & SymbolFlags.Alias) !== 0 ? typeChecker.getAliasedSymbol(symbol) : symbol;
20568
20447
  }
20569
20448
  function getSpecifierLocal(specifier) {
20570
20449
  return specifier.kind === SyntaxKind.Identifier ? specifier : specifier.name;
@@ -20629,8 +20508,8 @@ function isOnlyTypeReference(node) {
20629
20508
  let parent = node.parent;
20630
20509
  while (parent) {
20631
20510
  if (parent.kind === SyntaxKind.HeritageClause) return parent.token === SyntaxKind.ImplementsKeyword;
20632
- if (parent.kind === SyntaxKind.TypeAliasDeclaration || parent.kind === SyntaxKind.InterfaceDeclaration || ts$1.isTypeParameterDeclaration(parent)) return true;
20633
- if (ts$1.isTypeNode(parent) && !ts$1.isExpressionWithTypeArguments(parent)) return true;
20511
+ if (parent.kind === SyntaxKind.TypeAliasDeclaration || parent.kind === SyntaxKind.InterfaceDeclaration || isTypeParameterDeclaration(parent)) return true;
20512
+ if (isTypeNode(parent) && !isExpressionWithTypeArguments(parent)) return true;
20634
20513
  current = parent;
20635
20514
  parent = current.parent;
20636
20515
  }
@@ -22292,7 +22171,6 @@ const ts = createPlugin({
22292
22171
  namedDefaultExports_default,
22293
22172
  namespaceDeclarations_default,
22294
22173
  namespaceImplicitAmbientImports_default,
22295
- namespaceKeywords_default,
22296
22174
  nativeObjectExtensions_default,
22297
22175
  negativeIndexLengthMethods_default,
22298
22176
  negativeZeroComparisons_default,
@@ -22324,7 +22202,6 @@ const ts = createPlugin({
22324
22202
  objectSpreadUnnecessaryFallbacks_default,
22325
22203
  objectTypeDefinitions_default,
22326
22204
  octalEscapes_default,
22327
- octalNumbers_default,
22328
22205
  operatorAssignmentShorthand_default,
22329
22206
  overloadSignaturesAdjacent_default,
22330
22207
  parameterReassignments_default,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flint.fyi/ts",
3
- "version": "0.23.0",
3
+ "version": "0.23.2",
4
4
  "description": "[Experimental] TypeScript language plugin for Flint.",
5
5
  "homepage": "https://flint.fyi/rules/ts",
6
6
  "repository": {
@@ -23,20 +23,20 @@
23
23
  ],
24
24
  "dependencies": {
25
25
  "@eslint-community/regexpp": "^4.12.2",
26
+ "@flint.fyi/core": "^0.26.0",
27
+ "@flint.fyi/typescript-language": "^0.20.1",
28
+ "@flint.fyi/utils": "^0.16.0",
26
29
  "regexp-ast-analysis": "^0.7.1",
27
30
  "scslre": "^0.3.0",
28
31
  "ts-api-utils": "^2.4.0",
29
32
  "typescript": "^6.0.0",
30
- "zod": "^4.3.6",
31
- "@flint.fyi/typescript-language": "^0.20.0",
32
- "@flint.fyi/core": "^0.25.0",
33
- "@flint.fyi/utils": "^0.16.0"
33
+ "zod": "^4.3.6"
34
34
  },
35
35
  "devDependencies": {
36
- "tsdown": "0.22.3",
37
- "vitest": "4.1.0",
38
36
  "@flint.fyi/build": "^0.1.0",
39
- "@flint.fyi/rule-tester": "^0.18.0"
37
+ "@flint.fyi/rule-tester": "^0.19.1",
38
+ "tsdown": "0.22.14",
39
+ "vitest": "4.1.11"
40
40
  },
41
41
  "engines": {
42
42
  "node": ">=26.1.0"