@ttsc/lint 0.25.0 → 0.26.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 +1 -1
- package/lib/structures/rules/ITtscLintFunctionalRuleOptions.d.ts +73 -16
- package/linthost/config_format.go +7 -0
- package/linthost/directives.go +4 -7
- package/linthost/fix.go +6 -4
- package/linthost/rule_codes.json +1 -0
- package/linthost/rules_format_brace_continuation.go +267 -0
- package/linthost/rules_format_clause_join.go +289 -40
- package/linthost/rules_format_parameter_properties.go +9 -21
- package/linthost/rules_format_whitespace.go +5 -1
- package/linthost/rules_functional.go +248 -25
- package/linthost/rules_ts_extra.go +7 -5
- package/package.json +2 -2
- package/rule/rule.go +21 -9
- package/src/structures/rules/ITtscLintFunctionalRuleOptions.ts +73 -16
|
@@ -143,6 +143,34 @@ type functionalNoTryOptions struct {
|
|
|
143
143
|
AllowFinally bool `json:"allowFinally"`
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
+
// functionalNoMixedTypesOptions gates the two container kinds the rule visits.
|
|
147
|
+
// Both default to true (an absent key leaves the container checked), so the
|
|
148
|
+
// pointers distinguish "not configured" from an explicit false.
|
|
149
|
+
type functionalNoMixedTypesOptions struct {
|
|
150
|
+
CheckInterfaces *bool `json:"checkInterfaces"`
|
|
151
|
+
CheckTypeLiterals *bool `json:"checkTypeLiterals"`
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// functionalNoReturnVoidOptions narrows what counts as a rejected return.
|
|
155
|
+
//
|
|
156
|
+
// `allowNull` and `allowUndefined` default to true, matching the rule's
|
|
157
|
+
// existing behavior: only a declared `void` return type is rejected. Setting
|
|
158
|
+
// either to false extends the rejection to that declared return type.
|
|
159
|
+
// `ignoreInferredTypes` defaults to false and, when true, spares a bare
|
|
160
|
+
// `return;` whose enclosing function declares no return type, which is the one
|
|
161
|
+
// place the rule reports a void-ness it inferred rather than read.
|
|
162
|
+
type functionalNoReturnVoidOptions struct {
|
|
163
|
+
AllowNull *bool `json:"allowNull"`
|
|
164
|
+
AllowUndefined *bool `json:"allowUndefined"`
|
|
165
|
+
IgnoreInferredTypes bool `json:"ignoreInferredTypes"`
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// functionalPreferTacitOptions gates the member-expression callee shape.
|
|
169
|
+
// Defaults to true, keeping `x => service.handler(x)` reported as before.
|
|
170
|
+
type functionalPreferTacitOptions struct {
|
|
171
|
+
CheckMemberExpressions *bool `json:"checkMemberExpressions"`
|
|
172
|
+
}
|
|
173
|
+
|
|
146
174
|
type functionalImmutableDataOptions struct {
|
|
147
175
|
functionalPatternOptions
|
|
148
176
|
IgnoreMapsAndSets bool `json:"ignoreMapsAndSets"`
|
|
@@ -159,8 +187,15 @@ type functionalPreferImmutableTypesOptions struct {
|
|
|
159
187
|
functionalPatternOptions
|
|
160
188
|
}
|
|
161
189
|
|
|
190
|
+
// functionalPreferReadonlyTypeOptions narrows which positions the rule polices.
|
|
191
|
+
// Both gates default to off, so an absent key leaves every visited position
|
|
192
|
+
// checked exactly as before.
|
|
162
193
|
type functionalPreferReadonlyTypeOptions struct {
|
|
163
194
|
functionalPatternOptions
|
|
195
|
+
AllowMutableReturnType bool `json:"allowMutableReturnType"`
|
|
196
|
+
IgnoreClass interface{} `json:"ignoreClass"`
|
|
197
|
+
IgnoreCollections bool `json:"ignoreCollections"`
|
|
198
|
+
IgnoreInterface bool `json:"ignoreInterface"`
|
|
164
199
|
}
|
|
165
200
|
|
|
166
201
|
type functionalReadonlyTypeOptions struct {
|
|
@@ -332,6 +367,18 @@ func (functionalNoLoopStatements) Check(ctx *Context, node *shimast.Node) {
|
|
|
332
367
|
}
|
|
333
368
|
|
|
334
369
|
func (functionalNoMixedTypes) Check(ctx *Context, node *shimast.Node) {
|
|
370
|
+
var opts functionalNoMixedTypesOptions
|
|
371
|
+
_ = ctx.DecodeOptions(&opts)
|
|
372
|
+
switch node.Kind {
|
|
373
|
+
case shimast.KindInterfaceDeclaration:
|
|
374
|
+
if opts.CheckInterfaces != nil && !*opts.CheckInterfaces {
|
|
375
|
+
return
|
|
376
|
+
}
|
|
377
|
+
case shimast.KindTypeLiteral:
|
|
378
|
+
if opts.CheckTypeLiterals != nil && !*opts.CheckTypeLiterals {
|
|
379
|
+
return
|
|
380
|
+
}
|
|
381
|
+
}
|
|
335
382
|
members := containerMembers(node)
|
|
336
383
|
if len(members) < 2 {
|
|
337
384
|
return
|
|
@@ -361,16 +408,51 @@ func (functionalNoPromiseReject) Check(ctx *Context, node *shimast.Node) {
|
|
|
361
408
|
}
|
|
362
409
|
|
|
363
410
|
func (functionalNoReturnVoid) Check(ctx *Context, node *shimast.Node) {
|
|
411
|
+
var opts functionalNoReturnVoidOptions
|
|
412
|
+
_ = ctx.DecodeOptions(&opts)
|
|
364
413
|
if node.Kind == shimast.KindReturnStatement {
|
|
365
414
|
ret := node.AsReturnStatement()
|
|
366
|
-
if ret
|
|
367
|
-
|
|
415
|
+
if ret == nil || ret.Expression != nil {
|
|
416
|
+
return
|
|
417
|
+
}
|
|
418
|
+
if opts.IgnoreInferredTypes && functionalEnclosingReturnTypeText(ctx, node) == "" {
|
|
419
|
+
return
|
|
368
420
|
}
|
|
421
|
+
ctx.Report(node, "Function must return a value.")
|
|
369
422
|
return
|
|
370
423
|
}
|
|
371
|
-
|
|
424
|
+
switch functionalReturnTypeText(ctx, node) {
|
|
425
|
+
case "void":
|
|
372
426
|
ctx.Report(node, "Function must return a value.")
|
|
427
|
+
case "null":
|
|
428
|
+
if opts.AllowNull != nil && !*opts.AllowNull {
|
|
429
|
+
ctx.Report(node, "Function must return a value.")
|
|
430
|
+
}
|
|
431
|
+
case "undefined":
|
|
432
|
+
if opts.AllowUndefined != nil && !*opts.AllowUndefined {
|
|
433
|
+
ctx.Report(node, "Function must return a value.")
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// functionalEnclosingReturnTypeText returns the declared return type text of the
|
|
439
|
+
// nearest function-like ancestor of `node`, or "" when that function declares
|
|
440
|
+
// none. A bare `return;` there is the only place the rule reports a void-ness it
|
|
441
|
+
// inferred instead of reading, which is what `ignoreInferredTypes` spares.
|
|
442
|
+
//
|
|
443
|
+
// The walk stops at the nearest function-like of ANY kind. Skipping a
|
|
444
|
+
// constructor or a set accessor, neither of which may annotate a return type,
|
|
445
|
+
// would attribute an enclosing function's annotation to a `return;` that has
|
|
446
|
+
// nothing to do with it. A get accessor may annotate one, and
|
|
447
|
+
// functionalReturnTypeText reads it.
|
|
448
|
+
func functionalEnclosingReturnTypeText(ctx *Context, node *shimast.Node) string {
|
|
449
|
+
for parent := node.Parent; parent != nil; parent = parent.Parent {
|
|
450
|
+
if !isFunctionLikeKind(parent) {
|
|
451
|
+
continue
|
|
452
|
+
}
|
|
453
|
+
return functionalReturnTypeText(ctx, parent)
|
|
373
454
|
}
|
|
455
|
+
return ""
|
|
374
456
|
}
|
|
375
457
|
|
|
376
458
|
func (functionalNoThisExpressions) Check(ctx *Context, node *shimast.Node) {
|
|
@@ -418,6 +500,20 @@ func (functionalPreferPropertySignatures) Check(ctx *Context, node *shimast.Node
|
|
|
418
500
|
func (functionalPreferReadonlyType) Check(ctx *Context, node *shimast.Node) {
|
|
419
501
|
var opts functionalPreferReadonlyTypeOptions
|
|
420
502
|
_ = ctx.DecodeOptions(&opts)
|
|
503
|
+
if opts.IgnoreInterface && hasAncestor(node, func(ancestor *shimast.Node) bool {
|
|
504
|
+
return ancestor.Kind == shimast.KindInterfaceDeclaration
|
|
505
|
+
}) {
|
|
506
|
+
return
|
|
507
|
+
}
|
|
508
|
+
if functionalIgnoreClassSkips(opts.IgnoreClass, node) {
|
|
509
|
+
return
|
|
510
|
+
}
|
|
511
|
+
if opts.AllowMutableReturnType && isFunctionLikeReturnTypePosition(node) {
|
|
512
|
+
return
|
|
513
|
+
}
|
|
514
|
+
if opts.IgnoreCollections && isFunctionalCollectionTypeNode(node) {
|
|
515
|
+
return
|
|
516
|
+
}
|
|
421
517
|
switch node.Kind {
|
|
422
518
|
case shimast.KindArrayType:
|
|
423
519
|
if !isReadonlyTypeNode(node) {
|
|
@@ -451,10 +547,33 @@ func (functionalPreferReadonlyType) Check(ctx *Context, node *shimast.Node) {
|
|
|
451
547
|
}
|
|
452
548
|
|
|
453
549
|
func (functionalPreferTacit) Check(ctx *Context, node *shimast.Node) {
|
|
550
|
+
var opts functionalPreferTacitOptions
|
|
551
|
+
_ = ctx.DecodeOptions(&opts)
|
|
454
552
|
text := compactFunctionalWhitespace(nodeText(ctx.File, node))
|
|
455
|
-
if isTacitWrapperText(text) {
|
|
456
|
-
|
|
553
|
+
if !isTacitWrapperText(text) {
|
|
554
|
+
return
|
|
555
|
+
}
|
|
556
|
+
if opts.CheckMemberExpressions != nil && !*opts.CheckMemberExpressions &&
|
|
557
|
+
isTacitWrapperMemberCallee(text) {
|
|
558
|
+
return
|
|
457
559
|
}
|
|
560
|
+
ctx.Report(node, "Potentially unnecessary function wrapper.")
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// isTacitWrapperMemberCallee reports whether the wrapper's callee is a member
|
|
564
|
+
// expression (`service.handler`) rather than a bare identifier. `text` has
|
|
565
|
+
// already satisfied isTacitWrapperText, so the split and the `(` are present.
|
|
566
|
+
func isTacitWrapperMemberCallee(text string) bool {
|
|
567
|
+
parts := strings.Split(text, "=>")
|
|
568
|
+
if len(parts) != 2 {
|
|
569
|
+
return false
|
|
570
|
+
}
|
|
571
|
+
call := parts[1]
|
|
572
|
+
open := strings.LastIndex(call, "(")
|
|
573
|
+
if open <= 0 {
|
|
574
|
+
return false
|
|
575
|
+
}
|
|
576
|
+
return strings.Contains(call[:open], ".")
|
|
458
577
|
}
|
|
459
578
|
|
|
460
579
|
func (functionalReadonlyType) Check(ctx *Context, node *shimast.Node) {
|
|
@@ -595,27 +714,12 @@ func isDeclarationName(node *shimast.Node) bool {
|
|
|
595
714
|
}
|
|
596
715
|
}
|
|
597
716
|
|
|
717
|
+
// functionalReturnTypeText returns the declared return-type text of a
|
|
718
|
+
// signature-bearing node, or "" when it declares none. It reads the same
|
|
719
|
+
// signature table isFunctionLikeReturnTypePosition uses, so a get accessor is
|
|
720
|
+
// not mistaken for a declaration that cannot annotate its return type.
|
|
598
721
|
func functionalReturnTypeText(ctx *Context, node *shimast.Node) string {
|
|
599
|
-
|
|
600
|
-
switch node.Kind {
|
|
601
|
-
case shimast.KindFunctionDeclaration:
|
|
602
|
-
if decl := node.AsFunctionDeclaration(); decl != nil {
|
|
603
|
-
typeNode = decl.Type
|
|
604
|
-
}
|
|
605
|
-
case shimast.KindFunctionExpression:
|
|
606
|
-
if decl := node.AsFunctionExpression(); decl != nil {
|
|
607
|
-
typeNode = decl.Type
|
|
608
|
-
}
|
|
609
|
-
case shimast.KindArrowFunction:
|
|
610
|
-
if decl := node.AsArrowFunction(); decl != nil {
|
|
611
|
-
typeNode = decl.Type
|
|
612
|
-
}
|
|
613
|
-
case shimast.KindMethodDeclaration:
|
|
614
|
-
if decl := node.AsMethodDeclaration(); decl != nil {
|
|
615
|
-
typeNode = decl.Type
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
return strings.TrimSpace(nodeText(ctx.File, typeNode))
|
|
722
|
+
return strings.TrimSpace(nodeText(ctx.File, signatureReturnTypeNode(node)))
|
|
619
723
|
}
|
|
620
724
|
|
|
621
725
|
func functionalFunctionLikeName(node *shimast.Node) string {
|
|
@@ -757,6 +861,125 @@ func nilSafeFile(node *shimast.Node) *shimast.SourceFile {
|
|
|
757
861
|
return nil
|
|
758
862
|
}
|
|
759
863
|
|
|
864
|
+
// isFunctionLikeReturnTypePosition reports whether `node` is the return-type
|
|
865
|
+
// annotation of any signature-bearing declaration, or sits inside one. The rule
|
|
866
|
+
// visits type nodes, so a mutable array nested in the return type is the same
|
|
867
|
+
// position as the return type itself.
|
|
868
|
+
//
|
|
869
|
+
// Every kind that can carry a return-type annotation is listed: leaving call
|
|
870
|
+
// signatures, construct signatures, constructor types, or a get accessor out
|
|
871
|
+
// would let the same option answer differently for the same position depending
|
|
872
|
+
// on how the signature was spelled.
|
|
873
|
+
func isFunctionLikeReturnTypePosition(node *shimast.Node) bool {
|
|
874
|
+
for current := node; current != nil && current.Parent != nil; current = current.Parent {
|
|
875
|
+
typeNode := signatureReturnTypeNode(current.Parent)
|
|
876
|
+
if typeNode != nil && typeNode == current {
|
|
877
|
+
return true
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
return false
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
// signatureReturnTypeNode returns the declared return-type node of `node`, or
|
|
884
|
+
// nil when `node` carries no signature or declares no return type.
|
|
885
|
+
//
|
|
886
|
+
// Do not replace this table with typescript-go's own FunctionLikeData().Type:
|
|
887
|
+
// an index signature embeds the same base, so that accessor also returns the
|
|
888
|
+
// value type of `{ [k: string]: string[] }`, which is not a return type. The
|
|
889
|
+
// three kinds this table omits, a constructor, a set accessor, and an index
|
|
890
|
+
// signature, are exactly the ones whose Type field means something else.
|
|
891
|
+
func signatureReturnTypeNode(node *shimast.Node) *shimast.Node {
|
|
892
|
+
switch node.Kind {
|
|
893
|
+
case shimast.KindFunctionDeclaration:
|
|
894
|
+
if decl := node.AsFunctionDeclaration(); decl != nil {
|
|
895
|
+
return decl.Type
|
|
896
|
+
}
|
|
897
|
+
case shimast.KindFunctionExpression:
|
|
898
|
+
if decl := node.AsFunctionExpression(); decl != nil {
|
|
899
|
+
return decl.Type
|
|
900
|
+
}
|
|
901
|
+
case shimast.KindArrowFunction:
|
|
902
|
+
if decl := node.AsArrowFunction(); decl != nil {
|
|
903
|
+
return decl.Type
|
|
904
|
+
}
|
|
905
|
+
case shimast.KindMethodDeclaration:
|
|
906
|
+
if decl := node.AsMethodDeclaration(); decl != nil {
|
|
907
|
+
return decl.Type
|
|
908
|
+
}
|
|
909
|
+
case shimast.KindMethodSignature:
|
|
910
|
+
if decl := node.AsMethodSignatureDeclaration(); decl != nil {
|
|
911
|
+
return decl.Type
|
|
912
|
+
}
|
|
913
|
+
case shimast.KindGetAccessor:
|
|
914
|
+
if decl := node.AsGetAccessorDeclaration(); decl != nil {
|
|
915
|
+
return decl.Type
|
|
916
|
+
}
|
|
917
|
+
case shimast.KindFunctionType:
|
|
918
|
+
if decl := node.AsFunctionTypeNode(); decl != nil {
|
|
919
|
+
return decl.Type
|
|
920
|
+
}
|
|
921
|
+
case shimast.KindConstructorType:
|
|
922
|
+
if decl := node.AsConstructorTypeNode(); decl != nil {
|
|
923
|
+
return decl.Type
|
|
924
|
+
}
|
|
925
|
+
case shimast.KindCallSignature:
|
|
926
|
+
if decl := node.AsCallSignatureDeclaration(); decl != nil {
|
|
927
|
+
return decl.Type
|
|
928
|
+
}
|
|
929
|
+
case shimast.KindConstructSignature:
|
|
930
|
+
if decl := node.AsConstructSignatureDeclaration(); decl != nil {
|
|
931
|
+
return decl.Type
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
return nil
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
// isFunctionalClassMemberPosition reports whether `node` sits inside a class,
|
|
938
|
+
// and whether that position is a field. `ignoreClass: true` skips anything
|
|
939
|
+
// under a class, its heritage clause and type parameters included, the same
|
|
940
|
+
// ancestor test `ignoreInterface` applies. `"fieldsOnly"` narrows that to field
|
|
941
|
+
// declarations, leaving methods, accessors, and constructor parameters checked.
|
|
942
|
+
func isFunctionalClassMemberPosition(node *shimast.Node) (inClass bool, inField bool) {
|
|
943
|
+
for parent := node.Parent; parent != nil; parent = parent.Parent {
|
|
944
|
+
switch parent.Kind {
|
|
945
|
+
case shimast.KindPropertyDeclaration:
|
|
946
|
+
inField = true
|
|
947
|
+
case shimast.KindClassDeclaration, shimast.KindClassExpression:
|
|
948
|
+
return true, inField
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
return false, false
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
// functionalIgnoreClassSkips resolves the `boolean | "fieldsOnly"` option
|
|
955
|
+
// against a visited node's class position.
|
|
956
|
+
func functionalIgnoreClassSkips(option interface{}, node *shimast.Node) bool {
|
|
957
|
+
if option == nil || option == false {
|
|
958
|
+
return false
|
|
959
|
+
}
|
|
960
|
+
inClass, inField := isFunctionalClassMemberPosition(node)
|
|
961
|
+
if !inClass {
|
|
962
|
+
return false
|
|
963
|
+
}
|
|
964
|
+
if option == "fieldsOnly" {
|
|
965
|
+
return inField
|
|
966
|
+
}
|
|
967
|
+
return option == true
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
// isFunctionalCollectionTypeNode reports whether `node` is an array, tuple, or
|
|
971
|
+
// mutable built-in collection reference, the set `ignoreCollections` spares.
|
|
972
|
+
func isFunctionalCollectionTypeNode(node *shimast.Node) bool {
|
|
973
|
+
switch node.Kind {
|
|
974
|
+
case shimast.KindArrayType, shimast.KindTupleType:
|
|
975
|
+
return true
|
|
976
|
+
case shimast.KindTypeReference:
|
|
977
|
+
return isMutableTypeReference(node)
|
|
978
|
+
default:
|
|
979
|
+
return false
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
|
|
760
983
|
func isMutableTypeReference(node *shimast.Node) bool {
|
|
761
984
|
ref := node.AsTypeReferenceNode()
|
|
762
985
|
if ref == nil || ref.TypeName == nil {
|
|
@@ -317,12 +317,14 @@ func parameterPropertyName(param *shimast.Node) (string, bool) {
|
|
|
317
317
|
return name, name != ""
|
|
318
318
|
}
|
|
319
319
|
|
|
320
|
+
// isParameterProperty is the package's shared parameter-property predicate.
|
|
321
|
+
// The compiler's own mask is the source: a restated keyword list is what left
|
|
322
|
+
// `override` out of format/parameter-properties (#1131), and this predicate
|
|
323
|
+
// feeds six rules, so a restatement here would be five more chances at the same
|
|
324
|
+
// drift.
|
|
320
325
|
func isParameterProperty(param *shimast.Node) bool {
|
|
321
|
-
return
|
|
322
|
-
|
|
323
|
-
hasModifier(param, shimast.KindProtectedKeyword) ||
|
|
324
|
-
hasModifier(param, shimast.KindReadonlyKeyword) ||
|
|
325
|
-
hasModifier(param, shimast.KindOverrideKeyword)
|
|
326
|
+
return param != nil &&
|
|
327
|
+
param.ModifierFlags()&shimast.ModifierFlagsParameterPropertyModifier != 0
|
|
326
328
|
}
|
|
327
329
|
|
|
328
330
|
func thisPropertyAssignment(stmt *shimast.Node) (property string, value string, ok bool) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttsc/lint",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"description": "Reference ttsc plugin: ESLint-style lint rules over the TypeScript-Go Program used by the type-check pass.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"@types/node": "^25.3.0",
|
|
38
38
|
"rimraf": "^6.1.2",
|
|
39
39
|
"typescript": "^7.0.2",
|
|
40
|
-
"ttsc": "0.
|
|
40
|
+
"ttsc": "0.26.0"
|
|
41
41
|
},
|
|
42
42
|
"repository": {
|
|
43
43
|
"type": "git",
|
package/rule/rule.go
CHANGED
|
@@ -262,15 +262,27 @@ type RelatedInformation struct {
|
|
|
262
262
|
// be replaced as a whole.
|
|
263
263
|
//
|
|
264
264
|
// Application policy: a rule may emit several `TextEdit`s in one
|
|
265
|
-
// `ReportFix` / `ReportRangeFix` call, in any order. The
|
|
266
|
-
//
|
|
267
|
-
//
|
|
268
|
-
//
|
|
269
|
-
//
|
|
270
|
-
//
|
|
271
|
-
//
|
|
272
|
-
//
|
|
273
|
-
//
|
|
265
|
+
// `ReportFix` / `ReportRangeFix` call, in any order. The unit the host
|
|
266
|
+
// resolves conflicts on is the FINDING, not the individual edit. Within one
|
|
267
|
+
// fix pass the host considers each finding's edits as one group, earliest
|
|
268
|
+
// group first, and accepts a group only when every member coexists with the
|
|
269
|
+
// edits already accepted. If any member would be dropped, the whole group is
|
|
270
|
+
// skipped, so a multi-edit fix never half-applies. The skipped finding is not
|
|
271
|
+
// lost: the next cascade pass re-runs the rule against the rewritten source
|
|
272
|
+
// and the fix applies then, or the cascade converges without it.
|
|
273
|
+
//
|
|
274
|
+
// A finding's own edits must therefore not overlap each other either, or the
|
|
275
|
+
// finding can never apply. Exact duplicates within one finding are collapsed
|
|
276
|
+
// rather than treated as a conflict, so repeating an identical edit is
|
|
277
|
+
// harmless. Nothing diagnoses a skipped group, and the host does not report
|
|
278
|
+
// when a comment falls inside a deletion range.
|
|
279
|
+
//
|
|
280
|
+
// Emit the narrowest edits that express the rewrite. Several small
|
|
281
|
+
// non-overlapping edits contend for less source than one wide replacement and
|
|
282
|
+
// are the shape the atomic applier exists to support. Built-ins that ship
|
|
283
|
+
// multi-edit fixes include `typescript/no-import-type-side-effects`,
|
|
284
|
+
// `format/whitespace`, `format/indent`, `unicorn/prevent-abbreviations`, and
|
|
285
|
+
// `unicorn/template-indent`.
|
|
274
286
|
type TextEdit struct {
|
|
275
287
|
Pos int
|
|
276
288
|
End int
|
|
@@ -80,24 +80,45 @@ export interface ITtscLintFunctionalNoThrowStatementsRuleOptions {
|
|
|
80
80
|
|
|
81
81
|
/** `functional/no-mixed-types` rule options. */
|
|
82
82
|
export interface ITtscLintFunctionalNoMixedTypesRuleOptions {
|
|
83
|
-
/**
|
|
83
|
+
/**
|
|
84
|
+
* Check interface member kinds.
|
|
85
|
+
*
|
|
86
|
+
* @default true
|
|
87
|
+
*/
|
|
84
88
|
checkInterfaces?: boolean;
|
|
85
89
|
|
|
86
|
-
/**
|
|
90
|
+
/**
|
|
91
|
+
* Check type-literal member kinds.
|
|
92
|
+
*
|
|
93
|
+
* @default true
|
|
94
|
+
*/
|
|
87
95
|
checkTypeLiterals?: boolean;
|
|
88
96
|
}
|
|
89
97
|
|
|
90
98
|
/** `functional/no-return-void` rule options. */
|
|
91
99
|
export interface ITtscLintFunctionalNoReturnVoidRuleOptions {
|
|
92
|
-
/**
|
|
100
|
+
/**
|
|
101
|
+
* Permit a function whose declared return type is `null`. Set `false` to
|
|
102
|
+
* reject it the way a declared `void` is rejected.
|
|
103
|
+
*
|
|
104
|
+
* @default true
|
|
105
|
+
*/
|
|
93
106
|
allowNull?: boolean;
|
|
94
107
|
|
|
95
|
-
/**
|
|
108
|
+
/**
|
|
109
|
+
* Permit a function whose declared return type is `undefined`. Set `false` to
|
|
110
|
+
* reject it the way a declared `void` is rejected.
|
|
111
|
+
*
|
|
112
|
+
* @default true
|
|
113
|
+
*/
|
|
96
114
|
allowUndefined?: boolean;
|
|
97
115
|
|
|
98
116
|
/**
|
|
99
|
-
* Skip
|
|
100
|
-
*
|
|
117
|
+
* Skip a bare `return;` inside a function that declares no return type. That
|
|
118
|
+
* statement is the one place the rule rejects a void-ness it inferred rather
|
|
119
|
+
* than read from an annotation.
|
|
120
|
+
*
|
|
121
|
+
* @default false
|
|
101
122
|
*/
|
|
102
123
|
ignoreInferredTypes?: boolean;
|
|
103
124
|
}
|
|
@@ -105,7 +126,8 @@ export interface ITtscLintFunctionalNoReturnVoidRuleOptions {
|
|
|
105
126
|
/** `functional/prefer-immutable-types` rule options. */
|
|
106
127
|
export interface ITtscLintFunctionalPreferImmutableTypesRuleOptions extends ITtscLintFunctionalPatternOptions {
|
|
107
128
|
/**
|
|
108
|
-
* Minimum accepted immutability.
|
|
129
|
+
* Minimum accepted immutability. Reserved for upstream-compatible configs;
|
|
130
|
+
* the native subset computes no immutability level and treats any configured
|
|
109
131
|
* value as readonly-required.
|
|
110
132
|
*/
|
|
111
133
|
enforcement?:
|
|
@@ -118,31 +140,62 @@ export interface ITtscLintFunctionalPreferImmutableTypesRuleOptions extends ITts
|
|
|
118
140
|
|
|
119
141
|
/** `functional/prefer-readonly-type` rule options. */
|
|
120
142
|
export interface ITtscLintFunctionalPreferReadonlyTypeRuleOptions extends ITtscLintFunctionalPatternOptions {
|
|
121
|
-
/**
|
|
143
|
+
/**
|
|
144
|
+
* Permit mutation of locals while still policing exported types. Reserved for
|
|
145
|
+
* upstream-compatible configs; the native subset reads type annotations and
|
|
146
|
+
* models no local-versus-exported distinction.
|
|
147
|
+
*/
|
|
122
148
|
allowLocalMutation?: boolean;
|
|
123
149
|
|
|
124
|
-
/**
|
|
150
|
+
/**
|
|
151
|
+
* Permit a mutable return type even when parameters must be readonly. Covers
|
|
152
|
+
* every signature that can declare one, including call and construct
|
|
153
|
+
* signatures, constructor types, and a get accessor.
|
|
154
|
+
*
|
|
155
|
+
* @default false
|
|
156
|
+
*/
|
|
125
157
|
allowMutableReturnType?: boolean;
|
|
126
158
|
|
|
127
|
-
/**
|
|
159
|
+
/**
|
|
160
|
+
* Also check property positions that have no explicit type annotation.
|
|
161
|
+
* Reserved for upstream-compatible configs; judging an unannotated position
|
|
162
|
+
* needs the type checker, which this rule does not use.
|
|
163
|
+
*/
|
|
128
164
|
checkImplicit?: boolean;
|
|
129
165
|
|
|
130
|
-
/**
|
|
166
|
+
/**
|
|
167
|
+
* Skip array / tuple / `Map` / `Set` types.
|
|
168
|
+
*
|
|
169
|
+
* @default false
|
|
170
|
+
*/
|
|
131
171
|
ignoreCollections?: boolean;
|
|
132
172
|
|
|
133
173
|
/**
|
|
134
|
-
* Skip class
|
|
135
|
-
*
|
|
174
|
+
* Skip class members. `true` skips anything under a class, its heritage
|
|
175
|
+
* clause and type parameters included; `"fieldsOnly"` narrows that to field
|
|
176
|
+
* declarations and keeps methods, accessors, and constructor parameters
|
|
177
|
+
* checked.
|
|
178
|
+
*
|
|
179
|
+
* @default false
|
|
136
180
|
*/
|
|
137
181
|
ignoreClass?: boolean | "fieldsOnly";
|
|
138
182
|
|
|
139
|
-
/**
|
|
183
|
+
/**
|
|
184
|
+
* Skip interface members entirely.
|
|
185
|
+
*
|
|
186
|
+
* @default false
|
|
187
|
+
*/
|
|
140
188
|
ignoreInterface?: boolean;
|
|
141
189
|
}
|
|
142
190
|
|
|
143
191
|
/** `functional/prefer-tacit` rule options. */
|
|
144
192
|
export interface ITtscLintFunctionalPreferTacitRuleOptions {
|
|
145
|
-
/**
|
|
193
|
+
/**
|
|
194
|
+
* Check member expressions such as `x => service.map(x)`. Set `false` to keep
|
|
195
|
+
* the rule on bare-identifier callees only.
|
|
196
|
+
*
|
|
197
|
+
* @default true
|
|
198
|
+
*/
|
|
146
199
|
checkMemberExpressions?: boolean;
|
|
147
200
|
}
|
|
148
201
|
|
|
@@ -167,7 +220,11 @@ export interface ITtscLintFunctionalTypeDeclarationImmutabilityRule {
|
|
|
167
220
|
*/
|
|
168
221
|
immutability?: "ReadonlyShallow" | "ReadonlyDeep" | "Immutable" | "Mutable";
|
|
169
222
|
|
|
170
|
-
/**
|
|
223
|
+
/**
|
|
224
|
+
* Comparator applied to the immutability level above. Reserved for
|
|
225
|
+
* upstream-compatible configs alongside `immutability`: the native subset
|
|
226
|
+
* computes no immutability level, so there is nothing to compare.
|
|
227
|
+
*/
|
|
171
228
|
comparator?:
|
|
172
229
|
| "Less"
|
|
173
230
|
| "AtMost"
|