Skip to content
Open
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
26 changes: 21 additions & 5 deletions vscode-extension/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,28 @@
"plugins": [
"@typescript-eslint"
],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"rules": {
"@typescript-eslint/semi": "warn",
"curly": "warn",
"eqeqeq": "warn",
"no-throw-literal": "warn",
"semi": "off"
"@typescript-eslint/semi": "error",
"curly": "error",
"eqeqeq": "error",
"no-throw-literal": "error",
"semi": "off",
"no-console": "error",
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/no-inferrable-types": "error",
"@typescript-eslint/no-non-null-assertion": "error",
"@typescript-eslint/no-empty-function": "error",
"@typescript-eslint/ban-ts-comment": "error",
"@typescript-eslint/no-var-requires": "error",
"no-case-declarations": "error",
"prefer-const": "error",
"no-empty": "error",
"no-async-promise-executor": "error"
},
"ignorePatterns": [
"out",
Expand Down
2 changes: 1 addition & 1 deletion vscode-extension/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Visualize your codebase dependencies and architecture in navigable 3D worlds dir
## Current Version

- **Latest Release**: [See GitHub Releases](https://github.com/bitkojine/openas3d/releases) (or check the badge above)
- **Development Version**: 0.2.3+2026-01-27d
- **Development Version**: 0.3.1+2026-01-31d


## Usage
Expand Down
56 changes: 56 additions & 0 deletions vscode-extension/lint-hardening-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# ESLint Hardening Specification (v2)

This document outlines the phased plan to transition the `openas3d-vscode` extension from "warning-tolerant" to "strict-error" linting.

## Current Baseline (on `main`)
The following issues were identified after re-enabling recommended rules:
- **Major Issues**: `no-explicit-any` (316), `no-unused-vars` (71)
- **Moderate Issues**: `no-inferrable-types` (40), `no-non-null-assertion` (32), `no-empty-function` (22)
- **Minor Issues**: `ban-ts-comment` (6), `no-var-requires` (6), `no-case-declarations` (5), `prefer-const` (2), `no-empty` (1), `no-async-promise-executor` (1), `no-throw-literal` (1)

## Phase 1: Global Rule Hardening & Critical Fixes
Turning high-impact but low-volume rules into errors immediately.

- **Commit 1: Set All Targeted Rules to "Error" & Unmask Suppressions**
- Update `.eslintrc.json` to set all current warnings to `"error"`.
- Remove all current `eslint-disable`, `@ts-ignore`, and `@ts-expect-error` comments (11 found).
- Goal: Establish a truly honest baseline of all violations.
- **Commit 2: Fix Simple Core Errors (Minor Set)**
- Address: `no-case-declarations`, `no-empty`, `no-async-promise-executor`, `prefer-const`.
- Scope: ~10 instances.
- **Commit 3: Modernize Imports (`no-var-requires`)**
- Resolution: Convert `require` to ES `import`.
- Scope: 6 instances.

## Phase 2: Structural & Stylistic Cleanup
Addressing the moderate volume rules.

- **Commit 4: Satisfy `no-empty-function`**
- Resolution: Add `// Intentionally empty` comments to constructors and callbacks.
- Scope: 22 instances.
- **Commit 5: Resolve `no-non-null-assertion`**
- Resolution: Replace `!` with proper guard clauses or safe navigation.
- Scope: 34 instances.
- **Commit 6: Clean up `no-inferrable-types`**
- Resolution: Remove redundant type annotations like `: string = ''`.
- Scope: 40 instances.
- **Commit 7: Resolve `no-unused-vars`**
- Resolution: Remove unused imports/variables or prefix with `_`.
- Scope: 77 instances.

## Phase 3: The `any` Cleanup (`no-explicit-any`)
Addressing the largest challenge (322 instances) incrementally by module.

- **Commit 8: Fix `any` in `src/utils` and `src/shared`**
- **Commit 9: Fix `any` in `src/core` (Domain & Analysis)**
- **Commit 10: Fix `any` in `src/services` (Extension Core)**
- **Commit 11: Fix `any` in `src/webview` (Part 1: Logic/State)**
- **Commit 12: Fix `any` in `src/webview` (Part 2: Rendering/UI)**
- **Commit 13: Fix `any` in Tests & Mocks**

## Verification Strategy

Each commit must meet these criteria:
1. `npm run lint` shows **zero errors** for the specific rule(s) addressed.
2. `npm run compile` passes.
3. `npm run test` passes (all unit tests).
3 changes: 2 additions & 1 deletion vscode-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "openas3d-vscode",
"displayName": "OpenAs3D - 3D Codebase Explorer",
"description": "Visualize codebase dependencies and architecture in navigable 3D worlds",
"version": "0.2.3",
"version": "0.3.1+2026-01-31d",
"publisher": "openas3d",
"repository": {
"type": "git",
Expand Down Expand Up @@ -66,6 +66,7 @@
}
},
"scripts": {
"lint": "eslint src --ext .ts,.js",
"prebuild": "npm run version:sync && npm run version:local && npm run update-readme",
"build": "npm run compile && npm run package",
"build:prod": "npm run compile && npm run package",
Expand Down
60 changes: 35 additions & 25 deletions vscode-extension/src/__mocks__/three.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,19 @@ export class Vector3 {

export class Object3D {
public position: Vector3 = new Vector3();
public rotation: any = { x: 0, y: 0, z: 0 };
public quaternion: any = {
setFromUnitVectors: () => { },
copy: () => { },
set: () => { }
};
public rotation: { x: number; y: number; z: number } = { x: 0, y: 0, z: 0 };
public quaternion: {
setFromUnitVectors: (v1: Vector3, v2: Vector3) => void;
copy: (q: unknown) => void;
set: (x: number, y: number, z: number, w: number) => void;
} = {
setFromUnitVectors: () => { },
copy: () => { },
set: () => { }
};
public scale: Vector3 = new Vector3(1, 1, 1);
public children: Object3D[] = [];
public userData: any = {};
public userData: Record<string, unknown> = {};
public name: string = '';
public visible: boolean = true;

Expand All @@ -104,7 +108,7 @@ export class Object3D {

lookAt(v: Vector3) { }

traverse(callback: (object: Object3D) => any) {
traverse(callback: (object: Object3D) => void) {
callback(this);
for (const child of this.children) {
child.traverse(callback);
Expand All @@ -113,7 +117,7 @@ export class Object3D {
}

export class Mesh extends Object3D {
constructor(public geometry?: any, public material?: any) {
constructor(public geometry?: BufferGeometry, public material?: Material | Material[]) {
super();
}
}
Expand All @@ -123,19 +127,25 @@ export class Group extends Object3D { }
export class Scene extends Object3D { }

export class BufferGeometry {
public boundingBox: any = { max: { y: 1 }, min: { y: 0 } };
public attributes: any = {};
setFromPoints() { return this; }
public boundingBox: { max: { x: number; y: number; z: number }; min: { x: number; y: number; z: number } } | null = {
max: { x: 1, y: 1, z: 1 },
min: { x: 0, y: 0, z: 0 }
};
public attributes: Record<string, unknown> = {};
setFromPoints(points: Vector3[]) { return this; }
computeBoundingBox() { return this.boundingBox; }
setAttribute(name: string, attribute: any) { this.attributes[name] = attribute; }
setAttribute(name: string, attribute: unknown) { this.attributes[name] = attribute; }
dispose() { }
}

export class Box3 {
public min = new Vector3();
public max = new Vector3();
constructor() { }
setFromObject(obj: any) { return this; }
constructor(min?: Vector3, max?: Vector3) {
if (min) this.min.copy(min);
if (max) this.max.copy(max);
}
setFromObject(obj: Object3D) { return this; }
getSize(target: Vector3) {
target.set(1, 1, 1);
return target;
Expand All @@ -162,8 +172,8 @@ export class Material {

export class MeshLambertMaterial extends Material {
public emissive = { setHex: () => { } };
public map: any = undefined;
constructor(parameters?: any) {
public map: Texture | undefined = undefined;
constructor(parameters?: { map?: Texture; color?: number | string; emissive?: number | string }) {
super();
if (parameters && parameters.map) {
this.map = parameters.map;
Expand Down Expand Up @@ -199,7 +209,7 @@ export class Texture {
}

export class CanvasTexture extends Texture {
constructor(canvas: any) { super(); }
constructor(canvas: unknown) { super(); }
clone() {
// Return a Texture instance that mimics CanvasTexture for testing
const t = new CanvasTexture(null);
Expand All @@ -210,25 +220,25 @@ export class CanvasTexture extends Texture {
}

export class Sprite extends Object3D {
constructor(material?: any) {
constructor(material?: Material) {
super();
}
}

export class LinearMipmapLinearFilter { }
export class LinearFilter { }
export class QuadraticBezierCurve3 {
constructor(v0: any, v1: any, v2: any) { }
constructor(v0: Vector3, v1: Vector3, v2: Vector3) { }
getPoints() { return []; }
getTangent() { return new Vector3(); }
}
export class CubicBezierCurve3 {
constructor(v0: any, v1: any, v2: any, v3: any) { }
constructor(v0: Vector3, v1: Vector3, v2: Vector3, v3: Vector3) { }
getPoints() { return []; }
getTangent() { return new Vector3(); }
}
export class Line extends Object3D {
constructor(geo?: any, mat?: any) { super(); }
constructor(geo?: BufferGeometry, mat?: Material) { super(); }
computeLineDistances() { }
}

Expand All @@ -242,21 +252,21 @@ export class Color {
public r: number = 0;
public g: number = 0;
public b: number = 0;
constructor(r?: any, g?: any, b?: any) { }
constructor(r?: number | string, g?: number, b?: number) { }
set() { }
clone() { return new Color(this.r, this.g, this.b); }
offsetHSL() { return this; }
}

export class Float32BufferAttribute {
public count: number;
constructor(array: any, itemSize: any) {
constructor(array: number[] | Float32Array, itemSize: number) {
this.count = array.length / itemSize;
}
}

export class TubeGeometry extends BufferGeometry {
constructor(path: any, tubularSegments: any, radius: any, radialSegments: any, closed: any) {
constructor(path: unknown, tubularSegments: number, radius: number, radialSegments: number, closed: boolean) {
super();
// Mock default position attribute for count check
this.attributes.position = { count: (tubularSegments + 1) * (radialSegments + 1) };
Expand Down
Loading