@diplodoc/lint 1.3.2 → 1.4.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/.editorconfig ADDED
@@ -0,0 +1,20 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ insert_final_newline = true
7
+ trim_trailing_whitespace = true
8
+ indent_style = space
9
+ indent_size = 4
10
+
11
+ [{*.json,*.yml,*.yaml}]
12
+ indent_style = space
13
+ indent_size = 2
14
+
15
+ [*.md]
16
+ trim_trailing_whitespace = false
17
+
18
+ [GNUmakefile]
19
+ indent_style = tab
20
+ indent_size = 4
package/.eslintignore ADDED
@@ -0,0 +1,21 @@
1
+ .idea
2
+ .vscode
3
+ .history
4
+ .env
5
+ .DS_Store
6
+ node_modules
7
+ /lib
8
+ /dist
9
+ /build
10
+ /cache
11
+ /coverage
12
+ /external
13
+ # Test files - they use Node.js globals
14
+ test/
15
+ # Scripts use Node.js globals
16
+ scripts/
17
+
18
+ .lintstagedrc.js
19
+ .eslintrc.js
20
+ .prettierrc.js
21
+ .stylelintrc.js
package/.eslintrc.js ADDED
@@ -0,0 +1,8 @@
1
+ module.exports = {
2
+ root: true,
3
+ extends: require.resolve('@diplodoc/lint/eslint-config'),
4
+ parserOptions: {
5
+ tsconfigRootDir: __dirname,
6
+ project: true,
7
+ },
8
+ };
@@ -0,0 +1 @@
1
+ npm run pre-commit
@@ -0,0 +1,39 @@
1
+ /* eslint-env node */
2
+ module.exports = {
3
+ // Exclude config files and scripts from linting (they use CommonJS)
4
+ '**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx}': (filenames) => {
5
+ // Filter out config files and scripts
6
+ const configFiles = [
7
+ '.lintstagedrc.js',
8
+ '.eslintrc.js',
9
+ '.prettierrc.js',
10
+ '.stylelintrc.js',
11
+ ];
12
+ const filtered = filenames.filter(
13
+ (f) =>
14
+ !configFiles.some((config) => f.includes(config)) &&
15
+ !f.includes('scripts/') &&
16
+ !f.includes('test/'),
17
+ );
18
+ if (filtered.length === 0) {
19
+ return [];
20
+ }
21
+ return ['prettier --write', 'eslint --max-warnings=0 --fix --no-warn-ignored'];
22
+ },
23
+ '**/*.{css,scss}': ['prettier --write', 'stylelint --fix'],
24
+ '**/*.{json,yaml,yml,md}': ['prettier --write'],
25
+ '**/*.{svg,svgx}': ['svgo'],
26
+ // Run unit tests when test files or source files change
27
+ '**/*.{ts,tsx}': (filenames) => {
28
+ const testFiles = filenames.filter((f) => f.includes('.test.') || f.includes('.spec.'));
29
+ const sourceFiles = filenames.filter(
30
+ (f) => !f.includes('.test.') && !f.includes('.spec.') && f.includes('src/'),
31
+ );
32
+ const commands = [];
33
+ // Run tests if test files or source files changed
34
+ if (testFiles.length > 0 || sourceFiles.length > 0) {
35
+ commands.push('npm test');
36
+ }
37
+ return commands;
38
+ },
39
+ };
@@ -0,0 +1,14 @@
1
+ .idea
2
+ .vscode
3
+ .history
4
+ .env
5
+ .DS_Store
6
+ node_modules
7
+ /lib
8
+ /dist
9
+ /build
10
+ /cache
11
+ /coverage
12
+ /external
13
+ # Test fixtures with invalid JSON
14
+ test/fixtures/package-invalid.json
package/.prettierrc.js ADDED
@@ -0,0 +1 @@
1
+ module.exports = require('@diplodoc/lint/prettier-config');
@@ -0,0 +1,12 @@
1
+ .idea
2
+ .vscode
3
+ .history
4
+ .env
5
+ .DS_Store
6
+ node_modules
7
+ /lib
8
+ /dist
9
+ /build
10
+ /cache
11
+ /coverage
12
+ /external
@@ -0,0 +1,3 @@
1
+ module.exports = {
2
+ extends: require.resolve('@diplodoc/lint/stylelint-config'),
3
+ };
package/AGENTS.md ADDED
@@ -0,0 +1,529 @@
1
+ # AGENTS.md
2
+
3
+ This file contains instructions for AI agents working with the `@diplodoc/lint` project.
4
+
5
+ ## Common Rules and Standards
6
+
7
+ **Important**: This package follows common rules and standards defined in the Diplodoc metapackage. When working in metapackage mode, refer to:
8
+
9
+ - **`.agents/style-and-testing.md`** in the metapackage root for:
10
+ - Code style guidelines
11
+ - Commit message format (Conventional Commits)
12
+ - Pre-commit hooks rules (**CRITICAL**: Never commit with `--no-verify`)
13
+ - Testing standards
14
+ - Documentation requirements
15
+ - **`.agents/core.md`** for core concepts
16
+ - **`.agents/monorepo.md`** for workspace and dependency management
17
+ - **`.agents/dev-infrastructure.md`** for build and CI/CD
18
+
19
+ **Note**: In standalone mode (when this package is used independently), these rules still apply. If you need to reference the full documentation, check the [Diplodoc metapackage repository](https://github.com/diplodoc-platform/diplodoc).
20
+
21
+ ## Project Description
22
+
23
+ `@diplodoc/lint` is a DevOps infrastructure package that provides linting utilities for all Diplodoc platform packages. It consolidates ESLint, Prettier, Stylelint, Husky, and lint-staged configurations into a single package, replacing the deprecated `@diplodoc/eslint-config` and `@diplodoc/prettier-config` packages.
24
+
25
+ **Key Features**:
26
+
27
+ - Unified linting infrastructure for all platform packages
28
+ - Automatic infrastructure updates on each run
29
+ - Pre-commit hooks via Husky
30
+ - Multiple ESLint configurations (common, client, node)
31
+ - Prettier and Stylelint configurations
32
+ - SVGO integration for SVG optimization
33
+
34
+ ## Project Structure
35
+
36
+ ### Main Directories
37
+
38
+ - `bin/` — executable scripts (see detailed description below)
39
+ - `scaffolding/` — template files copied during `init`/`update`
40
+ - `.eslintrc.js` — ESLint configuration template
41
+ - `.prettierrc.js` — Prettier configuration template
42
+ - `.stylelintrc.js` — Stylelint configuration template
43
+ - `.lintstagedrc.js` — lint-staged configuration template
44
+ - `.husky/pre-commit` — Husky pre-commit hook template
45
+ - `scripts/` — helper scripts for package.json and .ignore file modification
46
+ - `modify-package.js` — adds lint scripts to package.json
47
+ - `modify-ignore.js` — updates .ignore files with standard patterns
48
+ - `test/` — package tests
49
+
50
+ ### Configuration Files
51
+
52
+ - `eslint-common-config.js` — common ESLint configuration
53
+ - `eslint-client-config.js` — client-side ESLint configuration
54
+ - `eslint-node-config.js` — Node.js ESLint configuration
55
+ - `eslint-prettier-config.js` — ESLint config with Prettier integration
56
+ - `prettier-common-config.js` — Prettier configuration
57
+ - `stylelint-common-config.js` — Stylelint configuration
58
+
59
+ ## Tech Stack
60
+
61
+ This package follows the standard Diplodoc platform tech stack. See `.agents/dev-infrastructure.md` and `.agents/style-and-testing.md` in the metapackage root for detailed information.
62
+
63
+ **Package-specific details**:
64
+
65
+ - **Language**: JavaScript (Node.js) - no TypeScript, pure JavaScript
66
+ - **Runtime**: Node.js >=11.5.1 (npm requirement)
67
+ - **Testing**: Custom test setup in `test/` directory (Node.js `assert` and `child_process`, no testing framework)
68
+ - **Build**: No build step required (pure JavaScript package)
69
+
70
+ ## Usage Modes
71
+
72
+ This package can be used in two different contexts:
73
+
74
+ ### 1. As Part of Metapackage (Workspace Mode)
75
+
76
+ When `@diplodoc/lint` is part of the Diplodoc metapackage:
77
+
78
+ - Located at `devops/lint/` in the metapackage
79
+ - Linked via npm workspaces
80
+ - Dependencies are shared from metapackage root `node_modules`
81
+ - Can be developed alongside other packages
82
+ - Changes are immediately available to other packages via workspace linking
83
+
84
+ **Development in Metapackage**:
85
+
86
+ ```bash
87
+ # From metapackage root
88
+ cd devops/lint
89
+ npm install # Uses workspace dependencies
90
+
91
+ # Or from metapackage root
92
+ npx nx build @diplodoc/lint # If configured in nx
93
+ ```
94
+
95
+ **Using from Other Packages in Metapackage**:
96
+
97
+ - Other packages can use `@diplodoc/lint` directly
98
+ - Workspace linking ensures local version is used
99
+ - No need to publish to npm for local development
100
+
101
+ ### 2. As Standalone Package (Independent Mode)
102
+
103
+ When `@diplodoc/lint` is used as a standalone npm package:
104
+
105
+ - Installed via `npm install --save-dev @diplodoc/lint`
106
+ - Has its own `node_modules` with all dependencies
107
+ - Can be cloned and developed independently
108
+ - Must be published to npm for others to use
109
+
110
+ **Development Standalone**:
111
+
112
+ ```bash
113
+ # Clone the repository
114
+ git clone git@github.com:diplodoc-platform/lint.git
115
+ cd lint
116
+ npm install # Installs all dependencies locally
117
+
118
+ # Run tests
119
+ npm test
120
+ ```
121
+
122
+ **Using in External Projects**:
123
+
124
+ ```bash
125
+ # Install from npm
126
+ npm install --save-dev @diplodoc/lint
127
+
128
+ # Initialize
129
+ npx @diplodoc/lint init
130
+
131
+ # Use
132
+ npm run lint
133
+ ```
134
+
135
+ ### Important Considerations
136
+
137
+ **Path Resolution**:
138
+
139
+ - In metapackage: Scripts resolve paths relative to metapackage structure
140
+ - Standalone: Scripts resolve paths relative to package root
141
+ - Proxy scripts (`bin/eslint`, etc.) use `require.resolve()` which works in both modes
142
+
143
+ **Dependencies**:
144
+
145
+ - In metapackage: May use dependencies from root `node_modules`
146
+ - Standalone: Must have all dependencies in local `node_modules`
147
+ - Both modes should work identically from user perspective
148
+
149
+ **Package Lock Management**:
150
+
151
+ - When adding/updating dependencies, use `npm i --no-workspaces --package-lock-only` to regenerate `package-lock.json` for standalone mode
152
+ - This ensures `package-lock.json` is valid when package is used outside workspace
153
+ - Always regenerate after dependency changes to maintain standalone compatibility
154
+
155
+ **Testing**:
156
+
157
+ - Test setup works in both modes
158
+ - When testing, ensure dependencies are properly resolved
159
+ - Consider testing both modes if making significant changes
160
+
161
+ ## Setup Commands
162
+
163
+ **In Metapackage**:
164
+
165
+ ```bash
166
+ # From devops/lint directory
167
+ npm install # Uses workspace dependencies
168
+
169
+ # Or from metapackage root
170
+ npm install # Installs all workspace dependencies
171
+ ```
172
+
173
+ **Standalone**:
174
+
175
+ ```bash
176
+ # Install dependencies
177
+ npm install
178
+
179
+ # Run tests
180
+ npm test
181
+ ```
182
+
183
+ **Important: Package Lock Management**
184
+
185
+ When working in metapackage mode but need to update `package-lock.json` for standalone mode:
186
+
187
+ ```bash
188
+ # Regenerate package-lock.json for standalone mode
189
+ npm i --no-workspaces --package-lock-only
190
+ ```
191
+
192
+ This ensures `package-lock.json` is valid when the package is used as a standalone npm package (not in workspace). Always use this when adding/updating dependencies in standalone mode.
193
+
194
+ ## Development Commands
195
+
196
+ **In Metapackage**:
197
+
198
+ ```bash
199
+ # From devops/lint directory
200
+ cd test && npm start
201
+
202
+ # Or using nx from metapackage root
203
+ npx nx test @diplodoc/lint # If configured
204
+ ```
205
+
206
+ **Standalone**:
207
+
208
+ ```bash
209
+ # Test the package
210
+ cd test && npm start
211
+ ```
212
+
213
+ ## Architecture
214
+
215
+ ### Bin Directory Structure
216
+
217
+ The `bin/` directory contains executable scripts that are made available via npm bin:
218
+
219
+ **Main Script: `lint`**
220
+
221
+ - **Purpose**: Main entry point for all linting operations
222
+ - **Commands**:
223
+ - `lint` (default) — runs all linters in check mode
224
+ - `lint fix` — runs all linters in fix mode (auto-fixes issues)
225
+ - `lint init` — initializes linting infrastructure in a package
226
+ - `lint update` — updates linting infrastructure (runs automatically on each `lint` call)
227
+
228
+ **Proxy Scripts** (redirect to original binaries from node_modules):
229
+
230
+ - `eslint` — proxies to `eslint/bin/eslint.js`
231
+ - `prettier` — proxies to `prettier/bin/prettier.cjs`
232
+ - `stylelint` — proxies to `stylelint/bin/stylelint.mjs`
233
+ - `husky` — proxies to `husky/bin.js`
234
+ - `lint-staged` — proxies to `lint-staged/bin/lint-staged.js`
235
+ - `svgo` — proxies to `svgo/bin/svgo`
236
+
237
+ **How Proxy Scripts Work**:
238
+
239
+ 1. Find the source directory of `@diplodoc/lint` package
240
+ 2. Use `require.resolve()` to locate the original package in node_modules
241
+ 3. Redirect execution to the original binary
242
+ 4. This allows using tools via `npx @diplodoc/lint eslint` instead of `npx eslint`
243
+
244
+ **Lint Script Behavior**:
245
+
246
+ **Default mode** (`lint`):
247
+
248
+ - Runs ESLint on all JS/TS files (check only)
249
+ - Runs Prettier in check mode on all JS/TS files
250
+ - Runs Stylelint on CSS/SCSS files (if found and not ignored)
251
+
252
+ **Fix mode** (`lint fix`):
253
+
254
+ - Runs ESLint with `--fix` flag (auto-fixes issues)
255
+ - Runs Prettier with `--write` flag (formats files)
256
+ - Runs Stylelint with `--fix` flag (auto-fixes CSS issues)
257
+
258
+ **Init/Update mode** (`lint init` or `lint update`):
259
+
260
+ 1. **Modify package.json**: Adds/updates lint scripts via `scripts/modify-package.js`
261
+ 2. **Initialize Husky**: Runs `husky init` (only on `init`)
262
+ 3. **Copy scaffolding**: Copies all files from `scaffolding/` directory to package root
263
+ 4. **Update ignore files**: Extends `.gitignore`, `.eslintignore`, `.prettierignore`, `.stylelintignore` via `scripts/modify-ignore.js`
264
+
265
+ ### Infrastructure Auto-Update
266
+
267
+ **Key Design Principle**: The package automatically checks and updates infrastructure in consuming packages on each run.
268
+
269
+ **How it works**:
270
+
271
+ 1. `@diplodoc/lint` is installed as a dev dependency in packages
272
+ 2. It's configured in `prepare` scripts: `"prepare": "husky || true"`
273
+ 3. On each `lint` command execution, it runs `lint update` first
274
+ 4. The `update` command checks if scaffolding files are up-to-date
275
+ 5. If outdated, it automatically copies/updates configuration files
276
+ 6. This prevents infrastructure drift across packages
277
+
278
+ **Current Implementation**:
279
+
280
+ - `lint update` always copies scaffolding files (overwrites existing)
281
+ - `lint update` always updates ignore files (adds missing patterns)
282
+ - No diff checking - always performs updates
283
+
284
+ **Potential Improvements**:
285
+
286
+ - Add hash-based change detection to skip unnecessary file operations
287
+ - Cache scaffolding file hashes to avoid redundant copies
288
+ - Only update ignore files if patterns are actually missing
289
+
290
+ ### Package Integration
291
+
292
+ When a package uses `@diplodoc/lint`:
293
+
294
+ 1. **Installation**: `npm install --save-dev @diplodoc/lint`
295
+ 2. **Initialization**: `npx @diplodoc/lint init`
296
+ - **Step 1**: Modifies `package.json` via `scripts/modify-package.js`
297
+ - Adds `lint`, `lint:fix`, `pre-commit`, `prepare` scripts
298
+ - **Step 2**: Initializes Husky (`husky init`)
299
+ - Creates `.husky/` directory
300
+ - Sets up git hooks
301
+ - **Step 3**: Copies scaffolding files from `scaffolding/` to package root
302
+ - `.eslintrc.js`, `.prettierrc.js`, `.stylelintrc.js`
303
+ - `.lintstagedrc.js`, `.husky/pre-commit`
304
+ - **Step 4**: Updates ignore files via `scripts/modify-ignore.js`
305
+ - Extends `.gitignore`, `.eslintignore`, `.prettierignore`, `.stylelintignore`
306
+ - Adds standard patterns (system files, build artifacts, node_modules)
307
+ 3. **Usage**: `npm run lint` or `npm run lint:fix`
308
+ - **Automatic update**: Runs `lint update` first (ensures infrastructure is current)
309
+ - **Then**: Runs actual linting (check or fix mode)
310
+
311
+ **Update Process** (`lint update`):
312
+
313
+ - Runs automatically on every `lint` command
314
+ - Copies scaffolding files (overwrites if changed)
315
+ - Updates ignore files (adds missing patterns)
316
+ - Does NOT re-initialize Husky (only `init` does that)
317
+ - Does NOT modify package.json scripts (only `init` does that)
318
+
319
+ ### Exports
320
+
321
+ The package exports configurations that can be imported by packages:
322
+
323
+ - `@diplodoc/lint/eslint-config` — Common ESLint config
324
+ - `@diplodoc/lint/eslint-config/client` — Client-side ESLint config
325
+ - `@diplodoc/lint/eslint-config/node` — Node.js ESLint config
326
+ - `@diplodoc/lint/prettier-config` — Prettier config
327
+ - `@diplodoc/lint/stylelint-config` — Stylelint config
328
+
329
+ Packages can extend these configs at the `src` level if needed.
330
+
331
+ ## Configuration
332
+
333
+ ### Linting Tools
334
+
335
+ **ESLint**:
336
+
337
+ - Uses `@gravity-ui/eslint-config` as base
338
+ - TypeScript support via `@typescript-eslint/eslint-plugin`
339
+ - Import resolution via `eslint-import-resolver-typescript`
340
+ - Security checks via `eslint-plugin-security`
341
+ - Prettier integration via `eslint-config-prettier`
342
+
343
+ **Prettier**:
344
+
345
+ - Uses `@gravity-ui/prettier-config` as base
346
+ - Consistent formatting across all packages
347
+
348
+ **Stylelint**:
349
+
350
+ - Uses `@gravity-ui/stylelint-config` as base
351
+ - CSS and SCSS support
352
+
353
+ **Husky**:
354
+
355
+ - Git hooks management
356
+ - Pre-commit hook runs `lint-staged`
357
+
358
+ **lint-staged**:
359
+
360
+ - Runs linting only on staged files
361
+ - Faster pre-commit checks
362
+
363
+ ### Scaffolding Files
364
+
365
+ Files in `scaffolding/` are copied to packages during `init`/`update`:
366
+
367
+ **`.eslintrc.js`**:
368
+
369
+ - Extends `@diplodoc/lint/eslint-config`
370
+ - Configures TypeScript parser with project-aware settings
371
+ - Sets `root: true` to prevent config inheritance from parent directories
372
+
373
+ **`.prettierrc.js`**:
374
+
375
+ - Exports `@diplodoc/lint/prettier-config` directly
376
+
377
+ **`.stylelintrc.js`**:
378
+
379
+ - Extends `@diplodoc/lint/stylelint-config`
380
+
381
+ **`.editorconfig`**:
382
+
383
+ - EditorConfig settings for consistent code formatting
384
+ - UTF-8 charset, LF line endings
385
+ - 4-space indentation by default, 2-space for JS/TS/JSON/YAML
386
+ - Trims trailing whitespace (except in Markdown files)
387
+
388
+ **`.lintstagedrc.js`**:
389
+
390
+ - Configures lint-staged to run on staged files:
391
+ - JS/TS files: Prettier + ESLint (with auto-fix, excludes config files and scripts)
392
+ - CSS/SCSS files: Prettier + Stylelint (with auto-fix)
393
+ - JSON/YAML/MD files: Prettier
394
+ - SVG files: SVGO optimization
395
+ - **Unit tests**: Automatically runs `npm test` when test files (`.test.ts`, `.spec.ts`) or source files (`src/`) are changed
396
+ - Config files (`.lintstagedrc.js`, `.eslintrc.js`, etc.) are excluded from ESLint checks (they use CommonJS)
397
+
398
+ **`.husky/pre-commit`**:
399
+
400
+ - Runs `npm run pre-commit` before each commit
401
+ - Pre-commit script runs `lint update && lint-staged`
402
+ - lint-staged automatically runs unit tests when relevant files are changed
403
+
404
+ **Ignore Files** (updated via `modify-ignore.js`):
405
+
406
+ - `.gitignore`, `.eslintignore`, `.prettierignore`, `.stylelintignore`
407
+ - Adds standard patterns:
408
+ - System files: `.idea`, `.vscode`, `.history`, `.env`, `.DS_Store`
409
+ - Build artifacts: `/lib`, `/dist`, `/build`, `/cache`, `/coverage`, `/external`
410
+ - Dependencies: `node_modules`
411
+
412
+ ## Testing
413
+
414
+ The package has a comprehensive test suite in the `test/` directory:
415
+
416
+ ### Test Structure
417
+
418
+ - `test/unit/` — unit tests for JavaScript modules
419
+ - `modify-package.test.js` — tests for package.json modification (8 tests)
420
+ - `modify-ignore.test.js` — tests for ignore file updates (9 tests)
421
+ - `test/integration/` — integration tests for bash scripts
422
+ - `init.test.js` — tests for `lint init` flow (4 tests)
423
+ - `update.test.js` — tests for `lint update` flow (6 tests)
424
+ - `lint.test.js` — tests for `lint` and `lint fix` flows (7 tests)
425
+ - `test/helpers/` — test utilities
426
+ - `temp-dir.js` — temporary directory management
427
+ - `file-utils.js` — file operations helpers
428
+ - `exec.js` — command execution helpers
429
+ - `test/fixtures/` — test data files
430
+ - `test/runner.js` — simple test runner (no external dependencies)
431
+
432
+ ### Running Tests
433
+
434
+ ```bash
435
+ # Run all tests
436
+ npm test
437
+
438
+ # Run only unit tests
439
+ npm run test:unit
440
+
441
+ # Run only integration tests
442
+ npm run test:integration
443
+
444
+ # Run old test script (legacy)
445
+ npm run test:old
446
+ ```
447
+
448
+ **Test Results**: All 34 tests should pass. The test runner uses Node.js built-in `assert` module and `child_process` for integration tests.
449
+
450
+ ## Code Conventions
451
+
452
+ 1. **File naming**:
453
+
454
+ - Config files: `*-config.js` (e.g., `eslint-common-config.js`)
455
+ - Scripts: `modify-*.js` in `scripts/` directory
456
+ - Binaries: executable scripts in `bin/` directory
457
+
458
+ 2. **Comments and documentation**:
459
+
460
+ - **All code comments must be in English**
461
+ - **All documentation files (ADR, AGENTS.md, README, etc.) must be in English**
462
+
463
+ 3. **Code style**:
464
+ - Follow standard JavaScript/Node.js conventions
465
+ - Use consistent formatting (enforced by Prettier)
466
+
467
+ ## Common Tasks
468
+
469
+ ### Adding a New Linting Rule
470
+
471
+ 1. Update the appropriate config file (e.g., `eslint-common-config.js`)
472
+ 2. Test the change in the `test/` directory
473
+ 3. Update version in `package.json`
474
+ 4. Packages will pick up the change on next `lint update`
475
+
476
+ ### Modifying Scaffolding Files
477
+
478
+ 1. Update files in `scaffolding/` directory
479
+ 2. Test with `npx @diplodoc/lint init` in a test package
480
+ 3. Verify that files are copied correctly
481
+ 4. Update version in `package.json`
482
+
483
+ ### Adding a New Configuration Export
484
+
485
+ 1. Create the config file (e.g., `new-config.js`)
486
+ 2. Add export to `package.json`:
487
+ ```json
488
+ {
489
+ "exports": {
490
+ "./new-config": "./new-config.js"
491
+ }
492
+ }
493
+ ```
494
+ 3. Document the export in README.md
495
+ 4. Update version in `package.json`
496
+
497
+ ### Updating Dependencies
498
+
499
+ 1. Update dependency versions in `package.json`
500
+ 2. Test that linting still works with new versions
501
+ 3. Run `npm test` to verify
502
+ 4. Update version in `package.json`
503
+
504
+ ## Important Notes
505
+
506
+ 1. **Auto-update mechanism**: The `lint update` command runs automatically on each `lint` execution. This ensures infrastructure stays in sync across packages.
507
+
508
+ 2. **Backward compatibility**: When updating configs, consider backward compatibility. Breaking changes may require major version bumps.
509
+
510
+ 3. **Package independence**: This package should not depend on other Diplodoc packages (except devops infrastructure like `@diplodoc/tsconfig` if needed).
511
+
512
+ 4. **Scaffolding updates**: When scaffolding files change, packages will automatically get updates on next `lint update` run.
513
+
514
+ 5. **Extensibility**: Packages can extend ESLint configs at the `src` level, but should not override base configs.
515
+
516
+ 6. **Replaces deprecated packages**: This package replaces `@diplodoc/eslint-config` and `@diplodoc/prettier-config`. Do not use those packages.
517
+
518
+ 7. **Used by all packages**: This is a critical infrastructure package used by all Diplodoc packages. Changes should be carefully tested.
519
+
520
+ 8. **Performance consideration**: Running `lint update` on every `lint` call can be slow. Consider implementing smart update detection in the future.
521
+
522
+ 9. **Dual usage mode**: This package works both as part of the metapackage (workspace mode) and as a standalone npm package. All scripts and commands must work correctly in both contexts. When making changes, test both modes to ensure compatibility.
523
+
524
+ ## Additional Resources
525
+
526
+ - `README.md` — main documentation
527
+ - `CONTRIBUTING.md` — contributor guide
528
+ - `CHANGELOG.md` — change history
529
+ - Metapackage `.agents/` — platform-wide agent documentation
package/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.4.0](https://github.com/diplodoc-platform/lint/compare/v1.3.3...v1.4.0) (2025-12-26)
4
+
5
+
6
+ ### Features
7
+
8
+ * add .editorconfig to scaffolding ([876ac1d](https://github.com/diplodoc-platform/lint/commit/876ac1de0e48f99b607608c87a63a2dd25ff0f5e))
9
+ * add unit tests to pre-commit hook and fix ESLint config ([3b063db](https://github.com/diplodoc-platform/lint/commit/3b063dbfd6feb382fcab2990cd6cea04b9f0d113))
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * add --no-warn-ignored flag to ESLint to suppress ignored file warnings ([06685b6](https://github.com/diplodoc-platform/lint/commit/06685b6d037d03607138836c110d7995b82a34f2))
15
+ * add eslint-env node comment to lint-staged config files ([c7516d9](https://github.com/diplodoc-platform/lint/commit/c7516d99f90b39b02ae7c788a4224da21a844fe6))
16
+ * add ignorePatterns to scaffolding/.eslintrc.js ([3a12425](https://github.com/diplodoc-platform/lint/commit/3a124252b3e41fcd4e1da337fe65305b2d252d19))
17
+ * add override for .mjs/.cjs files in ESLint config ([f494b66](https://github.com/diplodoc-platform/lint/commit/f494b661e377c0e21be86aab1f26c0d9e550fb6e))
18
+ * handle .lintstagedrc.js separately in lint-staged config ([fee8678](https://github.com/diplodoc-platform/lint/commit/fee8678ae67784c2372f21f470d4aeeaa195f7f4))
19
+ * improve cross-platform compatibility for integration tests ([d00f796](https://github.com/diplodoc-platform/lint/commit/d00f7964d4f284f727aa9ca78c0acbb9138d2a63))
20
+ * install @diplodoc/lint in test directory for npm script test ([d0bd5f1](https://github.com/diplodoc-platform/lint/commit/d0bd5f1e3c68a918b4d828309d2c14a0401592ef))
21
+ * make integration tests cross-platform compatible ([cc59464](https://github.com/diplodoc-platform/lint/commit/cc59464eb65e3cfc0589fff68a972df45cbd2305))
22
+ * update scaffolding/.lintstagedrc.js with test execution and ESLint fixes ([b065de0](https://github.com/diplodoc-platform/lint/commit/b065de0b39daa27fc1aa7bd8e2396571e887310e))
23
+ * update workflow and package-lock for standalone mode ([7fe3390](https://github.com/diplodoc-platform/lint/commit/7fe33909a55bc77ff0ba4abbae77bb936a4a2ca4))
24
+ * use find + grep to filter files before ESLint to respect .eslintignore ([edc7d90](https://github.com/diplodoc-platform/lint/commit/edc7d9047f2f902b05e708af7d1fa474b6418c0d))
25
+
26
+ ## [1.3.3](https://github.com/diplodoc-platform/lint/compare/v1.3.2...v1.3.3) (2025-08-21)
27
+
28
+
29
+ ### Bug Fixes
30
+
31
+ * Update @typescript-eslint/parser ([60cf215](https://github.com/diplodoc-platform/lint/commit/60cf215e7bea2fd50953ea1f8ce1fe234b5bc75a))
32
+
3
33
  ## [1.3.2](https://github.com/diplodoc-platform/lint/compare/v1.3.1...v1.3.2) (2025-08-20)
4
34
 
5
35
 
package/README.md CHANGED
@@ -2,32 +2,286 @@
2
2
 
3
3
  # @diplodoc/lint
4
4
 
5
- Diplodoc platform internal utility set for linting
5
+ Centralized linting and code formatting toolkit for Diplodoc projects. Combines ESLint, Prettier, and Stylelint configurations and automates their setup.
6
6
 
7
+ ## Features
7
8
 
8
- ## Install
9
+ - **Automatic setup** — one command to initialize all tools
10
+ - **Automatic updates** — synchronizes configurations across packages
11
+ - **Metapackage and standalone support** — works as part of the metapackage and as a standalone npm package
12
+ - **Unified standards** — shared linting rules for all Diplodoc packages
13
+ - **Git hooks** — automatic pre-commit hook setup via Husky
14
+ - **TypeScript/JavaScript** — full support for both languages
15
+ - **CSS/SCSS** — style support via Stylelint
9
16
 
10
- ```
17
+ ## Installation
18
+
19
+ ```bash
11
20
  npm install --save-dev @diplodoc/lint
12
21
  ```
13
22
 
14
- ## Usage
23
+ ## Quick Start
24
+
25
+ ### 1. Initialization
15
26
 
16
- Add initial configuration
27
+ Run the initialization command in your package root:
17
28
 
18
- ```sh
29
+ ```bash
19
30
  npx @diplodoc/lint init
31
+ ```
32
+
33
+ This command will:
34
+
35
+ - Add necessary scripts to `package.json`
36
+ - Create configuration files (`.eslintrc.js`, `.prettierrc.js`, `.stylelintrc.js`)
37
+ - Set up Git hooks via Husky
38
+ - Update `.gitignore`, `.eslintignore`, `.prettierignore`, `.stylelintignore`
39
+
40
+ After initialization, commit the changes:
41
+
42
+ ```bash
20
43
  git add --all && git commit -m 'chore: init lint'
21
44
  ```
22
45
 
23
- Run lint
46
+ ### 2. Usage
47
+
48
+ **Code checking:**
24
49
 
25
- ```sh
50
+ ```bash
26
51
  npm run lint
27
52
  ```
28
53
 
29
- Run lint in fix mode
54
+ **Automatic fixing:**
30
55
 
31
- ```sh
56
+ ```bash
32
57
  npm run lint:fix
33
58
  ```
59
+
60
+ **Update configurations:**
61
+
62
+ ```bash
63
+ npx @diplodoc/lint update
64
+ ```
65
+
66
+ > **Note**: The `update` command runs automatically before each check (`npm run lint`), so configurations are always up-to-date.
67
+
68
+ ## Commands
69
+
70
+ ### `lint init`
71
+
72
+ Initializes linting in a package:
73
+
74
+ - Adds scripts to `package.json`:
75
+ - `lint` — code checking
76
+ - `lint:fix` — automatic fixing
77
+ - `pre-commit` — pre-commit checking
78
+ - `prepare` — Husky setup
79
+ - Copies configuration files from `scaffolding/`
80
+ - Sets up Husky for Git hooks
81
+ - Updates ignore files
82
+
83
+ ### `lint update`
84
+
85
+ Updates configuration files to the latest versions:
86
+
87
+ - Updates `.eslintrc.js`, `.prettierrc.js`, `.stylelintrc.js`
88
+ - Updates ignore files with new patterns
89
+ - **Does not** re-initialize Husky
90
+ - **Does not** modify existing scripts in `package.json`
91
+
92
+ > **Important**: This command runs automatically before `lint` and `lint fix`, so configurations are always synchronized.
93
+
94
+ ### `lint`
95
+
96
+ Checks code for rule compliance:
97
+
98
+ 1. Automatically runs `lint update`
99
+ 2. Runs ESLint for JavaScript/TypeScript files
100
+ 3. Runs Prettier for formatting checks
101
+ 4. Runs Stylelint for CSS/SCSS files (if present)
102
+
103
+ ### `lint fix`
104
+
105
+ Automatically fixes found issues:
106
+
107
+ 1. Automatically runs `lint update`
108
+ 2. Runs ESLint with `--fix` flag
109
+ 3. Runs Prettier with `--write` flag
110
+ 4. Runs Stylelint with `--fix` flag (if CSS/SCSS files exist)
111
+
112
+ ## Configuration
113
+
114
+ After initialization, the following files are created in the package root:
115
+
116
+ ### `.eslintrc.js`
117
+
118
+ ```javascript
119
+ module.exports = {
120
+ root: true,
121
+ extends: require.resolve('@diplodoc/lint/eslint-config'),
122
+ parserOptions: {
123
+ tsconfigRootDir: __dirname,
124
+ project: true,
125
+ },
126
+ };
127
+ ```
128
+
129
+ Packages can extend the configuration at the `src/` level, but should not override base settings.
130
+
131
+ ### `.prettierrc.js`
132
+
133
+ ```javascript
134
+ module.exports = require('@diplodoc/lint/prettier-config');
135
+ ```
136
+
137
+ ### `.stylelintrc.js`
138
+
139
+ ```javascript
140
+ module.exports = {
141
+ extends: require.resolve('@diplodoc/lint/stylelint-config'),
142
+ };
143
+ ```
144
+
145
+ Created only if CSS/SCSS files exist in the project.
146
+
147
+ ## Supported Tools
148
+
149
+ ### ESLint
150
+
151
+ - Configurations for TypeScript and JavaScript
152
+ - React support (via `eslint-config/client`)
153
+ - Node.js support (via `eslint-config/node`)
154
+ - Project-aware TypeScript parsing
155
+
156
+ ### Prettier
157
+
158
+ - Unified formatting style for all packages
159
+ - Automatic formatting on save (via editor)
160
+
161
+ ### Stylelint
162
+
163
+ - CSS and SCSS support
164
+ - Uses `@gravity-ui/stylelint-config` as base
165
+
166
+ ### Husky
167
+
168
+ - Git hooks management
169
+ - Pre-commit hook runs `lint-staged`
170
+
171
+ ### lint-staged
172
+
173
+ - Checks only changed files
174
+ - Fast pre-commit checking
175
+
176
+ ## Metapackage vs Standalone Usage
177
+
178
+ The package works in two modes:
179
+
180
+ ### In Metapackage (workspace mode)
181
+
182
+ When the package is installed as part of the metapackage via npm workspaces:
183
+
184
+ - Dependencies are resolved through shared `node_modules`
185
+ - Commands work through workspace links
186
+ - `package-lock.json` is managed at the metapackage level
187
+
188
+ ### Standalone Mode
189
+
190
+ When the package is used as a standalone npm package:
191
+
192
+ - All dependencies are installed locally
193
+ - Commands work through `node_modules/.bin`
194
+ - For `package-lock.json` management, use `npm i --no-workspaces --package-lock-only`
195
+
196
+ Both modes are supported automatically — the package detects the context and works accordingly.
197
+
198
+ ## package.json Scripts
199
+
200
+ After `lint init`, the following scripts are added to `package.json`:
201
+
202
+ ```json
203
+ {
204
+ "scripts": {
205
+ "lint": "lint update && lint",
206
+ "lint:fix": "lint update && lint fix",
207
+ "pre-commit": "lint update && lint-staged",
208
+ "prepare": "husky"
209
+ }
210
+ }
211
+ ```
212
+
213
+ - `lint` — code checking (with auto-update)
214
+ - `lint:fix` — automatic fixing (with auto-update)
215
+ - `pre-commit` — pre-commit checking (runs via Husky)
216
+ - `prepare` — Husky setup when installing dependencies
217
+
218
+ ## Ignore Files
219
+
220
+ The package automatically updates the following ignore files:
221
+
222
+ - `.gitignore` — system files, dependencies, artifacts
223
+ - `.eslintignore` — system files, dependencies, artifacts, `test/`, `scripts/`
224
+ - `.prettierignore` — system files, dependencies, artifacts
225
+ - `.stylelintignore` — system files, dependencies, artifacts
226
+
227
+ Patterns are added automatically on `init` and `update`, duplicates are not created.
228
+
229
+ ## Testing
230
+
231
+ The package includes a comprehensive test suite (34 tests):
232
+
233
+ ```bash
234
+ # Run all tests
235
+ npm test
236
+
237
+ # Unit tests only
238
+ npm run test:unit
239
+
240
+ # Integration tests only
241
+ npm run test:integration
242
+ ```
243
+
244
+ Tests use Node.js built-in `assert` module and require no external dependencies.
245
+
246
+ ## Development
247
+
248
+ ### Package Structure
249
+
250
+ ```
251
+ @diplodoc/lint/
252
+ ├── bin/ # Executable scripts
253
+ │ ├── lint # Main script
254
+ │ ├── eslint # ESLint proxy
255
+ │ ├── prettier # Prettier proxy
256
+ │ └── ...
257
+ ├── scripts/ # Helper scripts
258
+ │ ├── modify-package.js
259
+ │ └── modify-ignore.js
260
+ ├── scaffolding/ # Configuration templates
261
+ │ ├── .eslintrc.js
262
+ │ ├── .prettierrc.js
263
+ │ └── ...
264
+ └── test/ # Tests
265
+ ├── unit/
266
+ ├── integration/
267
+ └── helpers/
268
+ ```
269
+
270
+ ### Making Changes
271
+
272
+ 1. Make code changes
273
+ 2. Run tests: `npm test`
274
+ 3. Check linting: `npm run lint`
275
+ 4. Test in a test package: `npx @diplodoc/lint init`
276
+
277
+ ## Important Notes
278
+
279
+ - **Auto-update**: The `lint update` command runs automatically on each `lint` execution, ensuring configuration synchronization
280
+ - **Backward compatibility**: When updating configs, backward compatibility is considered. Breaking changes require major version bumps
281
+ - **Package independence**: This package does not depend on other Diplodoc packages (except devops infrastructure)
282
+ - **Replaces deprecated packages**: This package replaces `@diplodoc/eslint-config` and `@diplodoc/prettier-config`. Do not use deprecated packages
283
+ - **Critical package**: This is a critical infrastructure dependency used by all Diplodoc packages. Changes should be thoroughly tested
284
+
285
+ ## License
286
+
287
+ MIT
package/bin/lint CHANGED
@@ -40,7 +40,12 @@ fi
40
40
  if [[ -n $FIX ]]; then
41
41
  echo "Run linters in fix mode"
42
42
 
43
- $BINDIR/eslint '**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx}' --fix
43
+ # Filter files using .eslintignore before passing to ESLint
44
+ if [[ -f .eslintignore ]]; then
45
+ find . -type f \( -name '*.js' -o -name '*.mjs' -o -name '*.cjs' -o -name '*.jsx' -o -name '*.ts' -o -name '*.mts' -o -name '*.cts' -o -name '*.tsx' \) ! -path '*/node_modules/*' | grep -vwFf .eslintignore | xargs $BINDIR/eslint --fix --no-warn-ignored || exit 1
46
+ else
47
+ $BINDIR/eslint '**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx}' --fix
48
+ fi
44
49
  $BINDIR/prettier --write '**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx}'
45
50
  if [[ -n $(find . -type f -name '*.css' -name '*.scss' | grep -vwFf .stylelintignore) ]]; then
46
51
  $BINDIR/stylelint '**/*.{css,scss}' --fix
@@ -51,7 +56,13 @@ fi
51
56
 
52
57
  echo "Run linters"
53
58
 
54
- $BINDIR/eslint '**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx}'
59
+ # Filter files using .eslintignore before passing to ESLint
60
+ # This ensures ignorePatterns and .eslintignore are respected
61
+ if [[ -f .eslintignore ]]; then
62
+ find . -type f \( -name '*.js' -o -name '*.mjs' -o -name '*.cjs' -o -name '*.jsx' -o -name '*.ts' -o -name '*.mts' -o -name '*.cts' -o -name '*.tsx' \) ! -path '*/node_modules/*' | grep -vwFf .eslintignore | xargs $BINDIR/eslint --no-warn-ignored || exit 1
63
+ else
64
+ $BINDIR/eslint '**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx}'
65
+ fi
55
66
  $BINDIR/prettier --check '**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx}'
56
67
  if [[ -n $(find . -type f -name '*.css' -name '*.scss' | grep -vwFf .stylelintignore) ]]; then
57
68
  $BINDIR/stylelint '**/*.{css,scss}'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diplodoc/lint",
3
- "version": "1.3.2",
3
+ "version": "1.4.0",
4
4
  "description": "Diplodoc platform internal utility set for linting",
5
5
  "bin": {
6
6
  "lint": "./bin/lint",
@@ -11,8 +11,22 @@
11
11
  "lint-staged": "./bin/lint-staged",
12
12
  "svgo": "./bin/svgo"
13
13
  },
14
+ "engines": {
15
+ "npm": ">=11.5.1"
16
+ },
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git@github.com:diplodoc-platform/lint.git"
20
+ },
14
21
  "scripts": {
15
- "test": "cd test && npm start"
22
+ "test": "node test/runner.js",
23
+ "test:unit": "node test/runner.js unit",
24
+ "test:integration": "node test/runner.js integration",
25
+ "test:old": "cd test && npm start",
26
+ "lint": "lint update && lint",
27
+ "lint:fix": "lint update && lint fix",
28
+ "pre-commit": "lint update && lint-staged",
29
+ "prepare": "husky"
16
30
  },
17
31
  "exports": {
18
32
  "./eslint-config": "./eslint-common-config.js",
@@ -30,7 +44,8 @@
30
44
  "@gravity-ui/eslint-config": "^3.2.0",
31
45
  "@gravity-ui/prettier-config": "^1.1.0",
32
46
  "@gravity-ui/stylelint-config": "^4.0.1",
33
- "@typescript-eslint/parser": "^6.21.0",
47
+ "@typescript-eslint/eslint-plugin": "^8.40.0",
48
+ "@typescript-eslint/parser": "^8.40.0",
34
49
  "eslint": "^8.57.0",
35
50
  "eslint-config-prettier": "^9.1.0",
36
51
  "eslint-import-resolver-typescript": "^3.6.1",
@@ -41,5 +56,8 @@
41
56
  "prettier": "^3.3.3",
42
57
  "stylelint": "15",
43
58
  "svgo": "^3.3.2"
59
+ },
60
+ "devDependencies": {
61
+ "fs-extra": "^11.3.3"
44
62
  }
45
63
  }
@@ -0,0 +1,20 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ insert_final_newline = true
7
+ trim_trailing_whitespace = true
8
+ indent_style = space
9
+ indent_size = 4
10
+
11
+ [{*.json,*.yml,*.yaml}]
12
+ indent_style = space
13
+ indent_size = 2
14
+
15
+ [*.md]
16
+ trim_trailing_whitespace = false
17
+
18
+ [GNUmakefile]
19
+ indent_style = tab
20
+ indent_size = 4
@@ -5,4 +5,12 @@ module.exports = {
5
5
  tsconfigRootDir: __dirname,
6
6
  project: true,
7
7
  },
8
+ overrides: [
9
+ {
10
+ files: ['*.mjs', '*.cjs'],
11
+ parserOptions: {
12
+ project: null,
13
+ },
14
+ },
15
+ ],
8
16
  };
@@ -1,6 +1,41 @@
1
+ /* eslint-env node */
1
2
  module.exports = {
2
- '**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx}': ['prettier --write', 'eslint --max-warnings=0 --fix'],
3
+ // Exclude config files and scripts from linting (they use CommonJS)
4
+ '**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx}': (filenames) => {
5
+ // Filter out config files and scripts
6
+ const configFiles = [
7
+ '.lintstagedrc.js',
8
+ '.eslintrc.js',
9
+ '.prettierrc.js',
10
+ '.stylelintrc.js',
11
+ ];
12
+ const filtered = filenames.filter(
13
+ (f) =>
14
+ !configFiles.some((config) => f.includes(config)) &&
15
+ !f.includes('scripts/') &&
16
+ !f.includes('test/'),
17
+ );
18
+ if (filtered.length === 0) {
19
+ return [];
20
+ }
21
+ return ['prettier --write', 'eslint --max-warnings=0 --fix --no-warn-ignored'];
22
+ },
23
+ // Handle .lintstagedrc.js separately (only prettier, no eslint)
24
+ '.lintstagedrc.js': ['prettier --write'],
3
25
  '**/*.{css,scss}': ['prettier --write', 'stylelint --fix'],
4
26
  '**/*.{json,yaml,yml,md}': ['prettier --write'],
5
27
  '**/*.{svg,svgx}': ['svgo'],
28
+ // Run unit tests when test files or source files change
29
+ '**/*.{ts,tsx}': (filenames) => {
30
+ const testFiles = filenames.filter((f) => f.includes('.test.') || f.includes('.spec.'));
31
+ const sourceFiles = filenames.filter(
32
+ (f) => !f.includes('.test.') && !f.includes('.spec.') && f.includes('src/'),
33
+ );
34
+ const commands = [];
35
+ // Run tests if test files or source files changed
36
+ if (testFiles.length > 0 || sourceFiles.length > 0) {
37
+ commands.push('npm test');
38
+ }
39
+ return commands;
40
+ },
6
41
  };
@@ -30,6 +30,14 @@ const ignores = {
30
30
  ...SYSTEM,
31
31
  ...INSTALL,
32
32
  ...ARTIFACTS,
33
+ // Test files and scripts use Node.js globals
34
+ 'test/',
35
+ 'scripts/',
36
+ // Config files use CommonJS
37
+ '.lintstagedrc.js',
38
+ '.eslintrc.js',
39
+ '.prettierrc.js',
40
+ '.stylelintrc.js',
33
41
  ],
34
42
  '.prettierignore': [
35
43
  ...SYSTEM,
@@ -11,6 +11,9 @@ try {
11
11
  }
12
12
 
13
13
  function configure(command, impl, force = false) {
14
+ if (!pkg.scripts) {
15
+ pkg.scripts = {};
16
+ }
14
17
  if (pkg.scripts[command] && !force) {
15
18
  if (pkg.scripts[command] !== impl) {
16
19
  throw `Lint command '${command}' already configured with different program`;