Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions checkers/discover/custom_analyzer_stub/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"globstar.dev/analysis"
)

var customCheckers []*analysis.Analyzer

var (
path = flag.String("path", ".", "Path to the directory to analyze")
test = flag.Bool("test", false, "Run the tests")
Expand Down
1 change: 1 addition & 0 deletions checkers/discover/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ package checkers
import (
"globstar.dev/checkers/javascript"
"globstar.dev/checkers/python"
"globstar.dev/checkers/typescript"
goAnalysis "globstar.dev/analysis"
)

Expand Down
4 changes: 4 additions & 0 deletions checkers/discover/generate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ package checkers
import (
"globstar.dev/checkers/javascript"
"globstar.dev/checkers/python"
"globstar.dev/checkers/typescript"
goAnalysis "globstar.dev/analysis"
)

Expand All @@ -86,6 +87,7 @@ package checkers
import (
"globstar.dev/checkers/javascript"
"globstar.dev/checkers/python"
"globstar.dev/checkers/typescript"
goAnalysis "globstar.dev/analysis"
)

Expand Down Expand Up @@ -116,6 +118,7 @@ package checkers
import (
"globstar.dev/checkers/javascript"
"globstar.dev/checkers/python"
"globstar.dev/checkers/typescript"
goAnalysis "globstar.dev/analysis"
)

Expand Down Expand Up @@ -151,6 +154,7 @@ package checkers
import (
"globstar.dev/checkers/javascript"
"globstar.dev/checkers/python"
"globstar.dev/checkers/typescript"
goAnalysis "globstar.dev/analysis"
)

Expand Down
Empty file added checkers/typescript/README.md
Empty file.
44 changes: 44 additions & 0 deletions checkers/typescript/no-any.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Test file for no-any checker
// This file should trigger the no-any checker

// <expect-error>
function processData(data: any) {
return data;
}

// <expect-error>
const handleInput = (input: any): void => {
console.log(input);
};

class DataProcessor {
// <expect-error>
process(item: any) {
return item;
}
}

interface Config {
// <expect-error>
value: any;
}

//Should NOT be flagged - using unknown
function processUnknown(data: unknown) {
return data;
}

//Should NOT be flagged - using specific type
function processUser(user: User) {
return user;
}

//Should NOT be flagged - using generic
function processGeneric<T>(data: T): T {
return data;
}

interface User {
name: string;
age: number;
}
30 changes: 30 additions & 0 deletions checkers/typescript/no-any.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
language: typescript
name: no-any
message: "Avoid using 'any' type. Use specific types or 'unknown' instead."
category: best-practices
severity: warning

pattern: |
(type_annotation
(predefined_type) @any_type
(#eq? @any_type "any")) @no-any

description: |
Issue:
Using the 'any' type defeats the purpose of TypeScript's type system. It disables type
checking and can lead to runtime errors that could have been caught at compile time.

Solution:
- Use specific types when the shape is known
- Use 'unknown' for values of truly unknown type (safer than 'any')
- Use generics when appropriate
- Use union types for multiple possible types

Example:
Bad:
function process(data: any) { ... }

Good:
function process(data: User | Product) { ... }
function process(data: unknown) { ... }
function process<T>(data: T) { ... }
43 changes: 43 additions & 0 deletions checkers/typescript/no-eval.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Test file for no-eval checker

function dangerousCode(input: string) {
// <expect-error>
eval(input);
}

// <expect-error>
const result = eval("2 + 2");

// <expect-error>
const calculate = (expr: string) => eval(expr);

function processConfig() {
const config = '{ "debug": true }';
// <expect-error>
return eval(`(${config})`);
}

//Should NOT be flagged - using JSON.parse
function safeJsonParse(json: string) {
return JSON.parse(json);
}

//Should NOT be flagged - using function map
const operations = {
add: (a: number, b: number) => a + b,
subtract: (a: number, b: number) => a - b,
};

function calculate_something(op: string, a: number, b: number) {
const operation = operations[op as keyof typeof operations];
return operation ? operation(a, b) : 0;
}

//Should NOT be flagged - configuration object
const config = {
development: { apiUrl: "http://localhost:3000" },
production: { apiUrl: "https://api.example.com" },
};

const environment: "development" | "production" = "development";
const settings = config[environment];
53 changes: 53 additions & 0 deletions checkers/typescript/no-eval.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
language: typescript
name: no-eval
message: "Avoid using 'eval()' as it poses security risks and performance issues."
category: security
severity: error

pattern: |
(call_expression
function: (identifier) @eval_func
(#eq? @eval_func "eval")) @no-eval

description: |
Issue:
Using 'eval()' is dangerous and should be avoided because:
- Security: Can execute arbitrary code, making it vulnerable to code injection attacks
- Performance: Prevents JavaScript engine optimizations
- Debugging: Makes code harder to debug and understand
- Maintainability: Creates unpredictable code behavior

eval() executes a string as JavaScript code, which means if user input is passed
to eval(), attackers can execute malicious code in your application.

Solution:
- Use JSON.parse() for parsing JSON strings
- Use Function constructor if you absolutely need dynamic code (still risky)
- Restructure your code to avoid dynamic code execution
- Use proper parsing libraries for specific data formats

Example:
Dangerous:
const userInput = getUserInput();
eval(userInput); // NEVER DO THIS!

const code = "alert('Hello')";
eval(code); // Avoid this

Safe alternatives:
// For JSON:
const data = JSON.parse(jsonString);

// For calculations:
const operators = {
'+': (a, b) => a + b,
'-': (a, b) => a - b,
};
const result = operators[operator](a, b);

// For configuration:
const config = {
development: { api: 'dev.api.com' },
production: { api: 'api.com' }
};
const settings = config[environment];
45 changes: 45 additions & 0 deletions checkers/typescript/no-explicit-any.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Test file for no-explicit-any checker

// <expect-error>
function parseJson(json: string): any {
return JSON.parse(json);
}

// <expect-error>
const processDataSafer = (data: any): void => {
console.log(data);
};

interface Config {
// <expect-error>
value: any;
// <expect-error>
settings: any;
}

class DataHandler {
// <expect-error>
handle(input: any) {
return input;
}
}

//Should NOT be flagged - using unknown
function parseJsonSafe(json: string): unknown {
return JSON.parse(json);
}

//Should NOT be flagged - using generics
function parseJsonGeneric<T>(json: string): T {
return JSON.parse(json);
}

//Should NOT be flagged - using specific type
interface User {
name: string;
email: string;
}

function saveUser(user: User): void {
console.log(user.name);
}
48 changes: 48 additions & 0 deletions checkers/typescript/no-explicit-any.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
language: typescript
name: no-explicit-any
message: "Avoid explicit 'any' type annotation. Consider using 'unknown' or a specific type."
category: best-practices
severity: warning

pattern: |
(type_annotation
(predefined_type) @explicit_any
(#eq? @explicit_any "any")) @no-explicit-any

description: |
Issue:
Explicitly annotating with 'any' type removes all type safety for that value.
This defeats the purpose of using TypeScript and can hide bugs.

The 'any' type should be avoided except in very specific cases where you're
gradually migrating JavaScript code to TypeScript or dealing with truly
dynamic data structures.

Solution:
- Use 'unknown' when the type is truly unknown (forces type checking before use)
- Use specific types or interfaces when the structure is known
- Use generics for reusable components
- Use union types for multiple possible types
- Use type guards to narrow 'unknown' types safely

Example:
Bad:
function parseJson(json: string): any {
return JSON.parse(json);
}

Good:
function parseJson<T>(json: string): T {
return JSON.parse(json);
}

// Or with unknown:
function parseJson(json: string): unknown {
return JSON.parse(json);
}

const data = parseJson(jsonString);
if (isUser(data)) {
// TypeScript knows data is User here
console.log(data.name);
}
40 changes: 40 additions & 0 deletions checkers/typescript/no-non-null-assertion.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Test file for no-non-null-assertion checker

interface User {
name: string;
email?: string;
}

function getUserEmail(user: User | null) {
// <expect-error>
return user!.email;
}

// <expect-error>
const element = document.getElementById("myId")!;

// <expect-error>
const value = possiblyUndefined!.property;

function process(data: string | undefined) {
// <expect-error>
const length = data!.length;
return length;
}

//Should NOT be flagged - using optional chaining
function getUserEmailSafe(user: User | null) {
return user?.email;
}

//Should NOT be flagged - using null check
const elementSafe = document.getElementById("myId");
if (elementSafe) {
elementSafe.classList.add("active");
}

//Should NOT be flagged - using nullish coalescing
function processSafe(data: string | undefined) {
const length = data?.length ?? 0;
return length;
}
37 changes: 37 additions & 0 deletions checkers/typescript/no-non-null-assertion.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
language: typescript
name: no-non-null-assertion
message: "Avoid using non-null assertion operator (!). This can lead to runtime errors."
category: best-practices
severity: warning

pattern: |
(non_null_expression) @no-non-null-assertion

exclude:
- "test/**"
- "*_test.ts"
- "*.test.ts"
- "tests/**"
- "__tests__/**"

description: |
Issue:
The non-null assertion operator (!) tells TypeScript to ignore potential null or undefined
values. This defeats the purpose of strict null checking and can lead to runtime errors.

Solution:
- Use optional chaining (?.) to safely access properties
- Use nullish coalescing (??) to provide default values
- Use explicit null checks (if statements)
- Use type guards to narrow types

Example:
Bad:
const value = possiblyNull!.property;
const element = document.getElementById('id')!;

Good:
const value = possiblyNull?.property;
const element = document.getElementById('id');
if (element) { /* use element */ }
const value = possiblyNull?.property ?? defaultValue;
Loading