@ttsc/lint 0.5.0 → 0.6.0-dev.20250501

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.
@@ -0,0 +1,341 @@
1
+ package main
2
+
3
+ import shimast "github.com/microsoft/typescript-go/shim/ast"
4
+
5
+ // no-empty-static-block: `class C { static {} }` has no effect.
6
+ // ESLint recommended: https://eslint.org/docs/latest/rules/no-empty-static-block
7
+ type noEmptyStaticBlock struct{}
8
+
9
+ func (noEmptyStaticBlock) Name() string { return "no-empty-static-block" }
10
+ func (noEmptyStaticBlock) Visits() []shimast.Kind {
11
+ return []shimast.Kind{shimast.KindClassStaticBlockDeclaration}
12
+ }
13
+ func (noEmptyStaticBlock) Check(ctx *Context, node *shimast.Node) {
14
+ block := node.AsClassStaticBlockDeclaration()
15
+ if block == nil || block.Body == nil {
16
+ return
17
+ }
18
+ body := block.Body.AsBlock()
19
+ if body == nil || body.Statements == nil || len(body.Statements.Nodes) == 0 {
20
+ ctx.Report(node, "Unexpected empty static block.")
21
+ }
22
+ }
23
+
24
+ // no-setter-return: setters must not return a value.
25
+ // ESLint recommended: https://eslint.org/docs/latest/rules/no-setter-return
26
+ type noSetterReturn struct{}
27
+
28
+ func (noSetterReturn) Name() string { return "no-setter-return" }
29
+ func (noSetterReturn) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindReturnStatement} }
30
+ func (noSetterReturn) Check(ctx *Context, node *shimast.Node) {
31
+ ret := node.AsReturnStatement()
32
+ if ret == nil || ret.Expression == nil || !isInsideDirectSetter(node) {
33
+ return
34
+ }
35
+ ctx.Report(node, "Setter should not return a value.")
36
+ }
37
+
38
+ func isInsideDirectSetter(node *shimast.Node) bool {
39
+ for p := node.Parent; p != nil; p = p.Parent {
40
+ if p.Kind == shimast.KindSetAccessor {
41
+ return true
42
+ }
43
+ if isFunctionLikeKind(p) {
44
+ return false
45
+ }
46
+ }
47
+ return false
48
+ }
49
+
50
+ // no-unused-labels: a label is useful only when a break/continue targets it.
51
+ // ESLint recommended: https://eslint.org/docs/latest/rules/no-unused-labels
52
+ type noUnusedLabels struct{}
53
+
54
+ func (noUnusedLabels) Name() string { return "no-unused-labels" }
55
+ func (noUnusedLabels) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindLabeledStatement} }
56
+ func (noUnusedLabels) Check(ctx *Context, node *shimast.Node) {
57
+ stmt := node.AsLabeledStatement()
58
+ if stmt == nil || stmt.Label == nil {
59
+ return
60
+ }
61
+ label := identifierText(stmt.Label)
62
+ if label == "" {
63
+ return
64
+ }
65
+ used := false
66
+ walkDescendants(stmt.Statement, func(child *shimast.Node) {
67
+ if used || child == nil {
68
+ return
69
+ }
70
+ switch child.Kind {
71
+ case shimast.KindBreakStatement:
72
+ br := child.AsBreakStatement()
73
+ used = br != nil && identifierText(br.Label) == label
74
+ case shimast.KindContinueStatement:
75
+ cont := child.AsContinueStatement()
76
+ used = cont != nil && identifierText(cont.Label) == label
77
+ }
78
+ })
79
+ if !used {
80
+ ctx.Report(stmt.Label, "Label '"+label+"' is defined but never used.")
81
+ }
82
+ }
83
+
84
+ // no-dynamic-delete: avoid deleting properties through dynamic keys.
85
+ // typescript-eslint strict: https://typescript-eslint.io/rules/no-dynamic-delete/
86
+ type noDynamicDelete struct{}
87
+
88
+ func (noDynamicDelete) Name() string { return "no-dynamic-delete" }
89
+ func (noDynamicDelete) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindDeleteExpression} }
90
+ func (noDynamicDelete) Check(ctx *Context, node *shimast.Node) {
91
+ del := node.AsDeleteExpression()
92
+ if del == nil || del.Expression == nil || del.Expression.Kind != shimast.KindElementAccessExpression {
93
+ return
94
+ }
95
+ access := del.Expression.AsElementAccessExpression()
96
+ if access == nil || isStaticPropertyKey(access.ArgumentExpression) {
97
+ return
98
+ }
99
+ ctx.Report(node, "Do not delete dynamically computed property keys.")
100
+ }
101
+
102
+ func isStaticPropertyKey(node *shimast.Node) bool {
103
+ node = stripParens(node)
104
+ if node == nil {
105
+ return false
106
+ }
107
+ switch node.Kind {
108
+ case shimast.KindStringLiteral,
109
+ shimast.KindNoSubstitutionTemplateLiteral,
110
+ shimast.KindNumericLiteral:
111
+ return true
112
+ }
113
+ return false
114
+ }
115
+
116
+ // no-non-null-asserted-nullish-coalescing: `foo! ?? bar` is contradictory.
117
+ // typescript-eslint strict: https://typescript-eslint.io/rules/no-non-null-asserted-nullish-coalescing/
118
+ type noNonNullAssertedNullishCoalescing struct{}
119
+
120
+ func (noNonNullAssertedNullishCoalescing) Name() string {
121
+ return "no-non-null-asserted-nullish-coalescing"
122
+ }
123
+ func (noNonNullAssertedNullishCoalescing) Visits() []shimast.Kind {
124
+ return []shimast.Kind{shimast.KindBinaryExpression}
125
+ }
126
+ func (noNonNullAssertedNullishCoalescing) Check(ctx *Context, node *shimast.Node) {
127
+ expr := node.AsBinaryExpression()
128
+ if expr == nil || expr.OperatorToken == nil || expr.OperatorToken.Kind != shimast.KindQuestionQuestionToken {
129
+ return
130
+ }
131
+ if left := stripParens(expr.Left); left != nil && left.Kind == shimast.KindNonNullExpression {
132
+ ctx.Report(left, "Nullish coalescing is unnecessary after a non-null assertion.")
133
+ }
134
+ if right := stripParens(expr.Right); right != nil && right.Kind == shimast.KindNonNullExpression {
135
+ ctx.Report(right, "Nullish coalescing is unnecessary before a non-null assertion.")
136
+ }
137
+ }
138
+
139
+ // no-unnecessary-type-constraint: `<T extends any>` / `<T extends unknown>`.
140
+ // typescript-eslint recommended: https://typescript-eslint.io/rules/no-unnecessary-type-constraint/
141
+ type noUnnecessaryTypeConstraint struct{}
142
+
143
+ func (noUnnecessaryTypeConstraint) Name() string { return "no-unnecessary-type-constraint" }
144
+ func (noUnnecessaryTypeConstraint) Visits() []shimast.Kind {
145
+ return []shimast.Kind{shimast.KindTypeParameter}
146
+ }
147
+ func (noUnnecessaryTypeConstraint) Check(ctx *Context, node *shimast.Node) {
148
+ param := node.AsTypeParameterDeclaration()
149
+ if param == nil || param.Constraint == nil {
150
+ return
151
+ }
152
+ if param.Constraint.Kind == shimast.KindAnyKeyword || param.Constraint.Kind == shimast.KindUnknownKeyword {
153
+ ctx.Report(param.Constraint, "Constraining a type parameter to any or unknown is unnecessary.")
154
+ }
155
+ }
156
+
157
+ // no-unsafe-function-type: `Function` accepts any callable shape.
158
+ // typescript-eslint recommended: https://typescript-eslint.io/rules/no-unsafe-function-type/
159
+ type noUnsafeFunctionType struct{}
160
+
161
+ func (noUnsafeFunctionType) Name() string { return "no-unsafe-function-type" }
162
+ func (noUnsafeFunctionType) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindTypeReference} }
163
+ func (noUnsafeFunctionType) Check(ctx *Context, node *shimast.Node) {
164
+ ref := node.AsTypeReferenceNode()
165
+ if ref == nil || identifierText(ref.TypeName) != "Function" {
166
+ return
167
+ }
168
+ ctx.Report(node, "The Function type is unsafe. Use a specific function type instead.")
169
+ }
170
+
171
+ // no-wrapper-object-types: prefer primitive type keywords over boxed object
172
+ // type names such as `String` and `Boolean`.
173
+ // typescript-eslint recommended: https://typescript-eslint.io/rules/no-wrapper-object-types/
174
+ type noWrapperObjectTypes struct{}
175
+
176
+ func (noWrapperObjectTypes) Name() string { return "no-wrapper-object-types" }
177
+ func (noWrapperObjectTypes) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindTypeReference} }
178
+ func (noWrapperObjectTypes) Check(ctx *Context, node *shimast.Node) {
179
+ ref := node.AsTypeReferenceNode()
180
+ if ref == nil {
181
+ return
182
+ }
183
+ switch identifierText(ref.TypeName) {
184
+ case "String", "Number", "Boolean", "Symbol", "BigInt", "Object":
185
+ ctx.Report(node, "Use primitive type keywords instead of wrapper object types.")
186
+ }
187
+ }
188
+
189
+ // no-useless-constructor: an empty constructor with no parameters is noise.
190
+ // typescript-eslint strict: https://typescript-eslint.io/rules/no-useless-constructor/
191
+ type noUselessConstructor struct{}
192
+
193
+ func (noUselessConstructor) Name() string { return "no-useless-constructor" }
194
+ func (noUselessConstructor) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindConstructor} }
195
+ func (noUselessConstructor) Check(ctx *Context, node *shimast.Node) {
196
+ ctor := node.AsConstructorDeclaration()
197
+ if ctor == nil || ctor.Body == nil {
198
+ return
199
+ }
200
+ if len(node.Parameters()) != 0 {
201
+ return
202
+ }
203
+ body := ctor.Body.AsBlock()
204
+ if body == nil || body.Statements == nil || len(body.Statements.Nodes) == 0 {
205
+ ctx.Report(node, "Useless empty constructor.")
206
+ }
207
+ }
208
+
209
+ // prefer-literal-enum-member: computed enum members are harder to inspect.
210
+ // typescript-eslint strict: https://typescript-eslint.io/rules/prefer-literal-enum-member/
211
+ type preferLiteralEnumMember struct{}
212
+
213
+ func (preferLiteralEnumMember) Name() string { return "prefer-literal-enum-member" }
214
+ func (preferLiteralEnumMember) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindEnumMember} }
215
+ func (preferLiteralEnumMember) Check(ctx *Context, node *shimast.Node) {
216
+ member := node.AsEnumMember()
217
+ if member == nil || member.Initializer == nil || isLiteralLike(member.Initializer) {
218
+ return
219
+ }
220
+ ctx.Report(member.Initializer, "Enum member initializer should be a literal value.")
221
+ }
222
+
223
+ // consistent-type-assertions: prefer `value as Type` over `<Type>value`.
224
+ // typescript-eslint stylistic: https://typescript-eslint.io/rules/consistent-type-assertions/
225
+ type consistentTypeAssertions struct{}
226
+
227
+ func (consistentTypeAssertions) Name() string { return "consistent-type-assertions" }
228
+ func (consistentTypeAssertions) Visits() []shimast.Kind {
229
+ return []shimast.Kind{shimast.KindTypeAssertionExpression}
230
+ }
231
+ func (consistentTypeAssertions) Check(ctx *Context, node *shimast.Node) {
232
+ ctx.Report(node, "Use `as` type assertions instead of angle-bracket assertions.")
233
+ }
234
+
235
+ // consistent-type-definitions: prefer interfaces for object-shaped public
236
+ // contracts. This mirrors typescript-eslint's default option.
237
+ // typescript-eslint stylistic: https://typescript-eslint.io/rules/consistent-type-definitions/
238
+ type consistentTypeDefinitions struct{}
239
+
240
+ func (consistentTypeDefinitions) Name() string { return "consistent-type-definitions" }
241
+ func (consistentTypeDefinitions) Visits() []shimast.Kind {
242
+ return []shimast.Kind{shimast.KindTypeAliasDeclaration}
243
+ }
244
+ func (consistentTypeDefinitions) Check(ctx *Context, node *shimast.Node) {
245
+ alias := node.AsTypeAliasDeclaration()
246
+ if alias == nil || alias.Type == nil || alias.Type.Kind != shimast.KindTypeLiteral {
247
+ return
248
+ }
249
+ ctx.Report(node, "Use an interface instead of a type literal alias.")
250
+ }
251
+
252
+ // dot-notation: `obj["prop"]` should be `obj.prop` when the key is a valid
253
+ // identifier.
254
+ // ESLint canonical: https://eslint.org/docs/latest/rules/dot-notation
255
+ type dotNotation struct{}
256
+
257
+ func (dotNotation) Name() string { return "dot-notation" }
258
+ func (dotNotation) Visits() []shimast.Kind {
259
+ return []shimast.Kind{shimast.KindElementAccessExpression}
260
+ }
261
+ func (dotNotation) Check(ctx *Context, node *shimast.Node) {
262
+ access := node.AsElementAccessExpression()
263
+ if access == nil {
264
+ return
265
+ }
266
+ key := stringLiteralText(access.ArgumentExpression)
267
+ if key == "" || !isSimpleIdentifierName(key) {
268
+ return
269
+ }
270
+ ctx.Report(node, "Use dot notation instead of a string literal property access.")
271
+ }
272
+
273
+ func isSimpleIdentifierName(value string) bool {
274
+ if value == "" {
275
+ return false
276
+ }
277
+ for i, r := range value {
278
+ if r == '_' || r == '$' || r >= 'a' && r <= 'z' || r >= 'A' && r <= 'Z' {
279
+ continue
280
+ }
281
+ if i > 0 && r >= '0' && r <= '9' {
282
+ continue
283
+ }
284
+ return false
285
+ }
286
+ return true
287
+ }
288
+
289
+ // no-unsafe-declaration-merging: class/interface merging hides runtime vs type
290
+ // surface differences.
291
+ // typescript-eslint recommended: https://typescript-eslint.io/rules/no-unsafe-declaration-merging/
292
+ type noUnsafeDeclarationMerging struct{}
293
+
294
+ func (noUnsafeDeclarationMerging) Name() string { return "no-unsafe-declaration-merging" }
295
+ func (noUnsafeDeclarationMerging) Visits() []shimast.Kind {
296
+ return []shimast.Kind{shimast.KindSourceFile}
297
+ }
298
+ func (noUnsafeDeclarationMerging) Check(ctx *Context, node *shimast.Node) {
299
+ classes := map[string]bool{}
300
+ var interfaces []*shimast.Node
301
+ walkDescendants(node, func(child *shimast.Node) {
302
+ switch child.Kind {
303
+ case shimast.KindClassDeclaration:
304
+ decl := child.AsClassDeclaration()
305
+ if decl != nil {
306
+ if name := identifierText(decl.Name()); name != "" {
307
+ classes[name] = true
308
+ }
309
+ }
310
+ case shimast.KindInterfaceDeclaration:
311
+ interfaces = append(interfaces, child)
312
+ }
313
+ })
314
+ for _, ifaceNode := range interfaces {
315
+ decl := ifaceNode.AsInterfaceDeclaration()
316
+ if decl == nil {
317
+ continue
318
+ }
319
+ name := identifierText(decl.Name())
320
+ if name != "" && classes[name] {
321
+ ctx.Report(ifaceNode, "Unsafe declaration merging between class and interface '"+name+"'.")
322
+ }
323
+ }
324
+ }
325
+
326
+ func init() {
327
+ Register(noEmptyStaticBlock{})
328
+ Register(noSetterReturn{})
329
+ Register(noUnusedLabels{})
330
+ Register(noDynamicDelete{})
331
+ Register(noNonNullAssertedNullishCoalescing{})
332
+ Register(noUnnecessaryTypeConstraint{})
333
+ Register(noUnsafeDeclarationMerging{})
334
+ Register(noUnsafeFunctionType{})
335
+ Register(noWrapperObjectTypes{})
336
+ Register(noUselessConstructor{})
337
+ Register(preferLiteralEnumMember{})
338
+ Register(consistentTypeAssertions{})
339
+ Register(consistentTypeDefinitions{})
340
+ Register(dotNotation{})
341
+ }
@@ -277,7 +277,20 @@ func isAssignmentOperator(kind shimast.Kind) bool {
277
277
  switch kind {
278
278
  case shimast.KindEqualsToken,
279
279
  shimast.KindPlusEqualsToken,
280
- shimast.KindMinusEqualsToken:
280
+ shimast.KindMinusEqualsToken,
281
+ shimast.KindAsteriskEqualsToken,
282
+ shimast.KindAsteriskAsteriskEqualsToken,
283
+ shimast.KindSlashEqualsToken,
284
+ shimast.KindPercentEqualsToken,
285
+ shimast.KindLessThanLessThanEqualsToken,
286
+ shimast.KindGreaterThanGreaterThanEqualsToken,
287
+ shimast.KindGreaterThanGreaterThanGreaterThanEqualsToken,
288
+ shimast.KindAmpersandEqualsToken,
289
+ shimast.KindBarEqualsToken,
290
+ shimast.KindCaretEqualsToken,
291
+ shimast.KindAmpersandAmpersandEqualsToken,
292
+ shimast.KindBarBarEqualsToken,
293
+ shimast.KindQuestionQuestionEqualsToken:
281
294
  return true
282
295
  }
283
296
  return false
@@ -18,6 +18,92 @@ func (noVar) Check(ctx *Context, node *shimast.Node) {
18
18
  }
19
19
  }
20
20
 
21
+ // prefer-const: flag `let` declarations whose binding is never reassigned.
22
+ // This follows ESLint's core rule for the common AST-local cases. It is
23
+ // intentionally conservative: destructuring and declaration-only `let`
24
+ // variables are skipped until the lint host grows full scope/data-flow state.
25
+ // ESLint canonical: https://eslint.org/docs/latest/rules/prefer-const
26
+ type preferConst struct{}
27
+
28
+ func (preferConst) Name() string { return "prefer-const" }
29
+ func (preferConst) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindSourceFile} }
30
+ func (preferConst) Check(ctx *Context, node *shimast.Node) {
31
+ type candidate struct {
32
+ name string
33
+ node *shimast.Node
34
+ }
35
+ var candidates []candidate
36
+ assigned := map[string]bool{}
37
+
38
+ walkDescendants(node, func(child *shimast.Node) {
39
+ switch child.Kind {
40
+ case shimast.KindVariableDeclaration:
41
+ decl := child.AsVariableDeclaration()
42
+ if decl == nil || child.Parent == nil || child.Parent.Kind != shimast.KindVariableDeclarationList {
43
+ return
44
+ }
45
+ listNode := child.Parent
46
+ if !shimast.IsLet(listNode) {
47
+ return
48
+ }
49
+ name := identifierText(decl.Name())
50
+ if name == "" {
51
+ return
52
+ }
53
+ if !isConstEligibleLetDeclaration(child, decl) {
54
+ return
55
+ }
56
+ candidates = append(candidates, candidate{name: name, node: child})
57
+ case shimast.KindBinaryExpression:
58
+ expr := child.AsBinaryExpression()
59
+ if expr == nil || expr.OperatorToken == nil || !isAssignmentOperator(expr.OperatorToken.Kind) {
60
+ return
61
+ }
62
+ for _, name := range bindingIdentifierNames(expr.Left) {
63
+ assigned[name] = true
64
+ }
65
+ case shimast.KindPrefixUnaryExpression:
66
+ expr := child.AsPrefixUnaryExpression()
67
+ if expr == nil {
68
+ return
69
+ }
70
+ if expr.Operator == shimast.KindPlusPlusToken || expr.Operator == shimast.KindMinusMinusToken {
71
+ if name := identifierText(expr.Operand); name != "" {
72
+ assigned[name] = true
73
+ }
74
+ }
75
+ case shimast.KindPostfixUnaryExpression:
76
+ expr := child.AsPostfixUnaryExpression()
77
+ if expr == nil {
78
+ return
79
+ }
80
+ if expr.Operator == shimast.KindPlusPlusToken || expr.Operator == shimast.KindMinusMinusToken {
81
+ if name := identifierText(expr.Operand); name != "" {
82
+ assigned[name] = true
83
+ }
84
+ }
85
+ }
86
+ })
87
+
88
+ for _, c := range candidates {
89
+ if !assigned[c.name] {
90
+ ctx.Report(c.node, "Use const instead of let.")
91
+ }
92
+ }
93
+ }
94
+
95
+ func isConstEligibleLetDeclaration(node *shimast.Node, decl *shimast.VariableDeclaration) bool {
96
+ if decl.Initializer != nil {
97
+ if node.Parent != nil && node.Parent.Parent != nil && node.Parent.Parent.Kind == shimast.KindForStatement {
98
+ list := node.Parent.AsVariableDeclarationList()
99
+ return list == nil || list.Declarations == nil || len(list.Declarations.Nodes) == 1
100
+ }
101
+ return true
102
+ }
103
+ return node.Parent != nil && node.Parent.Parent != nil &&
104
+ (node.Parent.Parent.Kind == shimast.KindForInStatement || node.Parent.Parent.Kind == shimast.KindForOfStatement)
105
+ }
106
+
21
107
  // no-undef-init: forbid `let x = undefined` and `var x = undefined`.
22
108
  // ESLint canonical: https://eslint.org/docs/latest/rules/no-undef-init
23
109
  type noUndefInit struct{}
@@ -36,5 +122,6 @@ func (noUndefInit) Check(ctx *Context, node *shimast.Node) {
36
122
 
37
123
  func init() {
38
124
  Register(noVar{})
125
+ Register(preferConst{})
39
126
  Register(noUndefInit{})
40
127
  }
package/src/index.ts ADDED
@@ -0,0 +1,35 @@
1
+ import path from "node:path";
2
+ import type {
3
+ ITtscProjectPluginConfig,
4
+ ITtscPlugin,
5
+ ITtscPluginFactoryContext,
6
+ } from "ttsc";
7
+
8
+ import type { ITtscLintConfig } from "./structures/ITtscLintConfig";
9
+
10
+ export * from "./structures/ITtscLintConfig";
11
+ export * from "./structures/ITtscLintRule";
12
+ export * from "./structures/ITtscLintSeverity";
13
+
14
+ export type ITtscLintPluginConfig = ITtscProjectPluginConfig & {
15
+ config?: string | ITtscLintConfig;
16
+ };
17
+
18
+ export function createTtscPlugin(
19
+ _context: ITtscPluginFactoryContext<ITtscLintPluginConfig>,
20
+ ): ITtscPlugin {
21
+ return {
22
+ name: "@ttsc/lint",
23
+ native: {
24
+ mode: "ttsc-lint",
25
+ source: {
26
+ dir: path.resolve(__dirname, ".."),
27
+ entry: "./plugin",
28
+ },
29
+ contractVersion: 1,
30
+ capabilities: ["check"],
31
+ },
32
+ };
33
+ }
34
+
35
+ export default createTtscPlugin;
@@ -0,0 +1,6 @@
1
+ import type { ITtscLintRule } from "./ITtscLintRule";
2
+ import type { ITtscLintSeverity } from "./ITtscLintSeverity";
3
+
4
+ export type ITtscLintConfig = {
5
+ [P in ITtscLintRule]?: ITtscLintSeverity;
6
+ };
@@ -0,0 +1,131 @@
1
+ export type ITtscLintRule =
2
+ | "adjacent-overload-signatures"
3
+ | "array-type"
4
+ | "ban-ts-comment"
5
+ | "ban-tslint-comment"
6
+ | "consistent-indexed-object-style"
7
+ | "consistent-type-assertions"
8
+ | "consistent-type-definitions"
9
+ | "consistent-type-imports"
10
+ | "dot-notation"
11
+ | "eqeqeq"
12
+ | "for-direction"
13
+ | "no-alert"
14
+ | "no-array-constructor"
15
+ | "no-array-delete"
16
+ | "no-async-promise-executor"
17
+ | "no-bitwise"
18
+ | "no-caller"
19
+ | "no-case-declarations"
20
+ | "no-class-assign"
21
+ | "no-compare-neg-zero"
22
+ | "no-cond-assign"
23
+ | "no-confusing-non-null-assertion"
24
+ | "no-console"
25
+ | "no-constant-condition"
26
+ | "no-continue"
27
+ | "no-control-regex"
28
+ | "no-debugger"
29
+ | "no-delete-var"
30
+ | "no-dupe-args"
31
+ | "no-dupe-else-if"
32
+ | "no-dupe-keys"
33
+ | "no-duplicate-case"
34
+ | "no-duplicate-enum-values"
35
+ | "no-dynamic-delete"
36
+ | "no-empty"
37
+ | "no-empty-character-class"
38
+ | "no-empty-function"
39
+ | "no-empty-interface"
40
+ | "no-empty-object-type"
41
+ | "no-empty-pattern"
42
+ | "no-empty-static-block"
43
+ | "no-eq-null"
44
+ | "no-eval"
45
+ | "no-ex-assign"
46
+ | "no-explicit-any"
47
+ | "no-extra-bind"
48
+ | "no-extra-boolean-cast"
49
+ | "no-extra-non-null-assertion"
50
+ | "no-fallthrough"
51
+ | "no-func-assign"
52
+ | "no-inferrable-types"
53
+ | "no-inner-declarations"
54
+ | "no-irregular-whitespace"
55
+ | "no-iterator"
56
+ | "no-labels"
57
+ | "no-lone-blocks"
58
+ | "no-lonely-if"
59
+ | "no-loss-of-precision"
60
+ | "no-misleading-character-class"
61
+ | "no-misused-new"
62
+ | "no-multi-assign"
63
+ | "no-multi-str"
64
+ | "no-namespace"
65
+ | "no-negated-condition"
66
+ | "no-nested-ternary"
67
+ | "no-new"
68
+ | "no-new-func"
69
+ | "no-new-wrappers"
70
+ | "no-non-null-asserted-nullish-coalescing"
71
+ | "no-non-null-asserted-optional-chain"
72
+ | "no-non-null-assertion"
73
+ | "no-obj-calls"
74
+ | "no-object-constructor"
75
+ | "no-octal"
76
+ | "no-octal-escape"
77
+ | "no-plusplus"
78
+ | "no-promise-executor-return"
79
+ | "no-proto"
80
+ | "no-prototype-builtins"
81
+ | "no-regex-spaces"
82
+ | "no-require-imports"
83
+ | "no-return-assign"
84
+ | "no-script-url"
85
+ | "no-self-assign"
86
+ | "no-self-compare"
87
+ | "no-sequences"
88
+ | "no-setter-return"
89
+ | "no-shadow-restricted-names"
90
+ | "no-sparse-arrays"
91
+ | "no-template-curly-in-string"
92
+ | "no-this-alias"
93
+ | "no-throw-literal"
94
+ | "no-undef-init"
95
+ | "no-undefined"
96
+ | "no-unnecessary-type-constraint"
97
+ | "no-unneeded-ternary"
98
+ | "no-unsafe-declaration-merging"
99
+ | "no-unsafe-finally"
100
+ | "no-unsafe-function-type"
101
+ | "no-unsafe-negation"
102
+ | "no-unused-expressions"
103
+ | "no-unused-labels"
104
+ | "no-useless-call"
105
+ | "no-useless-catch"
106
+ | "no-useless-computed-key"
107
+ | "no-useless-concat"
108
+ | "no-useless-constructor"
109
+ | "no-useless-rename"
110
+ | "no-var"
111
+ | "no-with"
112
+ | "no-wrapper-object-types"
113
+ | "object-shorthand"
114
+ | "operator-assignment"
115
+ | "prefer-as-const"
116
+ | "prefer-const"
117
+ | "prefer-enum-initializers"
118
+ | "prefer-exponentiation-operator"
119
+ | "prefer-for-of"
120
+ | "prefer-function-type"
121
+ | "prefer-literal-enum-member"
122
+ | "prefer-namespace-keyword"
123
+ | "prefer-spread"
124
+ | "prefer-template"
125
+ | "radix"
126
+ | "require-yield"
127
+ | "triple-slash-reference"
128
+ | "use-isnan"
129
+ | "valid-typeof"
130
+ | "vars-on-top"
131
+ | "yoda";
@@ -0,0 +1 @@
1
+ export type ITtscLintSeverity = "off" | "warning" | "warn" | "error" | 0 | 1 | 2;
package/tsconfig.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "../../config/tsconfig.json",
3
+ "compilerOptions": {
4
+ "ignoreDeprecations": "6.0",
5
+ "moduleResolution": "bundler",
6
+ "outDir": "lib",
7
+ "rootDir": "src"
8
+ },
9
+ "include": ["src"]
10
+ }
package/src/index.cjs DELETED
@@ -1,29 +0,0 @@
1
- // @ts-check
2
- "use strict";
3
-
4
- const path = require("node:path");
5
-
6
- /**
7
- * `@ttsc/lint` plugin descriptor.
8
- *
9
- * The `rules` field on the tsconfig plugin entry flows straight through to
10
- * the native binary via `--plugins-json`. Documented severity values are
11
- * `"off"`, `"warning"`, or `"error"`.
12
- *
13
- * @param {Record<string, unknown>} _config
14
- * @returns {{ name: string; native: { mode: string; source: { dir: string; entry: string }; contractVersion: 1; capabilities: string[] } }}
15
- */
16
- module.exports = function createTtscLint(_config) {
17
- return {
18
- name: "@ttsc/lint",
19
- native: {
20
- mode: "ttsc-lint",
21
- source: {
22
- dir: path.resolve(__dirname, ".."),
23
- entry: "./plugin",
24
- },
25
- contractVersion: 1,
26
- capabilities: ["check"],
27
- },
28
- };
29
- };