@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 +0 -14
- package/dist/index.mjs +101 -224
- package/package.json +8 -8
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
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
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
|
-
|
|
8643
|
-
|
|
8644
|
-
|
|
8645
|
-
|
|
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
|
-
|
|
9293
|
-
|
|
9294
|
-
|
|
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
|
-
|
|
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")
|
|
12190
|
-
|
|
12191
|
-
|
|
12192
|
-
|
|
12193
|
-
|
|
12194
|
-
|
|
12195
|
-
|
|
12196
|
-
min
|
|
12197
|
-
|
|
12198
|
-
|
|
12199
|
-
|
|
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)))
|
|
12543
|
-
|
|
12544
|
-
|
|
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
|
-
|
|
12856
|
-
|
|
12857
|
-
|
|
12858
|
-
|
|
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")
|
|
13320
|
-
|
|
13321
|
-
|
|
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
|
-
|
|
14021
|
-
|
|
14022
|
-
|
|
14023
|
-
|
|
14024
|
-
|
|
14025
|
-
|
|
14026
|
-
|
|
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)
|
|
14463
|
-
|
|
14464
|
-
|
|
14465
|
-
|
|
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
|
-
|
|
15953
|
-
|
|
15954
|
-
|
|
15955
|
-
|
|
15956
|
-
|
|
15957
|
-
|
|
15958
|
-
|
|
15959
|
-
|
|
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
|
-
|
|
20473
|
-
|
|
20474
|
-
|
|
20475
|
-
|
|
20476
|
-
|
|
20477
|
-
|
|
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)
|
|
20562
|
-
|
|
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
|
-
|
|
20567
|
-
|
|
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 ||
|
|
20633
|
-
if (
|
|
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.
|
|
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.
|
|
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"
|