|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +@nette/eslint-plugin is an ESLint configuration package with custom rules for Nette-specific JavaScript linting. The project is structured as an ESLint plugin and config, using the new flat configuration format. It supports both JavaScript and TypeScript, and includes a processor for Latte template files. |
| 8 | + |
| 9 | +## Common Commands |
| 10 | + |
| 11 | +```bash |
| 12 | +# Run all tests |
| 13 | +npm run test |
| 14 | + |
| 15 | +# Run linter |
| 16 | +npm run lint |
| 17 | + |
| 18 | +# Run linter with autofix |
| 19 | +npm run lint:fix |
| 20 | + |
| 21 | +# Run a specific test file |
| 22 | +npx mocha tests/prefer-line-comments.test.js |
| 23 | +``` |
| 24 | + |
| 25 | +## Code Architecture |
| 26 | + |
| 27 | +The codebase is structured as follows: |
| 28 | + |
| 29 | +1. **ESLint Plugin** (`src/plugins.js`): Exports the plugin configuration, including metadata and custom rules. |
| 30 | + |
| 31 | +2. **Custom Rules** (`src/rules/`): Individual rule implementations, each exported with `meta` and `create` functions: |
| 32 | + - `no-this-in-arrow-except-nested.js`: Prevents using `this` inside arrow functions with configurable exceptions |
| 33 | + - `prefer-line-comments.js`: Enforces line comments (`//`) over block comments (`/* */`) for single-line comments |
| 34 | + |
| 35 | +3. **Configs** (`src/configs/`): Configuration options for various environments: |
| 36 | + - `base.js`: Base ESLint configuration settings |
| 37 | + - `nette.js`: Nette-specific rules and configuration |
| 38 | + - `recommended.js`: Exports the combined recommended configuration for JavaScript |
| 39 | + - `typescript.js`: TypeScript-specific configuration extending the base and recommended settings |
| 40 | + |
| 41 | +4. **Latte Processor** (`src/latte-processor.js`): Processes Latte template files to extract and lint JavaScript code: |
| 42 | + - Handles different file types (.js.latte, .css.latte, .txt.latte, .latte) |
| 43 | + - Recognizes Latte syntax: `{$variable}`, `{=expression}`, `{_translation}`, `{control}` |
| 44 | + - Supports `n:syntax="off"` attribute to disable Latte processing in HTML elements |
| 45 | + - Maps ESLint errors back to original file locations |
| 46 | + - Configurable replacement values for different Latte constructs |
| 47 | + - Supports partial configuration with object spread merging |
| 48 | + |
| 49 | +5. **Entry Point** (`src/index.js`): Main entry point that exports the plugin and configurations: |
| 50 | + - Exports the plugin from `plugins.js` |
| 51 | + - Includes the Latte processor under `processors.latte` |
| 52 | + - Makes configurations available under `configs` namespace |
| 53 | + - Supports both JavaScript (recommended) and TypeScript configurations |
| 54 | + - Provides dedicated `latte` configuration for Latte template files |
| 55 | + - Includes `configureLatte()` factory function for custom Latte configurations |
| 56 | + - Configures processor with default settings on initialization |
| 57 | + |
| 58 | +6. **Tests** (`tests/`): Each rule has a corresponding test file using ESLint's `RuleTester`, plus integration tests: |
| 59 | + - Rule-specific tests: `no-this-except.test.js` and `prefer-line-comments.test.js` |
| 60 | + - Integration tests: `integration.test.js` for general plugin testing |
| 61 | + - Configuration tests: `javascript-config.test.js` and `typescript-config.test.js` for testing configs |
| 62 | + - Latte processor tests: `latte-processor.test.js` and `latte-integration.test.js` |
| 63 | + - Latte configuration tests: `latte-configuration.test.js` and `latte-config-integration.test.js` |
| 64 | + - Fixture files: `tests/fixtures/` contains sample Latte files for testing |
| 65 | + |
| 66 | +## Rule Details |
| 67 | + |
| 68 | +### no-this-in-arrow-except |
| 69 | + |
| 70 | +Prevents using `this` in arrow functions with exceptions for specific cases. It has two modes: |
| 71 | + |
| 72 | +1. **Default mode** (`allowNestedInFunction: false`): |
| 73 | + - Allows `this` in arrow functions only when they are callbacks in class methods or directly passed to function calls |
| 74 | + |
| 75 | +2. **Opt-in mode** (`allowNestedInFunction: true`): |
| 76 | + - Also allows `this` in arrow functions when nested within any regular function |
| 77 | + |
| 78 | +### prefer-line-comments |
| 79 | + |
| 80 | +Enforces the use of line comments (`//`) instead of block comments (`/* */`) for single-line comments. |
| 81 | +Exceptions are made for: |
| 82 | +- Multi-line block comments |
| 83 | +- JSDoc comments (block comments starting with `*`) |
| 84 | + |
| 85 | +## Latte Template Support |
| 86 | + |
| 87 | +The plugin includes a processor for Latte template files that allows ESLint to lint JavaScript code within Latte templates: |
| 88 | + |
| 89 | +### Supported File Types |
| 90 | +- `**/*.js.latte` - JavaScript files with Latte syntax |
| 91 | +- `**/*.css.latte` - CSS files with Latte syntax |
| 92 | +- `**/*.txt.latte` - Text files with Latte syntax |
| 93 | +- `**/*.latte` - HTML files with Latte syntax |
| 94 | + |
| 95 | +### Latte Syntax Recognition |
| 96 | +The processor recognizes and handles these Latte constructs: |
| 97 | +- `{$variable}` - Variables, replaced with `0` placeholder |
| 98 | +- `{=expression}` - Expressions, replaced with `0` placeholder |
| 99 | +- `{_"text"}` - Translations, replaced with `""` placeholder |
| 100 | +- `{if}`, `{/if}`, `{foreach}`, etc. - Control structures, removed completely |
| 101 | +- `n:syntax="off"` - Disables Latte processing within HTML elements |
| 102 | + |
| 103 | +### Usage |
| 104 | + |
| 105 | +**Basic usage with defaults:** |
| 106 | +```javascript |
| 107 | +import nette from '@nette/eslint-plugin'; |
| 108 | + |
| 109 | +export default [ |
| 110 | + ...nette.configs.latte |
| 111 | +]; |
| 112 | +``` |
| 113 | + |
| 114 | +**Custom configuration:** |
| 115 | +```javascript |
| 116 | +import nette from '@nette/eslint-plugin'; |
| 117 | + |
| 118 | +export default [ |
| 119 | + ...nette.configs.configureLatte({ |
| 120 | + latteReplacement: { |
| 121 | + expression: 'undefined', // Replace {$var} with 'undefined' |
| 122 | + translation: "'__missing__'", // Replace {_text} with '__missing__' |
| 123 | + control: '/* removed */' // Replace {if} with '/* removed */' |
| 124 | + }, |
| 125 | + removeLatteErrors: true, // Filter out ESLint errors from Latte code |
| 126 | + keepEOL: false // Remove newlines after Latte tags (default) |
| 127 | + }) |
| 128 | +]; |
| 129 | +``` |
| 130 | + |
| 131 | +**Partial configuration (only specify what you want to change):** |
| 132 | +```javascript |
| 133 | +export default [ |
| 134 | + ...nette.configs.configureLatte({ |
| 135 | + latteReplacement: { |
| 136 | + expression: 'null' // Only change expression replacement |
| 137 | + // translation and control use defaults: '""' and '' |
| 138 | + }, |
| 139 | + keepEOL: true |
| 140 | + }) |
| 141 | +]; |
| 142 | +``` |
| 143 | + |
| 144 | +**Available configuration functions:** |
| 145 | +- `nette.configs.latte` - Default Latte configuration |
| 146 | +- `nette.configs.configureLatte(options)` - Custom Latte configuration factory |
| 147 | + |
| 148 | +### Configuration Options |
| 149 | + |
| 150 | +- **latteReplacement** (`object`) - Replacement values for different Latte constructs. You can specify only the options you want to change: |
| 151 | + - **expression** (`string`, default: `'0'`) - Replacement for variable and expression tags `{$var}`, `{=expr}` |
| 152 | + - **translation** (`string`, default: `'""'`) - Replacement for translation tags `{_text}` |
| 153 | + - **control** (`string`, default: `''`) - Replacement for control structures `{if}`, `{/if}`, etc. |
| 154 | +- **removeLatteErrors** (`boolean`, default: `false`) - Whether to filter out ESLint errors that occur in original Latte code positions |
| 155 | +- **keepEOL** (`boolean`, default: `false`) - Whether to preserve newlines after Latte tags (useful for debugging) |
| 156 | + |
| 157 | +### Dependencies |
| 158 | + |
| 159 | +For basic Latte support (`.js.latte`, `.css.latte`, `.txt.latte`): |
| 160 | +- No additional dependencies required |
| 161 | + |
| 162 | +For HTML Latte support (`.latte` files with `<script>` tags): |
| 163 | +- Requires `eslint-plugin-html` to be installed |
| 164 | + |
| 165 | +### Implementation Details |
| 166 | + |
| 167 | +1. **Processor Architecture**: Uses ESLint's processor API to transform Latte files before linting |
| 168 | +2. **Configuration System**: Supports both global configuration via `latteProcessor.configure()` and per-config options |
| 169 | +3. **Partial Configuration**: Uses object spread to merge user settings with defaults, allowing partial overrides |
| 170 | +4. **Error Mapping**: Maps ESLint errors back to original file positions accounting for Latte tag transformations |
| 171 | +5. **Whitespace Handling**: When control structures or empty replacement tags are on lines containing only whitespace, the processor removes the leading whitespace from those lines while preserving the line structure |
| 172 | +6. **Test Coverage**: 65+ tests covering all functionality including edge cases and configuration scenarios |
| 173 | + |
| 174 | +### Limitations |
| 175 | +- Currently focuses on `.js.latte` files for full JavaScript linting experience |
| 176 | +- HTML parsing for `.latte` files requires `eslint-plugin-html` for complete functionality |
| 177 | +- Error mapping preserves original line/column positions from Latte templates |
| 178 | +- Global processor configuration means all instances of the processor share the same settings |
| 179 | +- Regex-based parsing may not handle extremely complex nested Latte constructs |
| 180 | + |
| 181 | +## TypeScript Support |
| 182 | + |
| 183 | +The plugin provides TypeScript support through dedicated configuration: |
| 184 | + |
| 185 | +1. **TypeScript Config**: Available as `nette.configs.typescript` in the API |
| 186 | +2. **Integration**: Integrates with `typescript-eslint` to provide TypeScript-aware linting |
| 187 | +3. **Rule Compatibility**: All Nette rules work in TypeScript files |
| 188 | +4. **Optional Dependency**: TypeScript support is optional and the package will work without TypeScript installed. Import from '@nette/eslint-plugin/typescript' to use TypeScript support directly. |
| 189 | +5. **Direct Import**: TypeScript configuration is available through a dedicated entry point via `import nette from '@nette/eslint-plugin/typescript'`. The customize function with `typescript: true` is no longer supported. |
| 190 | + |
| 191 | +## Testing Notes |
| 192 | + |
| 193 | +1. **TypeScript Rule Conflicts**: When running tests, TypeScript rules might interfere with test assertions. To avoid this: |
| 194 | + - In test files, explicitly disable TypeScript rules like `@typescript-eslint/no-unused-vars` and `@typescript-eslint/no-unused-expressions` |
| 195 | + - Use `console.log()` for variables to prevent unused variable warnings |
| 196 | + - Consider adding assertions that account for both JavaScript and TypeScript rule violations |
| 197 | + |
| 198 | +2. **Integration Tests**: The integration test expects specific error counts: |
| 199 | + - For `no-this-in-arrow-except`: Counts each `this` reference in an arrow function |
| 200 | + - For `prefer-line-comments`: Looks for single-line block comments |
| 201 | + |
| 202 | +3. **Latte Processor Tests**: Special considerations for Latte processor testing: |
| 203 | + - Use `beforeEach()` to reset processor configuration between tests to avoid test interference |
| 204 | + - Test configuration changes by calling `latteProcessor.configure()` with test-specific settings |
| 205 | + - Verify both `preprocess()` output (transformed code) and `postprocess()` behavior (error mapping) |
| 206 | + - Test edge cases like empty files, syntax-off regions, and partial configurations |
| 207 | + - Integration tests should verify the processor works with actual ESLint configurations |
| 208 | + |
| 209 | +## Implementation Notes |
| 210 | + |
| 211 | +1. The rule name in `plugins.js` is `no-this-in-arrow-except` but the file name is `no-this-in-arrow-except-nested.js`. |
| 212 | + |
| 213 | +2. The project uses ESLint v9 and the new flat config format, requiring Node.js v16.0.0 or higher. |
| 214 | + |
| 215 | +3. When testing with TypeScript configurations, make sure to have `typescript` and `typescript-eslint` installed. |
| 216 | + |
| 217 | +4. **Optional TypeScript Support**: The package is designed to work without TypeScript installed: |
| 218 | + - `index.js` uses top-level await to dynamically import TypeScript configuration |
| 219 | + - When TypeScript dependencies are missing, accessing `nette.configs.typescript` will throw a helpful error |
| 220 | + - For environments without top-level await support, an alternative implementation is provided in `index-no-await.js` |
| 221 | + |
| 222 | +5. **Latte Processor Implementation**: |
| 223 | + - Uses regex `/\{(?:[a-zA-Z_$\\/][^}]*)\}(\r?\n)?/g` to detect Latte tags |
| 224 | + - Employs global configuration via `_globalSettings` variable for processor state |
| 225 | + - Configuration merging uses object spread: `{...defaults, ...userSettings}` |
| 226 | + - Error mapping preserves original file positions through coordinate transformation |
| 227 | + - Supports different file types through filename-based detection |
0 commit comments