@flint.fyi/ts 0.22.0 → 0.23.1
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 +13 -94
- package/package.json +7 -7
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";
|
|
@@ -1690,13 +1690,14 @@ function isDirectEqualityCheck(node, operators, parameterName) {
|
|
|
1690
1690
|
body = getDirectReturnExpression(node.body);
|
|
1691
1691
|
break;
|
|
1692
1692
|
}
|
|
1693
|
-
if (body?.kind !== SyntaxKind.BinaryExpression) return;
|
|
1693
|
+
if (body?.kind !== SyntaxKind.BinaryExpression) return false;
|
|
1694
1694
|
const { left, operatorToken, right } = body;
|
|
1695
|
-
if (!operators.includes(operatorToken.kind)) return;
|
|
1695
|
+
if (!operators.includes(operatorToken.kind)) return false;
|
|
1696
1696
|
const isLeftParam = left.kind === SyntaxKind.Identifier && left.text === parameterName;
|
|
1697
1697
|
const isRightParam = right.kind === SyntaxKind.Identifier && right.text === parameterName;
|
|
1698
|
-
if (isLeftParam && !isRightParam) return
|
|
1699
|
-
if (isRightParam && !isLeftParam) return
|
|
1698
|
+
if (isLeftParam && !isRightParam) return true;
|
|
1699
|
+
if (isRightParam && !isLeftParam) return true;
|
|
1700
|
+
return false;
|
|
1700
1701
|
}
|
|
1701
1702
|
function getDirectReturnExpression(body) {
|
|
1702
1703
|
if (body.statements.length !== 1) return;
|
|
@@ -7743,40 +7744,6 @@ var namespaceImplicitAmbientImports_default = ruleCreator.createRule(typescriptL
|
|
|
7743
7744
|
}
|
|
7744
7745
|
});
|
|
7745
7746
|
//#endregion
|
|
7746
|
-
//#region src/rules/namespaceKeywords.ts
|
|
7747
|
-
var namespaceKeywords_default = ruleCreator.createRule(typescriptLanguage, {
|
|
7748
|
-
about: {
|
|
7749
|
-
description: "Reports using `module` keyword instead of `namespace` for TypeScript namespaces.",
|
|
7750
|
-
id: "namespaceKeywords",
|
|
7751
|
-
presets: ["stylistic", "stylisticStrict"]
|
|
7752
|
-
},
|
|
7753
|
-
messages: { preferNamespace: {
|
|
7754
|
-
primary: "The `namespace` keyword is preferred over `module` for TypeScript namespaces.",
|
|
7755
|
-
secondary: [
|
|
7756
|
-
"TypeScript originally used the `module` keyword to declare internal modules (namespaces).",
|
|
7757
|
-
"The `namespace` keyword was later introduced to avoid confusion with ES6 modules.",
|
|
7758
|
-
"Using `namespace` makes it clear you are defining a TypeScript namespace, not an ES6 module."
|
|
7759
|
-
],
|
|
7760
|
-
suggestions: ["Replace `module` with `namespace`."]
|
|
7761
|
-
} },
|
|
7762
|
-
setup(context) {
|
|
7763
|
-
return { visitors: { ModuleDeclaration: (node, { sourceFile }) => {
|
|
7764
|
-
if (node.name.kind === SyntaxKind.StringLiteral) return;
|
|
7765
|
-
const moduleKeywordToken = node.getChildren(sourceFile).find((child) => child.kind === SyntaxKind.ModuleKeyword);
|
|
7766
|
-
if (!moduleKeywordToken) return;
|
|
7767
|
-
const range = getTSNodeRange(moduleKeywordToken, sourceFile);
|
|
7768
|
-
context.report({
|
|
7769
|
-
fix: {
|
|
7770
|
-
range,
|
|
7771
|
-
text: "namespace"
|
|
7772
|
-
},
|
|
7773
|
-
message: "preferNamespace",
|
|
7774
|
-
range
|
|
7775
|
-
});
|
|
7776
|
-
} } };
|
|
7777
|
-
}
|
|
7778
|
-
});
|
|
7779
|
-
//#endregion
|
|
7780
7747
|
//#region src/rules/nativeObjectExtensions.ts
|
|
7781
7748
|
const nativeConstructors = /* @__PURE__ */ new Set([
|
|
7782
7749
|
"AggregateError",
|
|
@@ -10082,55 +10049,6 @@ var octalEscapes_default = ruleCreator.createRule(typescriptLanguage, {
|
|
|
10082
10049
|
}
|
|
10083
10050
|
});
|
|
10084
10051
|
//#endregion
|
|
10085
|
-
//#region src/rules/octalNumbers.ts
|
|
10086
|
-
var octalNumbers_default = ruleCreator.createRule(typescriptLanguage, {
|
|
10087
|
-
about: {
|
|
10088
|
-
description: "Reports using legacy octal numeric literals.",
|
|
10089
|
-
id: "octalNumbers",
|
|
10090
|
-
presets: ["javascript"]
|
|
10091
|
-
},
|
|
10092
|
-
messages: { noOctalNumber: {
|
|
10093
|
-
primary: "This legacy octal numeric literal evaluates to {{ raw }}. Did you mean that value, or to use a modern octal syntax such as {{ equivalent }}?",
|
|
10094
|
-
secondary: [
|
|
10095
|
-
"Legacy octal numeric literals (e.g., `077`, `0123`) are a deprecated feature in JavaScript that can lead to confusion and errors.",
|
|
10096
|
-
"They are forbidden in strict mode and are less readable than their modern alternatives.",
|
|
10097
|
-
"The digit `0` by itself is allowed as it represents zero, not an octal literal."
|
|
10098
|
-
],
|
|
10099
|
-
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."]
|
|
10100
|
-
} },
|
|
10101
|
-
setup(context) {
|
|
10102
|
-
return { visitors: { NumericLiteral: (node, { sourceFile }) => {
|
|
10103
|
-
const text = node.getText(sourceFile);
|
|
10104
|
-
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)) {
|
|
10105
|
-
const range = {
|
|
10106
|
-
begin: node.getStart(sourceFile),
|
|
10107
|
-
end: node.getEnd()
|
|
10108
|
-
};
|
|
10109
|
-
const octalValue = parseInt(text, 8);
|
|
10110
|
-
const modernOctalSyntax = `0o${text.slice(1)}`;
|
|
10111
|
-
const decimalWithoutLeadingZero = text.slice(1);
|
|
10112
|
-
context.report({
|
|
10113
|
-
data: {
|
|
10114
|
-
equivalent: modernOctalSyntax,
|
|
10115
|
-
raw: octalValue.toString()
|
|
10116
|
-
},
|
|
10117
|
-
message: "noOctalNumber",
|
|
10118
|
-
range,
|
|
10119
|
-
suggestions: [{
|
|
10120
|
-
id: "useModernOctalSyntax",
|
|
10121
|
-
range,
|
|
10122
|
-
text: modernOctalSyntax
|
|
10123
|
-
}, {
|
|
10124
|
-
id: "removeLeadingZero",
|
|
10125
|
-
range,
|
|
10126
|
-
text: decimalWithoutLeadingZero
|
|
10127
|
-
}]
|
|
10128
|
-
});
|
|
10129
|
-
}
|
|
10130
|
-
} } };
|
|
10131
|
-
}
|
|
10132
|
-
});
|
|
10133
|
-
//#endregion
|
|
10134
10052
|
//#region src/rules/operatorAssignmentShorthand.ts
|
|
10135
10053
|
const operatorTexts = /* @__PURE__ */ new Map([
|
|
10136
10054
|
[SyntaxKind.AmpersandToken, "&"],
|
|
@@ -20562,8 +20480,11 @@ function getImportSpecifiers(node) {
|
|
|
20562
20480
|
return specifiers;
|
|
20563
20481
|
}
|
|
20564
20482
|
function getReferencedSymbol(typeChecker, node) {
|
|
20565
|
-
|
|
20566
|
-
|
|
20483
|
+
let symbol;
|
|
20484
|
+
const parent = node.parent;
|
|
20485
|
+
if (isShorthandPropertyAssignment(parent)) symbol = typeChecker.getShorthandAssignmentValueSymbol(parent);
|
|
20486
|
+
else symbol = typeChecker.getSymbolAtLocation(node);
|
|
20487
|
+
return symbol?.flags && (symbol.flags & SymbolFlags.Alias) !== 0 ? typeChecker.getAliasedSymbol(symbol) : symbol;
|
|
20567
20488
|
}
|
|
20568
20489
|
function getSpecifierLocal(specifier) {
|
|
20569
20490
|
return specifier.kind === SyntaxKind.Identifier ? specifier : specifier.name;
|
|
@@ -20628,8 +20549,8 @@ function isOnlyTypeReference(node) {
|
|
|
20628
20549
|
let parent = node.parent;
|
|
20629
20550
|
while (parent) {
|
|
20630
20551
|
if (parent.kind === SyntaxKind.HeritageClause) return parent.token === SyntaxKind.ImplementsKeyword;
|
|
20631
|
-
if (parent.kind === SyntaxKind.TypeAliasDeclaration || parent.kind === SyntaxKind.InterfaceDeclaration ||
|
|
20632
|
-
if (
|
|
20552
|
+
if (parent.kind === SyntaxKind.TypeAliasDeclaration || parent.kind === SyntaxKind.InterfaceDeclaration || isTypeParameterDeclaration(parent)) return true;
|
|
20553
|
+
if (isTypeNode(parent) && !isExpressionWithTypeArguments(parent)) return true;
|
|
20633
20554
|
current = parent;
|
|
20634
20555
|
parent = current.parent;
|
|
20635
20556
|
}
|
|
@@ -22291,7 +22212,6 @@ const ts = createPlugin({
|
|
|
22291
22212
|
namedDefaultExports_default,
|
|
22292
22213
|
namespaceDeclarations_default,
|
|
22293
22214
|
namespaceImplicitAmbientImports_default,
|
|
22294
|
-
namespaceKeywords_default,
|
|
22295
22215
|
nativeObjectExtensions_default,
|
|
22296
22216
|
negativeIndexLengthMethods_default,
|
|
22297
22217
|
negativeZeroComparisons_default,
|
|
@@ -22323,7 +22243,6 @@ const ts = createPlugin({
|
|
|
22323
22243
|
objectSpreadUnnecessaryFallbacks_default,
|
|
22324
22244
|
objectTypeDefinitions_default,
|
|
22325
22245
|
octalEscapes_default,
|
|
22326
|
-
octalNumbers_default,
|
|
22327
22246
|
operatorAssignmentShorthand_default,
|
|
22328
22247
|
overloadSignaturesAdjacent_default,
|
|
22329
22248
|
parameterReassignments_default,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flint.fyi/ts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.1",
|
|
4
4
|
"description": "[Experimental] TypeScript language plugin for Flint.",
|
|
5
5
|
"homepage": "https://flint.fyi/rules/ts",
|
|
6
6
|
"repository": {
|
|
@@ -28,18 +28,18 @@
|
|
|
28
28
|
"ts-api-utils": "^2.4.0",
|
|
29
29
|
"typescript": "^6.0.0",
|
|
30
30
|
"zod": "^4.3.6",
|
|
31
|
-
"@flint.fyi/
|
|
32
|
-
"@flint.fyi/
|
|
33
|
-
"@flint.fyi/
|
|
31
|
+
"@flint.fyi/core": "^0.25.0",
|
|
32
|
+
"@flint.fyi/utils": "^0.16.0",
|
|
33
|
+
"@flint.fyi/typescript-language": "^0.20.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"tsdown": "0.22.3",
|
|
37
37
|
"vitest": "4.1.0",
|
|
38
|
-
"@flint.fyi/
|
|
39
|
-
"@flint.fyi/
|
|
38
|
+
"@flint.fyi/rule-tester": "^0.19.0",
|
|
39
|
+
"@flint.fyi/build": "^0.1.0"
|
|
40
40
|
},
|
|
41
41
|
"engines": {
|
|
42
|
-
"node": ">=
|
|
42
|
+
"node": ">=26.1.0"
|
|
43
43
|
},
|
|
44
44
|
"publishConfig": {
|
|
45
45
|
"access": "public"
|