diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..da20ca6 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,69 @@ +# GitHub Copilot Instructions for vscode-ddev-phpstan + +You are an expert Visual Studio Code Extension developer specializing in TypeScript and PHP tooling integration. You are working on the `vscode-ddev-phpstan` repository. + +## Project Overview +This project is a VS Code extension that integrates PHPStan (Static Analysis) running inside DDEV containers into the VS Code editor. It allows users to run PHPStan analysis on their PHP files without installing PHPStan locally on their host machine. + +## Tech Stack & Environment +- **Language**: TypeScript (Target ES2022, Strict Mode). +- **Runtime**: Node.js (via VS Code Extension Host). +- **Bundler**: esbuild. +- **Testing**: mocha, @vscode/test-electron. +- **Core Dependency**: `ddev` CLI tool (must be installed on user's machine). + +## Architecture & patterns + +### Service-Based Architecture +- Logic logic is encapsulated in "Services" located in `src/services/`. +- `PhpstanService` extends `BasePhpToolService`. If adding new PHP tools, follow this pattern. +- `extension.ts` acts as the composition root, managing service lifecycles and command registrations. + +### DDEV Integration +- **Crucial**: All PHP commands are executed inside the DDEV container, not on the host. +- Use `DdevUtils.execDdev` or similar helpers to run commands. +- **Path Mapping**: Be extremely careful with file paths. + - Host path: `/Users/user/project/src/File.php` + - Container path: `/var/www/html/src/File.php` + - The extension must translate paths correctly when parsing output from PHPStan (which reports container paths) to VS Code diagnostics (which expect host paths). + +### Error Handling +- User-facing errors: `vscode.window.showErrorMessage` or `showWarningMessage`. +- Internal logs: `console.log` or `console.error`. +- DDEV issues: Use `showDdevError` helper when DDEV is stopped or unconfigured. + +### Configuration +- Settings are defined in `package.json` under `contributes.configuration`. +- Access settings via `ConfigurationService`. +- React to configuration changes using `vscode.workspace.onDidChangeConfiguration`. + +## Coding Guidelines + +1. **TypeScript**: + - Use strict type annotations. Avoid `any` whenever possible. + - Use `async/await` for asynchronous operations. + - interfaces/types should be in `src/models/` if shared. + +2. **VS Code API**: + - Use `vscode` namespace imports (`import * as vscode from 'vscode';`). + - managing disposables: Push event listeners and commands to `context.subscriptions`. + +3. **Testing**: + - Write unit tests for services in `src/test/`. + - Mock `vscode` API where complex interactions occur, or use integration tests. + +4. **UI/UX**: + - Use Status Bar items effectively to show tool status (Ready, Error, etc.). + - Provide "Quick Fixes" or buttons in error messages for common actions (like "Start DDEV"). + +## Common Tasks + +- **Adding a new setting**: + 1. Add to `package.json`. + 2. Update `ConfigurationService` to read it. + 3. Update `PhpstanService` to use it. + +- **Parsing PHPStan Output**: + - PHPStan is run with `--error-format=json`. + - The output is parsed in `processToolOutput`. + - Ensure the JSON parsing is robust against non-JSON noise (like PHP warnings printed before JSON). diff --git a/README.md b/README.md index 739c8a5..ccfd657 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ This extension integrates [PHPStan](https://phpstan.org/) with Visual Studio Cod ## Requirements -- [VS Code](https://code.visualstudio.com/) 1.100.0 or higher +- [VS Code](https://code.visualstudio.com/) 1.108.0 or higher - [DDEV](https://github.com/ddev/ddev) project with running container - PHPStan installed in your DDEV container @@ -51,10 +51,10 @@ Key settings in VS Code preferences: - `ddev-phpstan.validateOn`: When to validate (`"save"` or `"type"`) - `ddev-phpstan.level`: PHPStan analysis level 0-9 (default: `6` - recommended for most projects) - `ddev-phpstan.minSeverity`: Minimum severity level (`"error"`, `"warning"`, `"info"`) -- `ddev-phpstan.configPath`: Path to custom PHPStan configuration file +- `ddev-phpstan.configPath`: Path to custom PHPStan configuration file. If left empty, the extension automatically looks for common configuration files like `phpstan.neon`, `phpstan.neon.dist`, `phpstan.dist.neon` in the workspace root. - `ddev-phpstan.excludePaths`: Array of paths to exclude from analysis (includes common exclusions by default) -**Important:** When `configPath` is specified, the extension will only use the configuration file and ignore the `level` and `excludePaths` settings, as these should be defined in the PHPStan configuration file itself. +**Important:** When `configPath` is specified or an auto-detected configuration file is found, the extension will use that configuration file. In this case, the `level` and `excludePaths` settings from VS Code are ignored, as these should be defined in the PHPStan configuration file itself. ### Example Configuration @@ -82,7 +82,7 @@ Key settings in VS Code preferences: - **Common Exclusions**: Automatically excludes vendor code, cache directories, and other common paths that shouldn't be analyzed - **Save-based Validation**: Runs analysis when files are saved for optimal performance -**Note:** When `configPath` is set to a specific PHPStan configuration file, the `level` and `excludePaths` settings will be ignored, and these values should instead be configured in your PHPStan configuration file. +**Note:** When `configPath` is set to a specific PHPStan configuration file (or one is auto-detected), the `level` and `excludePaths` settings will be ignored, and these values should instead be configured in your PHPStan configuration file. ## Status Bar diff --git a/src/test/ddev-utils.test.ts b/src/test/ddev-utils.test.ts index 9613150..6eb7a65 100644 --- a/src/test/ddev-utils.test.ts +++ b/src/test/ddev-utils.test.ts @@ -19,9 +19,17 @@ import * as assert from 'assert'; import * as sinon from 'sinon'; -import { afterEach, beforeEach } from 'mocha'; +import { afterEach, beforeEach, test } from 'mocha'; import { DdevUtils, sys } from '../shared/utils/ddev-utils'; +interface ExecDdevError extends Error { + status: number; + stderr: string; + stdout?: string; + command?: string; + workspacePath?: string; +} + suite('DdevUtils Test Suite', () => { let sandbox: sinon.SinonSandbox; let spawnSyncStub: sinon.SinonStub; @@ -106,7 +114,7 @@ suite('DdevUtils Test Suite', () => { const result = DdevUtils.validateDdevTool('phpstan', '/test/workspace'); assert.strictEqual(result.isValid, true); - assert.ok(result.errorType === undefined); + assert.strictEqual(result.errorType, undefined); }); test('validateDdevTool returns error message for DDEV issues', () => { @@ -159,7 +167,7 @@ suite('DdevUtils Test Suite', () => { assert.throws(() => { DdevUtils.execDdev(['ls'], '/test/workspace'); - }, (err: { status: number; stderr: string; stdout?: string; command?: string; workspacePath?: string; name?: string }) => { + }, (err: ExecDdevError) => { return err.status === 1 && err.stderr === 'error'; }); });