@ls-stack/fast-lint 0.4.0 → 0.5.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 +149 -2
- package/dist/darwin-arm64/fast-lint +0 -0
- package/dist/darwin-x64/fast-lint +0 -0
- package/dist/linux-arm64/fast-lint +0 -0
- package/dist/linux-x64/fast-lint +0 -0
- package/dist/win32-x64/fast-lint.exe +0 -0
- package/lib/index.d.ts +28 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Type-aware lint rules running natively on [tsrs](https://github.com/maschwenk/tsrs), the Rust port of the TypeScript 7
|
|
4
4
|
checker, through [tsrslint](https://github.com/maschwenk/tsrslint)'s rule framework. No ESLint, no Node type checker:
|
|
5
|
-
only these rules run, against one shared program per tsconfig.
|
|
6
|
-
|
|
5
|
+
only these rules run, against one shared program per tsconfig. It replaces the `@ls-stack/extended-lint` ESLint
|
|
6
|
+
plugin, whose rules were all moved here or removed.
|
|
7
7
|
|
|
8
8
|
## Rules
|
|
9
9
|
|
|
@@ -47,6 +47,11 @@ only these rules run, against one shared program per tsconfig. Type-aware rules
|
|
|
47
47
|
| `sort-react-components-and-styles` | moved from `@ls-stack/extended-lint` (see below) |
|
|
48
48
|
| `use-types-directly-above-usage` | moved from `@ls-stack/extended-lint` (see below) |
|
|
49
49
|
| `react-compiler-extra` | moved from `@ls-stack/extended-lint` (see below) |
|
|
50
|
+
| `no-restricted-comments` | moved from `@ls-stack/extended-lint` (see below) |
|
|
51
|
+
| `require-usage-explanation` | moved from `@ls-stack/extended-lint` (see below) |
|
|
52
|
+
| `use-top-level-regex` | moved from `@ls-stack/extended-lint` (see below) |
|
|
53
|
+
| `no-unused-obj-props` | moved from `@ls-stack/extended-lint`, stricter (see below) |
|
|
54
|
+
| `require-type-guard-explanation` | new, a stricter alternative to `no-type-guards` (see below) |
|
|
50
55
|
|
|
51
56
|
Options are the same as the former ESLint rules' (see `lib/index.d.ts`). Rule names may carry a plugin prefix, so
|
|
52
57
|
existing `@ls-stack/strict-casting` configs and disable comments keep working.
|
|
@@ -697,6 +702,148 @@ type Options = [
|
|
|
697
702
|
]
|
|
698
703
|
```
|
|
699
704
|
|
|
705
|
+
### `no-restricted-comments`
|
|
706
|
+
|
|
707
|
+
Disallows comments matching configured patterns:
|
|
708
|
+
|
|
709
|
+
- each pattern matches the comment text (without `//` or `/* */`) by `regex` or, without one, by `includes`
|
|
710
|
+
- a comment is reported once, for the first pattern it matches, with the pattern's `message` or
|
|
711
|
+
`Comment matches restricted pattern '<pattern>'`
|
|
712
|
+
- the comment's removal is offered as a suggestion, or applied as an autofix with `autoFix: true`
|
|
713
|
+
|
|
714
|
+
```ts
|
|
715
|
+
type Options = [
|
|
716
|
+
{
|
|
717
|
+
patterns: {
|
|
718
|
+
/** Rust `regex` syntax (no lookarounds or backreferences) */
|
|
719
|
+
regex?: string
|
|
720
|
+
includes?: string
|
|
721
|
+
/** Replaces the default message */
|
|
722
|
+
message?: string
|
|
723
|
+
/** Remove the comment as an autofix instead of a suggestion (default: false) */
|
|
724
|
+
autoFix?: boolean
|
|
725
|
+
}[]
|
|
726
|
+
},
|
|
727
|
+
]
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
### `require-usage-explanation`
|
|
731
|
+
|
|
732
|
+
Requires an explanatory comment with a given prefix above matched code:
|
|
733
|
+
|
|
734
|
+
- calls of a function (`fn`, matching `name()` and `obj.name()`) or nodes matching an ESQuery `selector`
|
|
735
|
+
- the comment can be right before the matched node or before any of its ancestors up to the statement holding it
|
|
736
|
+
(e.g. above the `const` or `return` statement, or inside a ternary branch, array or argument list)
|
|
737
|
+
- the comment must start with `commentPrefix` and have some text after it (`// WORKAROUND:` alone doesn't count)
|
|
738
|
+
|
|
739
|
+
```ts
|
|
740
|
+
type Options = [
|
|
741
|
+
{
|
|
742
|
+
matches: {
|
|
743
|
+
/** Name of the function whose calls need an explanation */
|
|
744
|
+
fn?: string
|
|
745
|
+
/** ESQuery selector of the nodes that need an explanation */
|
|
746
|
+
selector?: string
|
|
747
|
+
/** Prefix the explanation comment must start with, e.g. `WORKAROUND:` */
|
|
748
|
+
commentPrefix: string
|
|
749
|
+
/** Text appended to the error message */
|
|
750
|
+
message?: string
|
|
751
|
+
}[]
|
|
752
|
+
},
|
|
753
|
+
]
|
|
754
|
+
```
|
|
755
|
+
|
|
756
|
+
### `use-top-level-regex`
|
|
757
|
+
|
|
758
|
+
Requires regex literals to be declared at the top level, so functions don't create a new `RegExp` object on each call.
|
|
759
|
+
|
|
760
|
+
- regex literals inside functions, arrow functions and methods (including their default parameters) are reported
|
|
761
|
+
- regexes with the stateful `g` or `y` flags are allowed, since hoisting them would share `lastIndex` between calls
|
|
762
|
+
- regexes passed directly to `new RegExp(...)` are allowed
|
|
763
|
+
|
|
764
|
+
```ts
|
|
765
|
+
const WORD = /\w+/ // ok
|
|
766
|
+
|
|
767
|
+
function isWord(input: string) {
|
|
768
|
+
return /\w+/.test(input) // Error: move it to the top level
|
|
769
|
+
}
|
|
770
|
+
```
|
|
771
|
+
|
|
772
|
+
No options.
|
|
773
|
+
|
|
774
|
+
### `no-unused-obj-props`
|
|
775
|
+
|
|
776
|
+
Reports object literal properties that are never read:
|
|
777
|
+
|
|
778
|
+
- properties of a non-exported `const`/`let` initialized with an object literal (`as const` included) that no
|
|
779
|
+
`obj.key`, `obj['key']`, literal-typed `obj[key]`, destructuring or JSX `<obj.Key />` reads
|
|
780
|
+
(`unusedObjectProperty`); a property that is only assigned (`obj.key = value`) is reported too
|
|
781
|
+
- properties of the objects a non-exported local function returns that none of its callers read, when every call
|
|
782
|
+
initializes a variable (`const { a } = useThing()` or `const thing = useThing()` followed by property reads)
|
|
783
|
+
(`unusedReturnObjectProperty`)
|
|
784
|
+
|
|
785
|
+
The object is skipped whenever it escapes: spread, passed or returned, aliased, enumerated (`in`, `Object.keys`,
|
|
786
|
+
`for...in`), typed with `typeof`, exported, reassigned, read with a non-literal key, or when one of its methods,
|
|
787
|
+
accessors or function values uses `this`. Accessors, spreads, `__proto__` and dynamic computed keys are never
|
|
788
|
+
reported. Typed declarations, `satisfies` and other assertions are skipped.
|
|
789
|
+
|
|
790
|
+
```ts
|
|
791
|
+
const config = { retries: 3, timeout: 100 }
|
|
792
|
+
fetchWithRetries(config.retries) // Error: "timeout" is not being used
|
|
793
|
+
|
|
794
|
+
function useForm() {
|
|
795
|
+
return { values, errors, reset } // Error: "reset" is not used by any caller
|
|
796
|
+
}
|
|
797
|
+
const { values, errors } = useForm()
|
|
798
|
+
```
|
|
799
|
+
|
|
800
|
+
No options.
|
|
801
|
+
|
|
802
|
+
### `require-type-guard-explanation`
|
|
803
|
+
|
|
804
|
+
A stricter alternative to `no-type-guards`: TypeScript doesn't check type guards, so each one must explain why it is
|
|
805
|
+
safe and why TS inference or an alternative can't be used.
|
|
806
|
+
|
|
807
|
+
- every function with a body whose return type is `x is T`, `this is T` or `asserts x is T` (declarations, function
|
|
808
|
+
expressions, arrows, object and class methods, inline callbacks like `.filter((x): x is T => ...)`) needs a
|
|
809
|
+
comment starting with `commentPrefix` and at least `minLength` characters of explanation (`missingExplanation`)
|
|
810
|
+
- the comment goes right before the function or before the statement, `export`, class member or object property
|
|
811
|
+
holding it; consecutive `//` lines form one block, and block/JSDoc comments count too
|
|
812
|
+
- an explicit predicate TypeScript (5.5+) would infer identically is reported even with a comment, with a suggestion
|
|
813
|
+
to remove the annotation (`inferablePredicate`); only null/undefined and `typeof` checks it is sure about are
|
|
814
|
+
reported
|
|
815
|
+
- body-less signatures (overloads, `declare function`, interface members, function types) and `asserts x` are ignored
|
|
816
|
+
|
|
817
|
+
```ts
|
|
818
|
+
// Error: missingExplanation
|
|
819
|
+
function isNode(value: unknown): value is Node {
|
|
820
|
+
return isObject(value) && 'kind' in value
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// ok
|
|
824
|
+
// type-guard-safety: values come from our serializer, which always sets `kind`; a zod schema would parse every
|
|
825
|
+
// render
|
|
826
|
+
function isNode(value: unknown): value is Node {
|
|
827
|
+
return isObject(value) && 'kind' in value
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
// Error: inferablePredicate, TS infers `value is null | undefined`
|
|
831
|
+
function isNullish(value: unknown): value is null | undefined {
|
|
832
|
+
return value === null || value === undefined
|
|
833
|
+
}
|
|
834
|
+
```
|
|
835
|
+
|
|
836
|
+
```ts
|
|
837
|
+
type Options = [
|
|
838
|
+
{
|
|
839
|
+
/** Prefix the explanation comment must start with (default: `type-guard-safety:`) */
|
|
840
|
+
commentPrefix?: string
|
|
841
|
+
/** Minimum characters of explanation after the prefix (default: 20) */
|
|
842
|
+
minLength?: number
|
|
843
|
+
},
|
|
844
|
+
]
|
|
845
|
+
```
|
|
846
|
+
|
|
700
847
|
## Usage
|
|
701
848
|
|
|
702
849
|
```sh
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/linux-x64/fast-lint
CHANGED
|
Binary file
|
|
Binary file
|
package/lib/index.d.ts
CHANGED
|
@@ -208,6 +208,29 @@ export type ReactCompilerExtraOptions = {
|
|
|
208
208
|
disallowManualMemoization?: boolean
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
+
export type NoRestrictedCommentsOptions = {
|
|
212
|
+
patterns: {
|
|
213
|
+
regex?: string
|
|
214
|
+
includes?: string
|
|
215
|
+
message?: string
|
|
216
|
+
autoFix?: boolean
|
|
217
|
+
}[]
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export type RequireTypeGuardExplanationOptions = {
|
|
221
|
+
commentPrefix?: string
|
|
222
|
+
minLength?: number
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export type RequireUsageExplanationOptions = {
|
|
226
|
+
matches: {
|
|
227
|
+
fn?: string
|
|
228
|
+
selector?: string
|
|
229
|
+
commentPrefix: string
|
|
230
|
+
message?: string
|
|
231
|
+
}[]
|
|
232
|
+
}
|
|
233
|
+
|
|
211
234
|
type RuleOptions = {
|
|
212
235
|
'improved-no-unnecessary-condition': ImprovedNoUnnecessaryConditionOptions
|
|
213
236
|
'strict-casting': StrictCastingOptions
|
|
@@ -248,6 +271,11 @@ type RuleOptions = {
|
|
|
248
271
|
'sort-react-components-and-styles': SortReactComponentsAndStylesOptions
|
|
249
272
|
'use-types-directly-above-usage': UseTypesDirectlyAboveUsageOptions
|
|
250
273
|
'react-compiler-extra': ReactCompilerExtraOptions
|
|
274
|
+
'no-restricted-comments': NoRestrictedCommentsOptions
|
|
275
|
+
'require-usage-explanation': RequireUsageExplanationOptions
|
|
276
|
+
'use-top-level-regex': Record<string, never>
|
|
277
|
+
'no-unused-obj-props': Record<string, never>
|
|
278
|
+
'require-type-guard-explanation': RequireTypeGuardExplanationOptions
|
|
251
279
|
}
|
|
252
280
|
|
|
253
281
|
export type RulesConfig = {
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ls-stack/fast-lint",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "Fast type-aware lint rules for TypeScript and React, running natively on tsrs, the Rust port of the TypeScript checker",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
8
|
"fast-lint": "./bin/fast-lint.mjs"
|