pi-gitnexus-fork 0.7.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/.github/workflows/ci.yml +20 -0
- package/.gitnexusignore +11 -0
- package/.sg-rules/async-function-must-await-or-return.yml +55 -0
- package/.sg-rules/catch-must-log-error.yml +78 -0
- package/.sg-rules/class-must-implement-or-extend.yml +61 -0
- package/.sg-rules/class-property-must-be-readonly.yml +61 -0
- package/.sg-rules/error-must-extend-base.yml +56 -0
- package/.sg-rules/generic-must-be-constrained.yml +60 -0
- package/.sg-rules/import-reexport-risk.yml +9 -0
- package/.sg-rules/missing-session-id-in-api.yml +16 -0
- package/.sg-rules/no-any-in-generic-args.yml +57 -0
- package/.sg-rules/no-await-in-promise-all.yml +28 -0
- package/.sg-rules/no-barrel-export.yml +17 -0
- package/.sg-rules/no-bq-write-in-module.yml +65 -0
- package/.sg-rules/no-console-except-error.yml +27 -0
- package/.sg-rules/no-console-in-server.yml +42 -0
- package/.sg-rules/no-empty-catch.yml +20 -0
- package/.sg-rules/no-empty-function.yml +24 -0
- package/.sg-rules/no-eval.yml +28 -0
- package/.sg-rules/no-explicit-any.yml +34 -0
- package/.sg-rules/no-hardcoded-placeholder-string.yml +23 -0
- package/.sg-rules/no-hardcoded-secrets.yml +32 -0
- package/.sg-rules/no-innerHTML.yml +22 -0
- package/.sg-rules/no-json-parse-without-trycatch.yml +33 -0
- package/.sg-rules/no-magic-numbers.yml +25 -0
- package/.sg-rules/no-nested-ternary.yml +21 -0
- package/.sg-rules/no-non-null-assertion.yml +25 -0
- package/.sg-rules/no-stub-implementation.yml +44 -0
- package/.sg-rules/no-throw-literal.yml +50 -0
- package/.sg-rules/no-todo-comment.yml +24 -0
- package/.sg-rules/no-ts-ignore-comment.yml +48 -0
- package/.sg-rules/no-type-assertion-in-jsx.yml +23 -0
- package/.sg-rules/no-unguarded-trim.yml +24 -0
- package/.sg-rules/no-unknown-without-narrowing.yml +76 -0
- package/.sg-rules/no-unsafe-bracket-access.yml +58 -0
- package/.sg-rules/no-unsafe-type-assertion.yml +45 -0
- package/.sg-rules/switch-must-be-exhaustive.yml +62 -0
- package/.sg-rules/zod-async-refine-without-abort.yml +62 -0
- package/.sg-rules/zod-enum-unsafe-access.yml +59 -0
- package/.sg-rules/zod-nested-object-deep-path.yml +70 -0
- package/.sg-rules/zod-optional-without-default-in-route.yml +50 -0
- package/.sg-rules/zod-parse-not-safe.yml +42 -0
- package/.sg-rules/zod-preprocess-without-fallback.yml +58 -0
- package/.sg-rules/zod-refine-no-return-undefined.yml +54 -0
- package/.sg-rules/zod-transform-without-output-type.yml +52 -0
- package/.sg-sha +1 -0
- package/.sgignore +4 -0
- package/AGENTS.md +1 -0
- package/CHANGELOG.md +99 -0
- package/LICENSE +21 -0
- package/README.md +113 -0
- package/biome.json +25 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/clover.xml +890 -0
- package/coverage/coverage-final.json +12 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +131 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/coverage/src/augment-remote.ts.html +274 -0
- package/coverage/src/gitnexus.ts.html +1363 -0
- package/coverage/src/index.html +236 -0
- package/coverage/src/index.ts.html +1561 -0
- package/coverage/src/mcp-client-factory.ts.html +367 -0
- package/coverage/src/mcp-client-stdio.ts.html +736 -0
- package/coverage/src/mcp-client.ts.html +568 -0
- package/coverage/src/remote-mcp-client.ts.html +709 -0
- package/coverage/src/repo-resolver.ts.html +526 -0
- package/coverage/src/tools.ts.html +970 -0
- package/coverage/src/ui/index.html +131 -0
- package/coverage/src/ui/main-menu.ts.html +502 -0
- package/coverage/src/ui/settings-menu.ts.html +460 -0
- package/dist/augment-remote.d.ts +11 -0
- package/dist/augment-remote.js +55 -0
- package/dist/gitnexus.d.ts +103 -0
- package/dist/gitnexus.js +410 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +479 -0
- package/dist/mcp-client-factory.d.ts +19 -0
- package/dist/mcp-client-factory.js +78 -0
- package/dist/mcp-client-stdio.d.ts +35 -0
- package/dist/mcp-client-stdio.js +186 -0
- package/dist/mcp-client.d.ts +45 -0
- package/dist/mcp-client.js +145 -0
- package/dist/remote-mcp-client.d.ts +43 -0
- package/dist/remote-mcp-client.js +181 -0
- package/dist/repo-resolver.d.ts +47 -0
- package/dist/repo-resolver.js +123 -0
- package/dist/tools.d.ts +6 -0
- package/dist/tools.js +230 -0
- package/dist/ui/main-menu.d.ts +33 -0
- package/dist/ui/main-menu.js +102 -0
- package/dist/ui/settings-menu.d.ts +16 -0
- package/dist/ui/settings-menu.js +95 -0
- package/docs/design/remote-mcp-backend.md +153 -0
- package/media/screenshot.png +0 -0
- package/package.json +61 -0
- package/sgconfig.yml +4 -0
- package/skills/gitnexus-debugging/SKILL.md +84 -0
- package/skills/gitnexus-exploring/SKILL.md +73 -0
- package/skills/gitnexus-impact-analysis/SKILL.md +93 -0
- package/skills/gitnexus-pr-review/SKILL.md +109 -0
- package/skills/gitnexus-refactoring/SKILL.md +85 -0
- package/src/augment-remote.ts +63 -0
- package/src/gitnexus.ts +426 -0
- package/src/index.ts +492 -0
- package/src/mcp-client-factory.ts +94 -0
- package/src/mcp-client-stdio.ts +217 -0
- package/src/mcp-client.ts +208 -0
- package/src/remote-mcp-client.ts +250 -0
- package/src/repo-resolver.ts +147 -0
- package/src/tools.ts +295 -0
- package/src/ui/main-menu.ts +139 -0
- package/src/ui/settings-menu.ts +125 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# SOURCE: https://getpino.io/#/docs/api?id=logger
|
|
2
|
+
# "Pino is a structured JSON logger. Use it instead of console for production logging.
|
|
3
|
+
# console.log produces unstructured output that's hard to query in log aggregation systems."
|
|
4
|
+
# SOURCE: https://rules.sonarsource.com/typescript/RSPEC-4794/
|
|
5
|
+
# SonarQube S4794: "Using console logging in production code is a security and performance risk."
|
|
6
|
+
# Rationale: This is the server-side companion to no-console-except-error (which is in common/).
|
|
7
|
+
# Server code should ALWAYS use pino (injected via Fastify request.log or a shared logger).
|
|
8
|
+
#
|
|
9
|
+
# REFINED: Only flags console.log, console.debug, console.trace, console.info.
|
|
10
|
+
# console.error and console.warn are legitimate error/warning logging and are NOT flagged.
|
|
11
|
+
id: no-console-in-server
|
|
12
|
+
language: typescript
|
|
13
|
+
message: "console.log/debug/info/trace in server code — use request.log (Fastify pino) or the shared logger instead. Structured logs are required for Cloud Run log aggregation."
|
|
14
|
+
severity: warning
|
|
15
|
+
note: |
|
|
16
|
+
Flags unstructured console output (log, debug, trace, info) in server-side code.
|
|
17
|
+
These produce output without: request ID, timestamp, trace context, or log level.
|
|
18
|
+
|
|
19
|
+
console.error and console.warn are NOT flagged — they are legitimate for error/warning
|
|
20
|
+
logging and produce properly tagged output (stderr with error/warn level markers).
|
|
21
|
+
rule:
|
|
22
|
+
pattern: console.$METHOD($$$)
|
|
23
|
+
constraints:
|
|
24
|
+
METHOD:
|
|
25
|
+
# Only unstructured output methods — NOT error or warn
|
|
26
|
+
regex: '^(log|debug|trace|info)$'
|
|
27
|
+
paths:
|
|
28
|
+
- '**/api/**'
|
|
29
|
+
- '**/server/**'
|
|
30
|
+
- '**/routes/**'
|
|
31
|
+
- '**/src/index.ts'
|
|
32
|
+
- '**/src/app.ts'
|
|
33
|
+
- '**/src/server.ts'
|
|
34
|
+
ignores:
|
|
35
|
+
- '**/*.test.ts'
|
|
36
|
+
- '**/*.spec.ts'
|
|
37
|
+
- '**/test/**'
|
|
38
|
+
- '**/tests/**'
|
|
39
|
+
- '**/__tests__/**'
|
|
40
|
+
- '**/scripts/**'
|
|
41
|
+
- '**/migrations/**'
|
|
42
|
+
- 'test-*.ts'
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# SOURCE: https://eslint.org/docs/latest/rules/no-empty
|
|
2
|
+
# SOURCE: https://rules.sonarsource.com/typescript/RSPEC-108/
|
|
3
|
+
id: no-empty-catch
|
|
4
|
+
message: Empty catch block silently swallows errors — handle the error or add a comment explaining why it's intentionally ignored
|
|
5
|
+
severity: warning
|
|
6
|
+
language: TypeScript
|
|
7
|
+
note: Mirrors ESLint no-empty and SonarQube S108. Catch blocks with comments are acceptable.
|
|
8
|
+
rule:
|
|
9
|
+
kind: statement_block
|
|
10
|
+
pattern: '{}'
|
|
11
|
+
inside:
|
|
12
|
+
kind: catch_clause
|
|
13
|
+
ignores:
|
|
14
|
+
- '**/*.test.ts'
|
|
15
|
+
- '**/*.spec.ts'
|
|
16
|
+
- '**/test/**'
|
|
17
|
+
- '**/tests/**'
|
|
18
|
+
- '**/__tests__/**'
|
|
19
|
+
- '**/scripts/**'
|
|
20
|
+
- 'test-*.ts'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# SOURCE: https://eslint.org/docs/latest/rules/no-empty-function
|
|
2
|
+
# SOURCE: https://rules.sonarsource.com/typescript/RSPEC-1186/
|
|
3
|
+
id: no-empty-function
|
|
4
|
+
message: Empty function body — either implement, add a comment explaining why empty, or throw NotImplementedError
|
|
5
|
+
severity: warning
|
|
6
|
+
language: TypeScript
|
|
7
|
+
note: Mirrors ESLint no-empty-function and SonarQube S1186. Empty functions with comments inside are acceptable.
|
|
8
|
+
rule:
|
|
9
|
+
kind: statement_block
|
|
10
|
+
pattern: '{}'
|
|
11
|
+
inside:
|
|
12
|
+
any:
|
|
13
|
+
- kind: function_declaration
|
|
14
|
+
- kind: function_expression
|
|
15
|
+
- kind: arrow_function
|
|
16
|
+
- kind: method_definition
|
|
17
|
+
ignores:
|
|
18
|
+
- '**/*.test.ts'
|
|
19
|
+
- '**/*.spec.ts'
|
|
20
|
+
- '**/test/**'
|
|
21
|
+
- '**/tests/**'
|
|
22
|
+
- '**/__tests__/**'
|
|
23
|
+
- '**/scripts/**'
|
|
24
|
+
- 'test-*.ts'
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# SOURCE: https://eslint.org/docs/latest/rules/no-eval
|
|
2
|
+
# ESLint no-eval: "Eliminate eval() and its counterparts."
|
|
3
|
+
# SOURCE: https://rules.sonarsource.com/javascript/RSPEC-1528/
|
|
4
|
+
# SonarQube S1528: "eval" and "new Function" should not be used.
|
|
5
|
+
# SOURCE: https://ast-grep.github.io/catalog/typescript/no-eval.html
|
|
6
|
+
# ast-grep catalog rule for eval detection.
|
|
7
|
+
id: no-eval
|
|
8
|
+
language: TypeScript
|
|
9
|
+
message: "Avoid eval() / new Function() / setTimeout(string) / setInterval(string) — code injection risk"
|
|
10
|
+
severity: error
|
|
11
|
+
note: "Mirrors ESLint no-eval and SonarQube S1528. String arguments to setTimeout/setInterval act as eval."
|
|
12
|
+
rule:
|
|
13
|
+
any:
|
|
14
|
+
- pattern: eval($$$ARGS)
|
|
15
|
+
- pattern: new Function($$$ARGS)
|
|
16
|
+
- pattern: setTimeout($STR, $$$)
|
|
17
|
+
- pattern: setInterval($STR, $$$)
|
|
18
|
+
constraints:
|
|
19
|
+
STR:
|
|
20
|
+
kind: string
|
|
21
|
+
# Only match when first arg is a string literal (not a function reference)
|
|
22
|
+
ignores:
|
|
23
|
+
- '**/*.test.ts'
|
|
24
|
+
- '**/*.spec.ts'
|
|
25
|
+
- '**/test/**'
|
|
26
|
+
- '**/tests/**'
|
|
27
|
+
- '**/__tests__/**'
|
|
28
|
+
- '**/scripts/**'
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# SOURCE: https://typescript-eslint.io/rules/no-explicit-any/
|
|
2
|
+
# @typescript-eslint/no-explicit-any: "Disallow the any type."
|
|
3
|
+
# SOURCE: https://rules.sonarsource.com/typescript/RSPEC-4328/
|
|
4
|
+
# SonarQube S4328: "ANY type should not be used."
|
|
5
|
+
# SOURCE: https://google.github.io/styleguide/tsguide.html#typescript
|
|
6
|
+
# Google TypeScript Style Guide: "Avoid using any."
|
|
7
|
+
id: no-explicit-any
|
|
8
|
+
language: TypeScript
|
|
9
|
+
message: "Avoid explicit any — use a proper type, generic, or unknown"
|
|
10
|
+
severity: warning
|
|
11
|
+
note: "Mirrors @typescript-eslint/no-explicit-any and SonarQube S4328. any disables all type safety."
|
|
12
|
+
rule:
|
|
13
|
+
any:
|
|
14
|
+
- pattern: $X as any
|
|
15
|
+
- kind: predefined_type
|
|
16
|
+
pattern: any
|
|
17
|
+
inside:
|
|
18
|
+
any:
|
|
19
|
+
- kind: type_annotation
|
|
20
|
+
- kind: type_arguments
|
|
21
|
+
- kind: as_expression
|
|
22
|
+
- kind: tuple_type
|
|
23
|
+
- kind: array_type
|
|
24
|
+
- kind: union_type
|
|
25
|
+
- kind: intersection_type
|
|
26
|
+
ignores:
|
|
27
|
+
- '**/*.test.ts'
|
|
28
|
+
- '**/*.spec.ts'
|
|
29
|
+
- '**/test/**'
|
|
30
|
+
- '**/tests/**'
|
|
31
|
+
- '**/__tests__/**'
|
|
32
|
+
- '**/scripts/**'
|
|
33
|
+
- 'test-*.ts'
|
|
34
|
+
- '**/*.d.ts'
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# SOURCE: https://eslint.org/docs/latest/rules/no-magic-numbers
|
|
2
|
+
# SOURCE: https://rules.sonarsource.com/typescript/RSPEC-131/ (magic numbers)
|
|
3
|
+
id: no-hardcoded-placeholder-string
|
|
4
|
+
message: Hardcoded placeholder string detected — replace with actual value or configuration
|
|
5
|
+
severity: warning
|
|
6
|
+
language: TypeScript
|
|
7
|
+
note: Detects strings containing placeholder markers like TODO, FIXME, INSERT, REPLACE, STUB, PLACEHOLDER in production code.
|
|
8
|
+
rule:
|
|
9
|
+
any:
|
|
10
|
+
- pattern: '"$VALUE"'
|
|
11
|
+
- pattern: "'$VALUE'"
|
|
12
|
+
constraints:
|
|
13
|
+
VALUE:
|
|
14
|
+
regex: '(?i)^(TODO|FIXME|STUB|PLACEHOLDER|INSERT .+|REPLACE .+|NOT IMPLEMENTED)$'
|
|
15
|
+
ignores:
|
|
16
|
+
- '**/*.test.ts'
|
|
17
|
+
- '**/*.spec.ts'
|
|
18
|
+
- '**/test/**'
|
|
19
|
+
- '**/tests/**'
|
|
20
|
+
- '**/__tests__/**'
|
|
21
|
+
- '**/__mocks__/**'
|
|
22
|
+
- '**/scripts/**'
|
|
23
|
+
- 'test-*.ts'
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# SOURCE: https://github.com/gitleaks/gitleaks/blob/master/config/gitleaks.toml
|
|
2
|
+
# Gitleaks default config: regex patterns for passwords, API keys, tokens, private keys.
|
|
3
|
+
# SOURCE: https://rules.sonarsource.com/typescript/RSPEC-2068/
|
|
4
|
+
# SonarQube S2068: "Hardcoded credentials should not be used in source code."
|
|
5
|
+
# SOURCE: https://github.com/returntocorp/semgrep-rules/blob/main/javascript/lang/security/no-hardcoded-secrets.yaml
|
|
6
|
+
# Semgrep community rule for hardcoded secret detection.
|
|
7
|
+
id: no-hardcoded-secrets
|
|
8
|
+
language: TypeScript
|
|
9
|
+
message: "Hardcoded credentials detected — use environment variables or secrets manager"
|
|
10
|
+
severity: error
|
|
11
|
+
note: "Mirrors Gitleaks, SonarQube S2068, and Semgrep no-hardcoded-secrets. Catches password/secret/token/credential patterns."
|
|
12
|
+
rule:
|
|
13
|
+
any:
|
|
14
|
+
- pattern: const $KEY = '$VAL'
|
|
15
|
+
- pattern: $OBJ['$KEY'] = '$VAL'
|
|
16
|
+
- pattern: $OBJ.$KEY = '$VAL'
|
|
17
|
+
constraints:
|
|
18
|
+
KEY:
|
|
19
|
+
regex: '(?i)(password|secret|api[_-]?key|token|credential|private[_-]?key|auth[_-]?key|access[_-]?key)'
|
|
20
|
+
VAL:
|
|
21
|
+
regex: '[a-zA-Z0-9+/=_-]{8,}'
|
|
22
|
+
ignores:
|
|
23
|
+
- '**/*.test.ts'
|
|
24
|
+
- '**/*.spec.ts'
|
|
25
|
+
- '**/test/**'
|
|
26
|
+
- '**/tests/**'
|
|
27
|
+
- '**/__tests__/**'
|
|
28
|
+
- '**/__mocks__/**'
|
|
29
|
+
- '**/scripts/**'
|
|
30
|
+
- 'test-*.ts'
|
|
31
|
+
- '**/*.example*'
|
|
32
|
+
- '**/*.md'
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# SOURCE: https://github.com/mozilla/eslint-plugin-no-unsanitized/blob/master/rules/no-unsanitized-property.md
|
|
2
|
+
# Mozilla eslint-plugin-no-unsanitized: flags innerHTML/outerHTML assignments with unsanitized values.
|
|
3
|
+
# SOURCE: https://rules.sonarsource.com/typescript/RSPEC-2819/
|
|
4
|
+
# SonarQube S2819: "DOM properties should not be misused — innerHTML with untrusted data is XSS."
|
|
5
|
+
# SOURCE: https://websitesecurityscanner.org/alerts/dom-xss-innerhtml/
|
|
6
|
+
# DOM XSS via innerHTML is OWASP A03:2021 Injection.
|
|
7
|
+
id: no-innerHTML
|
|
8
|
+
language: TypeScript
|
|
9
|
+
message: "Avoid .innerHTML / .outerHTML assignment — XSS risk, use textContent or DOM API"
|
|
10
|
+
severity: error
|
|
11
|
+
note: "Mirrors Mozilla no-unsanitized and SonarQube S2819. Direct innerHTML assignment is the #1 DOM XSS vector."
|
|
12
|
+
rule:
|
|
13
|
+
any:
|
|
14
|
+
- pattern: $EL.innerHTML = $VAL
|
|
15
|
+
- pattern: $EL.outerHTML = $VAL
|
|
16
|
+
ignores:
|
|
17
|
+
- '**/*.test.ts'
|
|
18
|
+
- '**/*.spec.ts'
|
|
19
|
+
- '**/test/**'
|
|
20
|
+
- '**/tests/**'
|
|
21
|
+
- '**/__tests__/**'
|
|
22
|
+
- '**/scripts/**'
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# SOURCE: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse
|
|
2
|
+
# "JSON.parse() throws SyntaxError if the string is not valid JSON."
|
|
3
|
+
# SOURCE: https://typescript-eslint.io/rules/no-unsafe-assignment/
|
|
4
|
+
# TypeScript ESLint: unvalidated external data is a security risk.
|
|
5
|
+
# SOURCE: https://rules.sonarsource.com/typescript/RSPEC-4715/
|
|
6
|
+
# SonarQube S4715: "JSON.parse should not be used without error handling."
|
|
7
|
+
#
|
|
8
|
+
# NOTE: framework/bun/safe-json-parse.yml covers this for Bun projects.
|
|
9
|
+
# This rule covers the general TypeScript case (Node.js, Fastify, React).
|
|
10
|
+
id: no-json-parse-without-trycatch
|
|
11
|
+
language: typescript
|
|
12
|
+
message: "JSON.parse without try/catch — throws SyntaxError on malformed input. Wrap in try/catch or use safeParse-style helper"
|
|
13
|
+
severity: warning
|
|
14
|
+
note: |
|
|
15
|
+
JSON.parse() is the only standard JSON parser in JS and it throws on any invalid input.
|
|
16
|
+
In server-side code, malformed JSON from external sources (request bodies, config files,
|
|
17
|
+
external APIs) will crash the handler. Wrap in try/catch with a descriptive error message.
|
|
18
|
+
rule:
|
|
19
|
+
pattern: JSON.parse($ARG)
|
|
20
|
+
not:
|
|
21
|
+
inside:
|
|
22
|
+
kind: try_statement
|
|
23
|
+
has:
|
|
24
|
+
kind: catch_clause
|
|
25
|
+
stopBy: end
|
|
26
|
+
ignores:
|
|
27
|
+
- '**/*.test.ts'
|
|
28
|
+
- '**/*.spec.ts'
|
|
29
|
+
- '**/test/**'
|
|
30
|
+
- '**/tests/**'
|
|
31
|
+
- '**/__tests__/**'
|
|
32
|
+
- '**/scripts/**'
|
|
33
|
+
- 'test-*.ts'
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# SOURCE: https://eslint.org/docs/latest/rules/no-magic-numbers
|
|
2
|
+
# ESLint no-magic-numbers: "Disallow magic numbers — numbers should be named constants."
|
|
3
|
+
# SOURCE: https://rules.sonarsource.com/typescript/RSPEC-1094/
|
|
4
|
+
# SonarQube S109: "Magic numbers should not be used."
|
|
5
|
+
id: no-magic-numbers
|
|
6
|
+
language: TypeScript
|
|
7
|
+
message: "Magic number detected — extract to a named constant"
|
|
8
|
+
severity: hint
|
|
9
|
+
note: "Mirrors ESLint no-magic-numbers and SonarQube S109. Flags numeric literals > 1 in comparisons."
|
|
10
|
+
rule:
|
|
11
|
+
pattern: $X === $NUM
|
|
12
|
+
constraints:
|
|
13
|
+
NUM:
|
|
14
|
+
regex: '[2-9]'
|
|
15
|
+
ignores:
|
|
16
|
+
- '**/*.test.ts'
|
|
17
|
+
- '**/*.spec.ts'
|
|
18
|
+
- '**/test/**'
|
|
19
|
+
- '**/tests/**'
|
|
20
|
+
- '**/__tests__/**'
|
|
21
|
+
- '**/scripts/**'
|
|
22
|
+
- 'test-*.ts'
|
|
23
|
+
- '**/*.d.ts'
|
|
24
|
+
- '**/const*'
|
|
25
|
+
- '**/constants*'
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# SOURCE: https://eslint.org/docs/latest/rules/no-nested-ternary
|
|
2
|
+
# ESLint no-nested-ternary: "Disallow nested ternary expressions."
|
|
3
|
+
# SOURCE: https://github.com/airbnb/javascript/blob/master/packages/eslint-config-airbnb-base/rules/style.js
|
|
4
|
+
# Airbnb style guide: "Ternaries should not be nested."
|
|
5
|
+
id: no-nested-ternary
|
|
6
|
+
language: TypeScript
|
|
7
|
+
message: "Avoid nested ternary — extract to a variable or use if/else"
|
|
8
|
+
severity: warning
|
|
9
|
+
note: "Mirrors ESLint no-nested-ternary and Airbnb style guide. Nested ternaries are unreadable."
|
|
10
|
+
rule:
|
|
11
|
+
kind: ternary_expression
|
|
12
|
+
has:
|
|
13
|
+
kind: ternary_expression
|
|
14
|
+
ignores:
|
|
15
|
+
- '**/*.test.ts'
|
|
16
|
+
- '**/*.spec.ts'
|
|
17
|
+
- '**/test/**'
|
|
18
|
+
- '**/tests/**'
|
|
19
|
+
- '**/__tests__/**'
|
|
20
|
+
- '**/scripts/**'
|
|
21
|
+
- 'test-*.ts'
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# SOURCE: https://typescript-eslint.io/rules/no-non-null-assertion/
|
|
2
|
+
# @typescript-eslint/no-non-null-assertion: "Disallow non-null assertions using the ! postfix operator."
|
|
3
|
+
# SOURCE: https://rules.sonarsource.com/typescript/RSPEC-6557/
|
|
4
|
+
# SonarQube S6557: "Non-null assertions should not be used."
|
|
5
|
+
id: no-non-null-assertion
|
|
6
|
+
language: TypeScript
|
|
7
|
+
message: "Avoid non-null assertion (!) — use proper null checks or optional chaining"
|
|
8
|
+
severity: warning
|
|
9
|
+
note: "Mirrors @typescript-eslint/no-non-null-assertion and SonarQube S6557. The ! operator lies to the compiler."
|
|
10
|
+
rule:
|
|
11
|
+
pattern: $X!
|
|
12
|
+
constraints:
|
|
13
|
+
X:
|
|
14
|
+
not:
|
|
15
|
+
pattern: $Y!
|
|
16
|
+
# We match the postfix ! operator on identifiers and member expressions
|
|
17
|
+
ignores:
|
|
18
|
+
- '**/*.test.ts'
|
|
19
|
+
- '**/*.spec.ts'
|
|
20
|
+
- '**/test/**'
|
|
21
|
+
- '**/tests/**'
|
|
22
|
+
- '**/__tests__/**'
|
|
23
|
+
- '**/scripts/**'
|
|
24
|
+
- 'test-*.ts'
|
|
25
|
+
- '**/*.d.ts'
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# SOURCE: coding-guard internal — comprehensive stub/placeholder detection
|
|
2
|
+
# SOURCE: https://rules.sonarsource.com/typescript/RSPEC-4658/ (placeholder usage)
|
|
3
|
+
# SOURCE: https://rules.sonarsource.com/typescript/RSPEC-1155/ (empty/placeholder implementations)
|
|
4
|
+
id: no-stub-implementation
|
|
5
|
+
message: "Stub/placeholder/incomplete implementation detected — replace with real code"
|
|
6
|
+
severity: error
|
|
7
|
+
language: TypeScript
|
|
8
|
+
note: |
|
|
9
|
+
Comprehensive anti-evasion stub detector.
|
|
10
|
+
|
|
11
|
+
Keywords: stub, not yet implemented, deferred, work around, monkey patch,
|
|
12
|
+
placeholder, hack, temporary, fixme, wip, todo: implement, not implemented
|
|
13
|
+
|
|
14
|
+
Contexts: throw Error (any subclass), console.log/warn/error/info/debug
|
|
15
|
+
|
|
16
|
+
Evasion resistance:
|
|
17
|
+
- String concatenation: 'st' + 'ub' → caught via per-char gaps in $MSG text
|
|
18
|
+
- Template literals: `stub response` → caught via same regex
|
|
19
|
+
- Different Error types: TypeError/RangeError/etc → $ERR matches any class
|
|
20
|
+
|
|
21
|
+
Note: does NOT match `return` statements to avoid false positives from
|
|
22
|
+
prose/template strings containing incidental keyword matches.
|
|
23
|
+
rule:
|
|
24
|
+
any:
|
|
25
|
+
# ── throw patterns (any Error subclass) ──
|
|
26
|
+
- pattern: throw new $ERR($MSG)
|
|
27
|
+
# ── console patterns ──
|
|
28
|
+
- pattern: console.log($MSG)
|
|
29
|
+
- pattern: console.warn($MSG)
|
|
30
|
+
- pattern: console.error($MSG)
|
|
31
|
+
- pattern: console.info($MSG)
|
|
32
|
+
- pattern: console.debug($MSG)
|
|
33
|
+
constraints:
|
|
34
|
+
MSG:
|
|
35
|
+
regex: '(?i)(s[\W_]{0,5}t[\W_]{0,5}u[\W_]{0,5}b|h[\W_]{0,5}a[\W_]{0,5}c[\W_]{0,5}k|w[\W_]{0,5}i[\W_]{0,5}p|not.{0,15}implement|deferred|work.?-?around|monkey.?-?patch|placeholder|temporary|fixme|todo.{0,20}implement)'
|
|
36
|
+
ignores:
|
|
37
|
+
- '**/*.test.ts'
|
|
38
|
+
- '**/*.spec.ts'
|
|
39
|
+
- '**/test/**'
|
|
40
|
+
- '**/tests/**'
|
|
41
|
+
- '**/__tests__/**'
|
|
42
|
+
- '**/__mocks__/**'
|
|
43
|
+
- '**/scripts/**'
|
|
44
|
+
- '**/fixtures/**'
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# SOURCE: https://www.typescriptlang.org/docs/handbook/2/functions.html#optional-parameters-in-callbacks
|
|
2
|
+
# "Use explicit return types on methods that return promises to avoid accidentally
|
|
3
|
+
# returning void (floating promises)."
|
|
4
|
+
# SOURCE: https://typescript-book.com/exceptions/dont-throw-use-errors
|
|
5
|
+
# "throw 'string' or throw 42 bypasses Error stack trace capture. Always throw
|
|
6
|
+
# an Error subclass with proper context."
|
|
7
|
+
# SOURCE: https://kentcdodds.com/blog/get-a-catch-block-error-message-with-typescript
|
|
8
|
+
# "throw new Error() captures stack. throw 'message' does not."
|
|
9
|
+
id: no-throw-literal
|
|
10
|
+
language: typescript
|
|
11
|
+
message: "throw with non-Error value — no stack trace captured. Use throw new Error() or throw new AppError() for proper stack traces"
|
|
12
|
+
severity: error
|
|
13
|
+
note: |
|
|
14
|
+
UNSAFE:
|
|
15
|
+
throw 'Something went wrong'
|
|
16
|
+
throw 404
|
|
17
|
+
throw { message: 'failed', code: 'ERR_FAIL' }
|
|
18
|
+
throw response.statusText
|
|
19
|
+
|
|
20
|
+
SAFE:
|
|
21
|
+
throw new Error('Something went wrong')
|
|
22
|
+
throw new AppError('FAILED', 'Something went wrong', 500)
|
|
23
|
+
throw new NotFoundError('User')
|
|
24
|
+
if (err instanceof Error) throw err;
|
|
25
|
+
|
|
26
|
+
WHY: Only `throw new Error()` (or subclass) captures a stack trace. Throwing strings,
|
|
27
|
+
numbers, or plain objects produces errors with no stack trace — you can see the error
|
|
28
|
+
message but have NO idea where it was thrown from. This makes production debugging
|
|
29
|
+
impossible. Rule enforces all throws use Error instances.
|
|
30
|
+
rule:
|
|
31
|
+
any:
|
|
32
|
+
- pattern: throw $LIT
|
|
33
|
+
not:
|
|
34
|
+
any:
|
|
35
|
+
# Safe: throwing Error instances
|
|
36
|
+
- pattern: throw new $ERR($$$ARGS)
|
|
37
|
+
- pattern: throw new $ERR
|
|
38
|
+
# Safe: rethrowing caught error
|
|
39
|
+
- inside:
|
|
40
|
+
kind: catch_clause
|
|
41
|
+
stopBy: end
|
|
42
|
+
pattern: throw $ERR
|
|
43
|
+
ignores:
|
|
44
|
+
- '**/*.test.ts'
|
|
45
|
+
- '**/*.spec.ts'
|
|
46
|
+
- '**/test/**'
|
|
47
|
+
- '**/tests/**'
|
|
48
|
+
- '**/__tests__/**'
|
|
49
|
+
- '**/scripts/**'
|
|
50
|
+
- 'test-*.ts'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# SOURCE: https://eslint.org/docs/latest/rules/no-warning-comments
|
|
2
|
+
# Terms: TODO/FIXME/HACK only (mirrors ESLint defaults). Word boundary + location:start.
|
|
3
|
+
# SOURCE: https://rules.sonarsource.com/typescript/RSPEC-1135/
|
|
4
|
+
# isLetterAround() guard — requires delimiter after marker to avoid FP.
|
|
5
|
+
# SOURCE: https://github.com/detekt/detekt/issues/6116
|
|
6
|
+
# Community consensus: require colon after marker (TODO: not just TODO).
|
|
7
|
+
id: no-todo-comment
|
|
8
|
+
message: 'TODO/FIXME/HACK comment found — track in issue tracker instead. ALWAYS callsout to the user WHENEVER encountering these TODO warning'
|
|
9
|
+
severity: warning
|
|
10
|
+
language: TypeScript
|
|
11
|
+
note: "Mirrors ESLint no-warning-comments (terms: TODO/FIXME/HACK, location: start) and SonarQube S1135."
|
|
12
|
+
rule:
|
|
13
|
+
kind: comment
|
|
14
|
+
regex: '(?i)\b(TODO|FIXME|HACK)\s*[::]'
|
|
15
|
+
ignores:
|
|
16
|
+
- '**/*.test.ts'
|
|
17
|
+
- '**/*.spec.ts'
|
|
18
|
+
- '**/*.test-d.ts'
|
|
19
|
+
- '**/test/**'
|
|
20
|
+
- '**/tests/**'
|
|
21
|
+
- '**/__tests__/**'
|
|
22
|
+
- '**/__mocks__/**'
|
|
23
|
+
- '**/scripts/**'
|
|
24
|
+
- 'test-*.ts'
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# SOURCE: https://typescript-eslint.io/rules/ban-ts-comment/
|
|
2
|
+
# typescript-eslint ban-ts-comment: by default disallows `@ts-ignore` and `@ts-nocheck`
|
|
3
|
+
# while allowing `@ts-expect-error` (with description). Recommended preset.
|
|
4
|
+
# SOURCE: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-9.html#-ts-expect-error-comments
|
|
5
|
+
# TypeScript 3.9 introduced `@ts-expect-error` precisely so that the suppression
|
|
6
|
+
# itself raises an error once the underlying issue is fixed — `@ts-ignore` does not.
|
|
7
|
+
# SOURCE: https://rules.sonarsource.com/typescript/RSPEC-6535/
|
|
8
|
+
# SonarQube S6535: "TypeScript directive comments should not be used to silence type errors."
|
|
9
|
+
id: no-ts-ignore-comment
|
|
10
|
+
language: TypeScript
|
|
11
|
+
message: "Replace @ts-ignore / @ts-nocheck with @ts-expect-error — the latter errors out once the underlying issue is fixed"
|
|
12
|
+
severity: warning
|
|
13
|
+
note: |
|
|
14
|
+
Mirrors typescript-eslint ban-ts-comment (recommended preset) and SonarQube S6535.
|
|
15
|
+
|
|
16
|
+
`@ts-ignore` silences the next line forever — even after the type bug is
|
|
17
|
+
fixed, the directive lingers as dead noise (and can hide new bugs).
|
|
18
|
+
`@ts-expect-error` flips the contract: it suppresses the error, but the
|
|
19
|
+
compiler reports an error if the next line type-checks cleanly, so
|
|
20
|
+
obsolete suppressions get flagged the moment they become obsolete.
|
|
21
|
+
`@ts-nocheck` opts an entire file out of type checking and is almost
|
|
22
|
+
never the right answer in a typed codebase.
|
|
23
|
+
|
|
24
|
+
BAD:
|
|
25
|
+
// @ts-ignore
|
|
26
|
+
const value: number = JSON.parse(raw);
|
|
27
|
+
|
|
28
|
+
// @ts-nocheck
|
|
29
|
+
// (silences the entire file)
|
|
30
|
+
|
|
31
|
+
GOOD:
|
|
32
|
+
// @ts-expect-error - upstream types are wrong, see DT#12345
|
|
33
|
+
const value: number = JSON.parse(raw);
|
|
34
|
+
|
|
35
|
+
rule:
|
|
36
|
+
kind: comment
|
|
37
|
+
regex: '@ts-(ignore|nocheck)\b'
|
|
38
|
+
ignores:
|
|
39
|
+
- '**/*.test.ts'
|
|
40
|
+
- '**/*.spec.ts'
|
|
41
|
+
- '**/*.test-d.ts'
|
|
42
|
+
- '**/test/**'
|
|
43
|
+
- '**/tests/**'
|
|
44
|
+
- '**/__tests__/**'
|
|
45
|
+
- '**/__mocks__/**'
|
|
46
|
+
- '**/scripts/**'
|
|
47
|
+
- 'test-*.ts'
|
|
48
|
+
- '**/*.d.ts'
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# SOURCE: https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-assertions
|
|
2
|
+
# TypeScript handbook: "Type assertions are a way to tell TypeScript 'trust me, I know what I'm doing.'
|
|
3
|
+
# The two syntaxes are angle-bracket and as-style, but angle-bracket syntax is NOT valid in JSX/TSX files."
|
|
4
|
+
# SOURCE: https://typescript-eslint.io/rules/consistent-type-assertions/
|
|
5
|
+
# @typescript-eslint/consistent-type-assertions: "Enforce consistent usage of type assertions."
|
|
6
|
+
id: no-type-assertion-in-jsx
|
|
7
|
+
language: typescript
|
|
8
|
+
message: "Angle-bracket type assertion (<Type>expr) conflicts with JSX syntax in TSX — use 'as' syntax instead"
|
|
9
|
+
severity: error
|
|
10
|
+
note: |
|
|
11
|
+
In TSX files, <Type>expr is ambiguous — TypeScript parses it as a JSX element, not a type assertion.
|
|
12
|
+
Use expr as Type instead. This is a hard error in TSX files, not a style preference.
|
|
13
|
+
rule:
|
|
14
|
+
pattern: <$TYPE>$EXPR
|
|
15
|
+
# ast-grep limitation: tree-sitter-typescript may parse this as JSX, not type assertion.
|
|
16
|
+
# If this rule doesn't fire, it's because the parser can't distinguish JSX from angle-bracket assertions.
|
|
17
|
+
# TypeScript itself handles this by banning angle-bracket assertions in TSX — this rule mirrors that.
|
|
18
|
+
ignores:
|
|
19
|
+
- '**/*.test.ts'
|
|
20
|
+
- '**/*.spec.ts'
|
|
21
|
+
- '**/test/**'
|
|
22
|
+
- '**/tests/**'
|
|
23
|
+
- '**/__tests__/**'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# SOURCE: coding-guard internal — detects .trim() calls in React render paths
|
|
2
|
+
id: no-unguarded-trim-in-render
|
|
3
|
+
message: "Unguarded .trim() in component — consider (val ?? '').trim() or val?.trim()"
|
|
4
|
+
severity: info
|
|
5
|
+
language: TypeScript
|
|
6
|
+
note: |
|
|
7
|
+
Flags .trim() calls in React component files (.tsx) that lack
|
|
8
|
+
null-safety guards. Use (value ?? '').trim() or value?.trim().
|
|
9
|
+
rule:
|
|
10
|
+
pattern: $OBJ.trim()
|
|
11
|
+
constraints:
|
|
12
|
+
OBJ:
|
|
13
|
+
regex: '^\w+(\.\w+)+$'
|
|
14
|
+
ignores:
|
|
15
|
+
- '**/*.test.ts'
|
|
16
|
+
- '**/*.test.tsx'
|
|
17
|
+
- '**/*.spec.ts'
|
|
18
|
+
- '**/*.spec.tsx'
|
|
19
|
+
- '**/test/**'
|
|
20
|
+
- '**/tests/**'
|
|
21
|
+
- '**/__tests__/**'
|
|
22
|
+
- '**/__mocks__/**'
|
|
23
|
+
- '**/scripts/**'
|
|
24
|
+
- '**/fixtures/**'
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# SOURCE: https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates
|
|
2
|
+
# "Type predicates (param is Type) are the TypeScript way to narrow types.
|
|
3
|
+
# typeof checks are for primitives only. instanceof is for classes."
|
|
4
|
+
# SOURCE: https://www.totaltypescript.com/tips/use-type-predicates-to-narrow-types
|
|
5
|
+
# "unknown should be narrowed with type predicates before use."
|
|
6
|
+
# SOURCE: https://typescript-book.com/typeNarrowing
|
|
7
|
+
# "Don't access unknown without narrowing. Use type guards."
|
|
8
|
+
id: no-unknown-without-narrowing
|
|
9
|
+
language: typescript
|
|
10
|
+
message: "Parameter typed as 'unknown' used without type narrowing — use type guard (typeof, instanceof, in) or zod.parse() before accessing"
|
|
11
|
+
severity: warning
|
|
12
|
+
note: |
|
|
13
|
+
UNSAFE:
|
|
14
|
+
function handle(data: unknown) {
|
|
15
|
+
const str = data.toString(); // no narrowing — runtime error if data is null
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function process(value: unknown) {
|
|
19
|
+
console.log((value as any).name); // bypasses the point of unknown
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
SAFE:
|
|
23
|
+
function handle(data: unknown) {
|
|
24
|
+
if (typeof data === 'string') {
|
|
25
|
+
return data.toUpperCase(); // narrowed to string
|
|
26
|
+
}
|
|
27
|
+
if (typeof data === 'object' && data !== null && 'name' in data) {
|
|
28
|
+
return (data as { name: string }).name; // narrowed
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function process(value: unknown) {
|
|
33
|
+
const result = schema.safeParse(value); // zod validation
|
|
34
|
+
if (!result.success) throw new ValidationError('...');
|
|
35
|
+
return result.data;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
WHY: `unknown` forces you to narrow before use — that's its purpose. Accessing unknown
|
|
39
|
+
without narrowing defeats the entire point. Use typeof (primitives), instanceof (classes),
|
|
40
|
+
in operator (objects), or zod.parse() for complex shapes. `as any` on unknown is the
|
|
41
|
+
worst violation — it removes ALL type safety.
|
|
42
|
+
rule:
|
|
43
|
+
pattern: $PARAM.$METHOD($$$ARGS)
|
|
44
|
+
inside:
|
|
45
|
+
any:
|
|
46
|
+
- kind: function_declaration
|
|
47
|
+
- kind: arrow_function
|
|
48
|
+
- kind: function_expression
|
|
49
|
+
not:
|
|
50
|
+
any:
|
|
51
|
+
# Safe: inside a typeof narrowing if block
|
|
52
|
+
- inside:
|
|
53
|
+
pattern: |
|
|
54
|
+
if (typeof $PARAM === $$$TYPE) {
|
|
55
|
+
$$$PRE
|
|
56
|
+
$PARAM.$METHOD($$$ARGS)
|
|
57
|
+
$$$POST
|
|
58
|
+
}
|
|
59
|
+
stopBy: end
|
|
60
|
+
# Safe: inside an instanceof narrowing if block
|
|
61
|
+
- inside:
|
|
62
|
+
pattern: |
|
|
63
|
+
if ($PARAM instanceof $$$TYPE) {
|
|
64
|
+
$$$PRE
|
|
65
|
+
$PARAM.$METHOD($$$ARGS)
|
|
66
|
+
$$$POST
|
|
67
|
+
}
|
|
68
|
+
stopBy: end
|
|
69
|
+
ignores:
|
|
70
|
+
- '**/*.test.ts'
|
|
71
|
+
- '**/*.spec.ts'
|
|
72
|
+
- '**/test/**'
|
|
73
|
+
- '**/tests/**'
|
|
74
|
+
- '**/__tests__/**'
|
|
75
|
+
- '**/scripts/**'
|
|
76
|
+
- 'test-*.ts'
|