@better-i18n/cli 0.1.0 → 0.1.2
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/README.md +247 -83
- package/dist/analyzer/file-collector.d.ts.map +1 -1
- package/dist/analyzer/file-collector.js +48 -9
- package/dist/analyzer/file-collector.js.map +1 -1
- package/dist/analyzer/rules/jsx-text.d.ts.map +1 -1
- package/dist/analyzer/rules/jsx-text.js +2 -0
- package/dist/analyzer/rules/jsx-text.js.map +1 -1
- package/dist/analyzer/rules/ternary-locale.d.ts.map +1 -1
- package/dist/analyzer/rules/ternary-locale.js +5 -1
- package/dist/analyzer/rules/ternary-locale.js.map +1 -1
- package/dist/analyzer/types.d.ts +1 -0
- package/dist/analyzer/types.d.ts.map +1 -1
- package/dist/commands/scan.d.ts.map +1 -1
- package/dist/commands/scan.js +3 -1
- package/dist/commands/scan.js.map +1 -1
- package/dist/context/detector.d.ts.map +1 -1
- package/dist/context/detector.js +48 -23
- package/dist/context/detector.js.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/reporters/eslint-style.d.ts +2 -2
- package/dist/reporters/eslint-style.d.ts.map +1 -1
- package/dist/reporters/eslint-style.js +31 -17
- package/dist/reporters/eslint-style.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ Hardcoded strings slip into codebases easily. Finding them manually is tedious.
|
|
|
27
27
|
# Global install
|
|
28
28
|
npm install -g @better-i18n/cli
|
|
29
29
|
|
|
30
|
-
# Or use with npx (no install)
|
|
30
|
+
# Or use with npx (no install needed)
|
|
31
31
|
npx @better-i18n/cli scan
|
|
32
32
|
|
|
33
33
|
# Or add to your project
|
|
@@ -43,93 +43,167 @@ better-i18n scan
|
|
|
43
43
|
# That's it! The CLI auto-detects your i18n.config.ts
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
##
|
|
46
|
+
## Features
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
- ✅ **Auto-config detection** - Reads your existing `i18n.config.ts`
|
|
49
|
+
- ✅ **Smart filtering** - Ignores CSS classes, URLs, constants, HTML entities
|
|
50
|
+
- ✅ **Glob patterns** - Exclude test files, stories, UI components
|
|
51
|
+
- ✅ **Clickable output** - File paths are Cmd+clickable in VS Code terminal
|
|
52
|
+
- ✅ **CI/CD ready** - JSON output, exit codes, staged files support
|
|
53
|
+
- ✅ **Fast** - Scans 100+ files in <100ms
|
|
54
|
+
|
|
55
|
+
## Example Output
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
$ better-i18n scan
|
|
59
|
+
|
|
60
|
+
✓ Project: better-i18n/landing
|
|
61
|
+
✓ Found 57 files
|
|
51
62
|
|
|
52
|
-
|
|
53
|
-
|
|
63
|
+
components/sign-up.tsx (11)
|
|
64
|
+
24:13 missing "Create an account" i18n/jsx-text
|
|
65
|
+
32:22 missing "Name" i18n/jsx-text
|
|
66
|
+
40:22 missing "Email" i18n/jsx-text
|
|
54
67
|
|
|
55
|
-
|
|
56
|
-
|
|
68
|
+
components/contact.tsx (9)
|
|
69
|
+
24:59 missing "Contact us" i18n/jsx-text
|
|
70
|
+
31:22 missing "Message" i18n/jsx-text
|
|
57
71
|
|
|
58
|
-
|
|
59
|
-
better-i18n scan --staged
|
|
72
|
+
✖ 87 problems (87 missing translations)
|
|
60
73
|
|
|
61
|
-
|
|
62
|
-
better-i18n scan --verbose
|
|
74
|
+
Scanned 57 files in 0.07s
|
|
63
75
|
```
|
|
64
76
|
|
|
65
|
-
|
|
77
|
+
**Cmd+Click** on any file path to jump directly to the issue in VS Code!
|
|
66
78
|
|
|
67
|
-
|
|
68
|
-
$ better-i18n scan
|
|
79
|
+
## Commands & Options
|
|
69
80
|
|
|
70
|
-
|
|
71
|
-
✓ Found 45 files
|
|
81
|
+
### `better-i18n scan`
|
|
72
82
|
|
|
73
|
-
|
|
74
|
-
12:8 warning "Welcome back" i18n/jsx-text
|
|
75
|
-
15:18 warning "Profile picture" i18n/jsx-attribute
|
|
83
|
+
Scan your codebase for hardcoded strings.
|
|
76
84
|
|
|
77
|
-
|
|
78
|
-
|
|
85
|
+
```bash
|
|
86
|
+
# Basic usage
|
|
87
|
+
better-i18n scan
|
|
88
|
+
|
|
89
|
+
# Scan specific directory
|
|
90
|
+
better-i18n scan --dir ./src
|
|
91
|
+
|
|
92
|
+
# Output formats
|
|
93
|
+
better-i18n scan --format json # JSON output for CI/tooling
|
|
94
|
+
better-i18n scan --format eslint # Human-readable (default)
|
|
79
95
|
|
|
80
|
-
|
|
96
|
+
# CI/CD integration
|
|
97
|
+
better-i18n scan --ci # Exit with code 1 if issues found
|
|
98
|
+
better-i18n scan --staged # Only scan git staged files
|
|
81
99
|
|
|
82
|
-
|
|
100
|
+
# Debug
|
|
101
|
+
better-i18n scan --verbose # Show detailed output
|
|
83
102
|
```
|
|
84
103
|
|
|
85
104
|
## Detection Rules
|
|
86
105
|
|
|
87
|
-
| Rule | Severity | What it catches |
|
|
88
|
-
|
|
89
|
-
| `jsx-text` |
|
|
90
|
-
| `jsx-attribute` |
|
|
91
|
-
| `ternary-locale` | error | `locale === 'en' ? '
|
|
106
|
+
| Rule | Severity | What it catches | Example |
|
|
107
|
+
|------|----------|-----------------|---------|
|
|
108
|
+
| `jsx-text` | missing | Hardcoded text in JSX | `<h1>Hello</h1>` |
|
|
109
|
+
| `jsx-attribute` | missing | Hardcoded attributes | `<img alt="Logo" />` |
|
|
110
|
+
| `ternary-locale` | error | Locale-based ternaries | `locale === 'en' ? 'Hi' : 'Hola'` |
|
|
111
|
+
|
|
112
|
+
### Automatically Ignored
|
|
113
|
+
|
|
114
|
+
- HTML entities: `"`, `&`, `'`
|
|
115
|
+
- CSS classes: `className="flex items-center"`
|
|
116
|
+
- URLs: `href="https://example.com"`
|
|
117
|
+
- Paths: `/api/users`
|
|
118
|
+
- Numbers: `42`, `3.14`, `100%`
|
|
119
|
+
- Constants: `SCREAMING_CASE`
|
|
120
|
+
- Symbols: `→`, `•`, `...`
|
|
92
121
|
|
|
93
122
|
## Configuration
|
|
94
123
|
|
|
95
|
-
|
|
124
|
+
Create or update your `i18n.config.ts`:
|
|
96
125
|
|
|
97
126
|
```ts
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
export const
|
|
102
|
-
project
|
|
103
|
-
defaultLocale
|
|
104
|
-
|
|
105
|
-
// Optional: customize lint behavior
|
|
127
|
+
export const project = "your-org/your-project";
|
|
128
|
+
export const defaultLocale = "en";
|
|
129
|
+
|
|
130
|
+
export const i18nWorkspaceConfig = {
|
|
131
|
+
project,
|
|
132
|
+
defaultLocale,
|
|
106
133
|
lint: {
|
|
134
|
+
// Files to scan (defaults: ["src", "app", "components", "pages"])
|
|
107
135
|
include: ["src/**/*.tsx", "app/**/*.tsx"],
|
|
108
|
-
|
|
136
|
+
|
|
137
|
+
// Files to ignore (automatically merges with defaults)
|
|
138
|
+
exclude: [
|
|
139
|
+
"**/skeletons.tsx", // Mock/demo components
|
|
140
|
+
"**/*.stories.tsx", // Storybook files
|
|
141
|
+
"**/*.test.tsx", // Test files
|
|
142
|
+
"**/components/ui/**", // UI library components
|
|
143
|
+
],
|
|
144
|
+
|
|
145
|
+
// Rule configuration (optional)
|
|
109
146
|
rules: {
|
|
110
147
|
"jsx-text": "warning",
|
|
111
|
-
"jsx-attribute": "warning",
|
|
148
|
+
"jsx-attribute": "warning",
|
|
112
149
|
"ternary-locale": "error",
|
|
113
150
|
},
|
|
114
151
|
},
|
|
115
|
-
}
|
|
152
|
+
};
|
|
116
153
|
```
|
|
117
154
|
|
|
118
|
-
###
|
|
155
|
+
### Config Options
|
|
119
156
|
|
|
120
157
|
| Option | Type | Description |
|
|
121
158
|
|--------|------|-------------|
|
|
122
|
-
| `include` | `string[]` | Glob patterns for files to scan |
|
|
123
|
-
| `exclude` | `string[]` | Glob patterns
|
|
124
|
-
| `rules` | `object` |
|
|
159
|
+
| `include` | `string[]` | Glob patterns for files to scan (default: `["src", "app", "components", "pages"]`) |
|
|
160
|
+
| `exclude` | `string[]` | Glob patterns to ignore (merges with defaults: `node_modules`, `.next`, etc.) |
|
|
161
|
+
| `rules` | `object` | Set severity: `"error"` \| `"warning"` \| `"off"` |
|
|
162
|
+
|
|
163
|
+
## Usage Scenarios
|
|
164
|
+
|
|
165
|
+
### 1. Local Development
|
|
166
|
+
|
|
167
|
+
Add to your `package.json`:
|
|
125
168
|
|
|
126
|
-
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"scripts": {
|
|
172
|
+
"lint": "next lint && better-i18n scan --ci",
|
|
173
|
+
"lint:i18n": "better-i18n scan"
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Run before commits:
|
|
179
|
+
```bash
|
|
180
|
+
npm run lint:i18n
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### 2. Pre-commit Hook
|
|
184
|
+
|
|
185
|
+
Install [Husky](https://typicode.github.io/husky/):
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
npx husky init
|
|
189
|
+
echo "npx @better-i18n/cli scan --staged --ci" > .husky/pre-commit
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Or with [lint-staged](https://github.com/lint-staged/lint-staged):
|
|
193
|
+
|
|
194
|
+
```json
|
|
195
|
+
{
|
|
196
|
+
"lint-staged": {
|
|
197
|
+
"*.{tsx,jsx}": ["better-i18n scan --ci"]
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
```
|
|
127
201
|
|
|
128
|
-
### GitHub Actions
|
|
202
|
+
### 3. GitHub Actions CI
|
|
129
203
|
|
|
130
204
|
```yaml
|
|
131
|
-
# .github/workflows/i18n-
|
|
132
|
-
name: i18n
|
|
205
|
+
# .github/workflows/i18n-check.yml
|
|
206
|
+
name: i18n Check
|
|
133
207
|
|
|
134
208
|
on: [push, pull_request]
|
|
135
209
|
|
|
@@ -141,77 +215,167 @@ jobs:
|
|
|
141
215
|
- uses: actions/setup-node@v4
|
|
142
216
|
with:
|
|
143
217
|
node-version: '20'
|
|
144
|
-
- run: npx @better-i18n/cli scan --ci
|
|
218
|
+
- run: npx @better-i18n/cli scan --ci --format json
|
|
145
219
|
```
|
|
146
220
|
|
|
147
|
-
###
|
|
221
|
+
### 4. VS Code Integration
|
|
148
222
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
```bash
|
|
152
|
-
# .husky/pre-commit
|
|
153
|
-
npx @better-i18n/cli scan --staged --ci
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
Or with [lint-staged](https://github.com/lint-staged/lint-staged):
|
|
223
|
+
Add to `.vscode/tasks.json`:
|
|
157
224
|
|
|
158
225
|
```json
|
|
159
226
|
{
|
|
160
|
-
"
|
|
161
|
-
|
|
162
|
-
|
|
227
|
+
"version": "2.0.0",
|
|
228
|
+
"tasks": [
|
|
229
|
+
{
|
|
230
|
+
"label": "i18n: Check translations",
|
|
231
|
+
"type": "shell",
|
|
232
|
+
"command": "npx @better-i18n/cli scan",
|
|
233
|
+
"problemMatcher": [],
|
|
234
|
+
"presentation": {
|
|
235
|
+
"reveal": "always",
|
|
236
|
+
"panel": "new"
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
]
|
|
163
240
|
}
|
|
164
241
|
```
|
|
165
242
|
|
|
243
|
+
Run with: `Cmd+Shift+P` → `Tasks: Run Task` → `i18n: Check translations`
|
|
244
|
+
|
|
245
|
+
### 5. Monorepo Usage
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
# Scan specific package
|
|
249
|
+
cd packages/web-app
|
|
250
|
+
better-i18n scan
|
|
251
|
+
|
|
252
|
+
# Or from root with --dir
|
|
253
|
+
better-i18n scan --dir packages/web-app
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Each package can have its own `i18n.config.ts`.
|
|
257
|
+
|
|
166
258
|
## JSON Output
|
|
167
259
|
|
|
168
|
-
Use `--format json` for programmatic
|
|
260
|
+
Use `--format json` for programmatic integration:
|
|
169
261
|
|
|
170
262
|
```bash
|
|
171
|
-
better-i18n scan --format json
|
|
263
|
+
better-i18n scan --format json > i18n-report.json
|
|
172
264
|
```
|
|
173
265
|
|
|
174
266
|
```json
|
|
175
267
|
{
|
|
176
268
|
"project": {
|
|
177
|
-
"workspaceId": "
|
|
178
|
-
"projectSlug": "
|
|
269
|
+
"workspaceId": "better-i18n",
|
|
270
|
+
"projectSlug": "landing",
|
|
179
271
|
"defaultLocale": "en"
|
|
180
272
|
},
|
|
181
|
-
"files":
|
|
273
|
+
"files": 57,
|
|
182
274
|
"issues": [
|
|
183
275
|
{
|
|
184
|
-
"file": "
|
|
185
|
-
"line":
|
|
186
|
-
"column":
|
|
187
|
-
"text": "
|
|
276
|
+
"file": "components/sign-up.tsx",
|
|
277
|
+
"line": 24,
|
|
278
|
+
"column": 13,
|
|
279
|
+
"text": "Create an account",
|
|
188
280
|
"type": "jsx-text",
|
|
189
281
|
"severity": "warning",
|
|
190
|
-
"message": "Hardcoded text
|
|
282
|
+
"message": "Hardcoded text: \"Create an account\"",
|
|
283
|
+
"suggestedKey": "signUp.createAnAccount"
|
|
191
284
|
}
|
|
192
285
|
],
|
|
193
|
-
"duration":
|
|
286
|
+
"duration": 67
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### JSON Schema
|
|
291
|
+
|
|
292
|
+
```ts
|
|
293
|
+
interface ScanResult {
|
|
294
|
+
project?: {
|
|
295
|
+
workspaceId: string;
|
|
296
|
+
projectSlug: string;
|
|
297
|
+
defaultLocale: string;
|
|
298
|
+
};
|
|
299
|
+
files: number;
|
|
300
|
+
issues: Issue[];
|
|
301
|
+
duration: number;
|
|
194
302
|
}
|
|
303
|
+
|
|
304
|
+
interface Issue {
|
|
305
|
+
file: string; // Relative path
|
|
306
|
+
line: number; // Line number
|
|
307
|
+
column: number; // Column number
|
|
308
|
+
text: string; // Hardcoded text
|
|
309
|
+
type: "jsx-text" | "jsx-attribute" | "ternary-locale";
|
|
310
|
+
severity: "error" | "warning";
|
|
311
|
+
message: string; // Human-readable message
|
|
312
|
+
suggestedKey?: string; // Auto-generated translation key
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## Advanced Usage
|
|
317
|
+
|
|
318
|
+
### Custom Scripts
|
|
319
|
+
|
|
320
|
+
```bash
|
|
321
|
+
# Count missing translations
|
|
322
|
+
better-i18n scan --format json | jq '.issues | length'
|
|
323
|
+
|
|
324
|
+
# Get unique files with issues
|
|
325
|
+
better-i18n scan --format json | jq -r '.issues[].file' | sort -u
|
|
326
|
+
|
|
327
|
+
# Filter only errors
|
|
328
|
+
better-i18n scan --format json | jq '.issues[] | select(.severity == "error")'
|
|
195
329
|
```
|
|
196
330
|
|
|
197
|
-
|
|
331
|
+
### Combine with Other Tools
|
|
198
332
|
|
|
199
|
-
|
|
333
|
+
```bash
|
|
334
|
+
# Run with TypeScript checks
|
|
335
|
+
tsc --noEmit && better-i18n scan --ci
|
|
336
|
+
|
|
337
|
+
# Run with ESLint
|
|
338
|
+
eslint . && better-i18n scan --ci
|
|
200
339
|
|
|
201
|
-
|
|
202
|
-
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
340
|
+
# Parallel execution
|
|
341
|
+
npm-run-all --parallel typecheck lint:eslint lint:i18n
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
## Troubleshooting
|
|
345
|
+
|
|
346
|
+
### Config not detected
|
|
347
|
+
|
|
348
|
+
Make sure your `i18n.config.ts` exports either:
|
|
349
|
+
- `export const project = "org/slug"`
|
|
350
|
+
- `export const i18nWorkspaceConfig = { project: "org/slug" }`
|
|
351
|
+
|
|
352
|
+
### Too many false positives
|
|
353
|
+
|
|
354
|
+
Add exclusions to your config:
|
|
355
|
+
```ts
|
|
356
|
+
exclude: [
|
|
357
|
+
"**/*.stories.tsx",
|
|
358
|
+
"**/demo/**",
|
|
359
|
+
"**/examples/**",
|
|
360
|
+
]
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### Clickable links not working
|
|
364
|
+
|
|
365
|
+
Make sure you're using VS Code's integrated terminal. External terminals may not support clickable file paths.
|
|
207
366
|
|
|
208
367
|
## Part of Better i18n
|
|
209
368
|
|
|
210
369
|
This CLI is part of the [Better i18n](https://better-i18n.com) ecosystem:
|
|
211
370
|
|
|
212
371
|
- **[@better-i18n/next](https://www.npmjs.com/package/@better-i18n/next)** - Next.js i18n SDK
|
|
213
|
-
- **[@better-i18n/cli](https://www.npmjs.com/package/@better-i18n/cli)** - This CLI
|
|
372
|
+
- **[@better-i18n/cli](https://www.npmjs.com/package/@better-i18n/cli)** - This CLI tool
|
|
214
373
|
- **[Dashboard](https://better-i18n.com)** - Visual translation management
|
|
374
|
+
- **[MCP Server](https://github.com/better-i18n/better-i18n)** - AI-powered translation assistant
|
|
375
|
+
|
|
376
|
+
## Contributing
|
|
377
|
+
|
|
378
|
+
Found a bug or have a feature request? [Open an issue](https://github.com/better-i18n/better-i18n/issues).
|
|
215
379
|
|
|
216
380
|
## License
|
|
217
381
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-collector.d.ts","sourceRoot":"","sources":["../../src/analyzer/file-collector.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAeD;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"file-collector.d.ts","sourceRoot":"","sources":["../../src/analyzer/file-collector.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAeD;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAqC7E;AA2CD;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAAE,GACjB,OAAO,CAmDT"}
|
|
@@ -21,20 +21,25 @@ const DEFAULT_EXTENSIONS = [".tsx", ".jsx"];
|
|
|
21
21
|
* Collect files to analyze
|
|
22
22
|
*/
|
|
23
23
|
export async function collectFiles(options) {
|
|
24
|
-
const { rootDir, include = DEFAULT_INCLUDE,
|
|
24
|
+
const { rootDir, include = DEFAULT_INCLUDE, extensions = DEFAULT_EXTENSIONS, } = options;
|
|
25
|
+
// Merge default excludes with user-provided excludes
|
|
26
|
+
const allExcludes = [...DEFAULT_EXCLUDE, ...(options.exclude || [])];
|
|
25
27
|
const files = [];
|
|
26
|
-
|
|
28
|
+
// Directory names to exclude (no glob)
|
|
29
|
+
const excludeSet = new Set(allExcludes.filter((e) => !e.includes("*")));
|
|
30
|
+
// Glob patterns to exclude
|
|
31
|
+
const globPatterns = allExcludes.filter((e) => e.includes("*"));
|
|
27
32
|
// Check which include directories exist
|
|
28
33
|
const existingDirs = include.filter((dir) => existsSync(join(rootDir, dir)));
|
|
29
34
|
// If no include dirs exist, scan root
|
|
30
35
|
const dirsToScan = existingDirs.length > 0 ? existingDirs : ["."];
|
|
31
36
|
for (const dir of dirsToScan) {
|
|
32
37
|
const fullDir = join(rootDir, dir);
|
|
33
|
-
collectFromDir(fullDir, rootDir, files, excludeSet, extensions);
|
|
38
|
+
collectFromDir(fullDir, rootDir, files, excludeSet, extensions, globPatterns);
|
|
34
39
|
}
|
|
35
40
|
return files;
|
|
36
41
|
}
|
|
37
|
-
function collectFromDir(dir, rootDir, files, excludeSet, extensions) {
|
|
42
|
+
function collectFromDir(dir, rootDir, files, excludeSet, extensions, globPatterns = []) {
|
|
38
43
|
try {
|
|
39
44
|
const entries = readdirSync(dir, { withFileTypes: true });
|
|
40
45
|
for (const entry of entries) {
|
|
@@ -42,11 +47,17 @@ function collectFromDir(dir, rootDir, files, excludeSet, extensions) {
|
|
|
42
47
|
continue;
|
|
43
48
|
const fullPath = join(dir, entry.name);
|
|
44
49
|
if (entry.isDirectory()) {
|
|
45
|
-
|
|
50
|
+
// Check if directory matches glob pattern like **/components/ui/**
|
|
51
|
+
if (shouldExcludeFile(fullPath, globPatterns))
|
|
52
|
+
continue;
|
|
53
|
+
collectFromDir(fullPath, rootDir, files, excludeSet, extensions, globPatterns);
|
|
46
54
|
}
|
|
47
55
|
else if (entry.isFile()) {
|
|
48
56
|
const ext = entry.name.slice(entry.name.lastIndexOf("."));
|
|
49
57
|
if (extensions.includes(ext)) {
|
|
58
|
+
// Check if file matches glob pattern
|
|
59
|
+
if (shouldExcludeFile(fullPath, globPatterns))
|
|
60
|
+
continue;
|
|
50
61
|
files.push(fullPath);
|
|
51
62
|
}
|
|
52
63
|
}
|
|
@@ -62,17 +73,45 @@ function collectFromDir(dir, rootDir, files, excludeSet, extensions) {
|
|
|
62
73
|
export function shouldExcludeFile(filePath, patterns) {
|
|
63
74
|
const fileName = filePath.split("/").pop() || "";
|
|
64
75
|
for (const pattern of patterns) {
|
|
65
|
-
|
|
76
|
+
// Handle **/filename.ext pattern (match filename anywhere)
|
|
77
|
+
if (pattern.startsWith("**/") && !pattern.slice(3).includes("/")) {
|
|
78
|
+
const filePattern = pattern.slice(3); // Remove **/
|
|
79
|
+
if (filePattern.includes("*")) {
|
|
80
|
+
// Convert glob to regex: *.stories.tsx -> .*\.stories\.tsx
|
|
81
|
+
const regex = new RegExp("^" + filePattern.replace(/\./g, "\\.").replace(/\*/g, ".*") + "$");
|
|
82
|
+
if (regex.test(fileName))
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
else if (fileName === filePattern) {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Handle **/dir/** pattern (match directory path)
|
|
90
|
+
else if (pattern.startsWith("**/") && pattern.endsWith("/**")) {
|
|
91
|
+
const dirName = pattern.slice(3, -3); // Remove **/ and /**
|
|
92
|
+
if (filePath.includes(`/${dirName}/`) ||
|
|
93
|
+
filePath.includes(`${dirName}/`)) {
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Handle **/*.ext pattern (match extension)
|
|
98
|
+
else if (pattern.startsWith("**/*.")) {
|
|
66
99
|
const ext = pattern.slice(4);
|
|
67
100
|
if (fileName.endsWith(ext))
|
|
68
101
|
return true;
|
|
69
102
|
}
|
|
103
|
+
// Handle simple glob
|
|
70
104
|
else if (pattern.includes("*")) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
105
|
+
const regex = new RegExp("^" +
|
|
106
|
+
pattern
|
|
107
|
+
.replace(/\./g, "\\.")
|
|
108
|
+
.replace(/\*\*/g, ".*")
|
|
109
|
+
.replace(/\*/g, "[^/]*") +
|
|
110
|
+
"$");
|
|
111
|
+
if (regex.test(filePath) || regex.test(fileName))
|
|
74
112
|
return true;
|
|
75
113
|
}
|
|
114
|
+
// Simple string match
|
|
76
115
|
else if (filePath.includes(pattern)) {
|
|
77
116
|
return true;
|
|
78
117
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-collector.js","sourceRoot":"","sources":["../../src/analyzer/file-collector.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAUjC,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC;AAC9D,MAAM,eAAe,GAAG;IACtB,cAAc;IACd,MAAM;IACN,OAAO;IACP,MAAM;IACN,OAAO;IACP,KAAK;IACL,WAAW;IACX,WAAW;CACZ,CAAC;AACF,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE5C;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAAuB;IACxD,MAAM,EACJ,OAAO,EACP,OAAO,GAAG,eAAe,EACzB,
|
|
1
|
+
{"version":3,"file":"file-collector.js","sourceRoot":"","sources":["../../src/analyzer/file-collector.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsx-text.d.ts","sourceRoot":"","sources":["../../../src/analyzer/rules/jsx-text.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"jsx-text.d.ts","sourceRoot":"","sources":["../../../src/analyzer/rules/jsx-text.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAiBtD;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,WAAW,GAAG,KAAK,GAAG,IAAI,CAwB7E"}
|
|
@@ -15,6 +15,8 @@ const IGNORE_PATTERNS = [
|
|
|
15
15
|
/^https?:\/\//, // URLs
|
|
16
16
|
/^\//, // Paths
|
|
17
17
|
/^[a-z-]+$/, // CSS-like (lowercase with hyphens only)
|
|
18
|
+
/^&[a-z]+;$/, // HTML entities like " &
|
|
19
|
+
/^&#\d+;$/, // Numeric HTML entities like '
|
|
18
20
|
];
|
|
19
21
|
/**
|
|
20
22
|
* Check JSX text node for hardcoded strings
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsx-text.js","sourceRoot":"","sources":["../../../src/analyzer/rules/jsx-text.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,sBAAsB,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGvE;;GAEG;AACH,MAAM,eAAe,GAAG;IACtB,eAAe,EAAE,kBAAkB;IACnC,oCAAoC,EAAE,eAAe;IACrD,gBAAgB,EAAE,+BAA+B;IACjD,WAAW,EAAE,iBAAiB;IAC9B,cAAc,EAAE,OAAO;IACvB,KAAK,EAAE,QAAQ;IACf,WAAW,EAAE,yCAAyC;
|
|
1
|
+
{"version":3,"file":"jsx-text.js","sourceRoot":"","sources":["../../../src/analyzer/rules/jsx-text.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,sBAAsB,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGvE;;GAEG;AACH,MAAM,eAAe,GAAG;IACtB,eAAe,EAAE,kBAAkB;IACnC,oCAAoC,EAAE,eAAe;IACrD,gBAAgB,EAAE,+BAA+B;IACjD,WAAW,EAAE,iBAAiB;IAC9B,cAAc,EAAE,OAAO;IACvB,KAAK,EAAE,QAAQ;IACf,WAAW,EAAE,yCAAyC;IACtD,YAAY,EAAE,yCAAyC;IACvD,UAAU,EAAE,mCAAmC;CAChD,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,IAAgB,EAAE,GAAgB;IAC7D,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IAE9B,2BAA2B;IAC3B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAE3C,wBAAwB;IACxB,KAAK,MAAM,OAAO,IAAI,eAAe,EAAE,CAAC;QACtC,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;IACtC,CAAC;IAED,eAAe;IACf,MAAM,GAAG,GAAG,GAAG,CAAC,UAAU,CAAC,6BAA6B,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IAE1E,OAAO;QACL,IAAI,EAAE,GAAG,CAAC,QAAQ;QAClB,IAAI,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC;QAClB,MAAM,EAAE,GAAG,CAAC,SAAS,GAAG,CAAC;QACzB,IAAI;QACJ,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE,SAAS;QACnB,OAAO,EAAE,oBAAoB,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG;QAClD,YAAY,EAAE,sBAAsB,CAAC,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC;KACzD,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ternary-locale.d.ts","sourceRoot":"","sources":["../../../src/analyzer/rules/ternary-locale.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEtD;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,EAAE,CAAC,qBAAqB,EAC9B,GAAG,EAAE,WAAW,GACf,KAAK,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"ternary-locale.d.ts","sourceRoot":"","sources":["../../../src/analyzer/rules/ternary-locale.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEtD;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,EAAE,CAAC,qBAAqB,EAC9B,GAAG,EAAE,WAAW,GACf,KAAK,GAAG,IAAI,CAgDd"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Detects anti-pattern: locale === 'en' ? 'Hello' : 'Merhaba'
|
|
5
5
|
*/
|
|
6
6
|
import ts from "typescript";
|
|
7
|
-
import { truncate } from "../../utils/text.js";
|
|
7
|
+
import { generateKeyFromContext, truncate } from "../../utils/text.js";
|
|
8
8
|
/**
|
|
9
9
|
* Check conditional expression for locale-based ternary
|
|
10
10
|
*/
|
|
@@ -35,6 +35,9 @@ export function checkTernaryLocale(node, ctx) {
|
|
|
35
35
|
const text = hasStringTrue
|
|
36
36
|
? node.whenTrue.text
|
|
37
37
|
: node.whenFalse.text;
|
|
38
|
+
// Ignore empty strings (common in URL construction: locale === 'en' ? '' : locale + '/')
|
|
39
|
+
if (text.trim() === "")
|
|
40
|
+
return null;
|
|
38
41
|
const pos = ctx.sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
39
42
|
return {
|
|
40
43
|
file: ctx.filePath,
|
|
@@ -44,6 +47,7 @@ export function checkTernaryLocale(node, ctx) {
|
|
|
44
47
|
type: "ternary-locale",
|
|
45
48
|
severity: "error", // This is an anti-pattern, so error
|
|
46
49
|
message: `Locale ternary pattern detected: "${truncate(text, 30)}"`,
|
|
50
|
+
suggestedKey: generateKeyFromContext(text, ctx.filePath),
|
|
47
51
|
};
|
|
48
52
|
}
|
|
49
53
|
//# sourceMappingURL=ternary-locale.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ternary-locale.js","sourceRoot":"","sources":["../../../src/analyzer/rules/ternary-locale.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"ternary-locale.js","sourceRoot":"","sources":["../../../src/analyzer/rules/ternary-locale.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,sBAAsB,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGvE;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAA8B,EAC9B,GAAgB;IAEhB,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;IAEjC,8BAA8B;IAC9B,IAAI,CAAC,EAAE,CAAC,kBAAkB,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC;IAEnD,iCAAiC;IACjC,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC;IAC5B,IAAI,kBAAkB,GAAG,KAAK,CAAC;IAE/B,qCAAqC;IACrC,IAAI,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACpD,kBAAkB,GAAG,IAAI,CAAC;IAC5B,CAAC;IAED,kEAAkE;IAClE,IAAI,EAAE,CAAC,0BAA0B,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACvE,kBAAkB,GAAG,IAAI,CAAC;IAC5B,CAAC;IAED,IAAI,CAAC,kBAAkB;QAAE,OAAO,IAAI,CAAC;IAErC,8CAA8C;IAC9C,MAAM,aAAa,GAAG,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxD,MAAM,cAAc,GAAG,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAE1D,IAAI,CAAC,aAAa,IAAI,CAAC,cAAc;QAAE,OAAO,IAAI,CAAC;IAEnD,uBAAuB;IACvB,MAAM,IAAI,GAAG,aAAa;QACxB,CAAC,CAAE,IAAI,CAAC,QAA6B,CAAC,IAAI;QAC1C,CAAC,CAAE,IAAI,CAAC,SAA8B,CAAC,IAAI,CAAC;IAE9C,yFAAyF;IACzF,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAEpC,MAAM,GAAG,GAAG,GAAG,CAAC,UAAU,CAAC,6BAA6B,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IAE1E,OAAO;QACL,IAAI,EAAE,GAAG,CAAC,QAAQ;QAClB,IAAI,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC;QAClB,MAAM,EAAE,GAAG,CAAC,SAAS,GAAG,CAAC;QACzB,IAAI;QACJ,IAAI,EAAE,gBAAgB;QACtB,QAAQ,EAAE,OAAO,EAAE,oCAAoC;QACvD,OAAO,EAAE,qCAAqC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG;QACnE,YAAY,EAAE,sBAAsB,CAAC,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC;KACzD,CAAC;AACJ,CAAC"}
|
package/dist/analyzer/types.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/analyzer/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,GAAG,eAAe,GAAG,gBAAgB,GAAG,iBAAiB,CAAC;IAC1E,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,OAAO,YAAY,EAAE,UAAU,CAAC;CAC7C;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC1B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,GAAG,KAAK,CAAC,CAAC;IACpD,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/analyzer/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,GAAG,eAAe,GAAG,gBAAgB,GAAG,iBAAiB,CAAC;IAC1E,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,OAAO,YAAY,EAAE,UAAU,CAAC;CAC7C;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,GAAG,KAAK,CAAC,CAAC;IACpD,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAS,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAM/D,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAS,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAM/D,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA6ErE"}
|
package/dist/commands/scan.js
CHANGED
|
@@ -58,7 +58,9 @@ export async function scanCommand(options) {
|
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
60
|
else {
|
|
61
|
-
|
|
61
|
+
// Default max issues to 100 if not specified
|
|
62
|
+
const maxIssues = options.maxIssues ?? 100;
|
|
63
|
+
reportEslintStyle(allIssues, rootDir, maxIssues);
|
|
62
64
|
// Summary
|
|
63
65
|
console.log();
|
|
64
66
|
if (allIssues.length === 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAEtD,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAoB;IACpD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAG,GAAG,CAAC,EAAE,IAAI,EAAE,sBAAsB,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;IAE7E,iCAAiC;IACjC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAC7C,MAAM,OAAO,GAAG,MAAM,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAEpD,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CAAC,OAAO,CACb,YAAY,IAAI,CAAC,OAAO,CAAC,WAAW,GAAG,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC,EAAE,CACpE,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;IAC1D,CAAC;IAED,wBAAwB;IACxB,OAAO,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACrC,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC;QAC/B,OAAO;QACP,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO;QAC/B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO;KAChC,CAAC,CAAC;IAEH,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;QAC5C,OAAO;IACT,CAAC;IAED,OAAO,CAAC,OAAO,CAAC,SAAS,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC;IAE/C,wBAAwB;IACxB,OAAO,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACnD,MAAM,SAAS,GAAY,EAAE,CAAC;IAE9B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;YACtD,SAAS,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC;QAC5B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBACpB,OAAO,CAAC,KAAK,CAAC,mBAAmB,IAAI,GAAG,EAAE,KAAK,CAAC,CAAC;YACnD,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,CAAC,IAAI,EAAE,CAAC;IAEf,yBAAyB;IACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;IAExC,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC9B,UAAU,CAAC;YACT,OAAO,EAAE,OAAO,IAAI,SAAS;YAC7B,KAAK,EAAE,KAAK,CAAC,MAAM;YACnB,MAAM,EAAE,SAAS;YACjB,QAAQ;SACT,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,iBAAiB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detector.d.ts","sourceRoot":"","sources":["../../src/context/detector.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAc,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEvE;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,GAAE,MAAsB,GAC/B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"detector.d.ts","sourceRoot":"","sources":["../../src/context/detector.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAc,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEvE;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,GAAE,MAAsB,GAC/B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAqBhC"}
|
package/dist/context/detector.js
CHANGED
|
@@ -11,11 +11,18 @@ import { dirname, join } from "node:path";
|
|
|
11
11
|
*/
|
|
12
12
|
export async function detectProjectContext(startDir = process.cwd()) {
|
|
13
13
|
try {
|
|
14
|
+
// First check the startDir itself for i18n.config.ts
|
|
15
|
+
const localConfig = findConfigFile(startDir);
|
|
16
|
+
if (localConfig) {
|
|
17
|
+
return parseI18nConfig(localConfig);
|
|
18
|
+
}
|
|
19
|
+
// Then check workspace root
|
|
14
20
|
const workspaceRoot = findWorkspaceRoot(startDir);
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
21
|
+
if (workspaceRoot !== startDir) {
|
|
22
|
+
const configFile = findConfigFile(workspaceRoot);
|
|
23
|
+
if (configFile) {
|
|
24
|
+
return parseI18nConfig(configFile);
|
|
25
|
+
}
|
|
19
26
|
}
|
|
20
27
|
}
|
|
21
28
|
catch (error) {
|
|
@@ -57,14 +64,26 @@ function findWorkspaceRoot(startDir) {
|
|
|
57
64
|
/**
|
|
58
65
|
* Search for i18n config files
|
|
59
66
|
*/
|
|
60
|
-
function findConfigFile(
|
|
67
|
+
function findConfigFile(searchRoot) {
|
|
68
|
+
// First look for i18n.config.ts directly in search root
|
|
69
|
+
const directConfigs = ["i18n.config.ts", "i18n.config.js"];
|
|
70
|
+
for (const configName of directConfigs) {
|
|
71
|
+
const configPath = join(searchRoot, configName);
|
|
72
|
+
if (existsSync(configPath)) {
|
|
73
|
+
return configPath;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Then search subdirectories
|
|
61
77
|
const files = [];
|
|
78
|
+
let foundConfig = null;
|
|
62
79
|
function searchDir(dir, depth = 0) {
|
|
63
|
-
if (depth > 5)
|
|
80
|
+
if (depth > 5 || foundConfig)
|
|
64
81
|
return;
|
|
65
82
|
try {
|
|
66
83
|
const entries = readdirSync(dir);
|
|
67
84
|
for (const entry of entries) {
|
|
85
|
+
if (foundConfig)
|
|
86
|
+
return;
|
|
68
87
|
if (["node_modules", ".git", "dist", "build", ".next"].includes(entry)) {
|
|
69
88
|
continue;
|
|
70
89
|
}
|
|
@@ -74,8 +93,8 @@ function findConfigFile(workspaceRoot) {
|
|
|
74
93
|
searchDir(fullPath, depth + 1);
|
|
75
94
|
}
|
|
76
95
|
else if (/i18n\.config\.(ts|js)$/.test(entry)) {
|
|
77
|
-
|
|
78
|
-
return
|
|
96
|
+
foundConfig = fullPath;
|
|
97
|
+
return;
|
|
79
98
|
}
|
|
80
99
|
else if (/\.(ts|tsx|js|jsx)$/.test(entry)) {
|
|
81
100
|
files.push(fullPath);
|
|
@@ -86,17 +105,11 @@ function findConfigFile(workspaceRoot) {
|
|
|
86
105
|
// Ignore permission errors
|
|
87
106
|
}
|
|
88
107
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const configPath = join(workspaceRoot, configName);
|
|
93
|
-
if (existsSync(configPath)) {
|
|
94
|
-
return configPath;
|
|
95
|
-
}
|
|
108
|
+
searchDir(searchRoot);
|
|
109
|
+
if (foundConfig) {
|
|
110
|
+
return foundConfig;
|
|
96
111
|
}
|
|
97
|
-
//
|
|
98
|
-
searchDir(workspaceRoot);
|
|
99
|
-
// Search for createI18n import
|
|
112
|
+
// Search for createI18n import as fallback
|
|
100
113
|
for (const file of files) {
|
|
101
114
|
try {
|
|
102
115
|
const content = readFileSync(file, "utf-8");
|
|
@@ -116,13 +129,27 @@ function findConfigFile(workspaceRoot) {
|
|
|
116
129
|
*/
|
|
117
130
|
function parseI18nConfig(filePath) {
|
|
118
131
|
const content = readFileSync(filePath, "utf-8");
|
|
119
|
-
// Try project
|
|
132
|
+
// Try project = "org/slug" format (exported const)
|
|
133
|
+
const projectConstMatch = content.match(/(?:export\s+)?const\s+project\s*=\s*['"]([^'"]+\/[^'"]+)['"]/);
|
|
134
|
+
if (projectConstMatch) {
|
|
135
|
+
const [workspaceId, projectSlug] = projectConstMatch[1].split("/");
|
|
136
|
+
const localeMatch = content.match(/defaultLocale[:\s]*['"]([^'"]+)['"]/);
|
|
137
|
+
const cdnMatch = content.match(/cdnBaseUrl[:\s]*['"]([^'"]+)['"]/);
|
|
138
|
+
const lint = parseLintConfig(content);
|
|
139
|
+
return {
|
|
140
|
+
workspaceId,
|
|
141
|
+
projectSlug,
|
|
142
|
+
defaultLocale: localeMatch?.[1] || "en",
|
|
143
|
+
cdnBaseUrl: cdnMatch?.[1],
|
|
144
|
+
lint,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
// Try project: "org/slug" format (object property)
|
|
120
148
|
const projectMatch = content.match(/project:\s*['"]([^'"]+\/[^'"]+)['"]/);
|
|
121
149
|
if (projectMatch) {
|
|
122
150
|
const [workspaceId, projectSlug] = projectMatch[1].split("/");
|
|
123
151
|
const localeMatch = content.match(/defaultLocale:\s*['"]([^'"]+)['"]/);
|
|
124
152
|
const cdnMatch = content.match(/cdnBaseUrl:\s*['"]([^'"]+)['"]/);
|
|
125
|
-
// Try to parse lint config
|
|
126
153
|
const lint = parseLintConfig(content);
|
|
127
154
|
return {
|
|
128
155
|
workspaceId,
|
|
@@ -153,9 +180,7 @@ function parseI18nConfig(filePath) {
|
|
|
153
180
|
* Parse optional lint config from file content
|
|
154
181
|
*/
|
|
155
182
|
function parseLintConfig(content) {
|
|
156
|
-
|
|
157
|
-
// In real implementation, could use AST parsing
|
|
158
|
-
if (!content.includes("lint:")) {
|
|
183
|
+
if (!content.includes("lint:") && !content.includes("lint =")) {
|
|
159
184
|
return undefined;
|
|
160
185
|
}
|
|
161
186
|
const config = {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detector.js","sourceRoot":"","sources":["../../src/context/detector.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAG1C;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,WAAmB,OAAO,CAAC,GAAG,EAAE;IAEhC,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"detector.js","sourceRoot":"","sources":["../../src/context/detector.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -10,12 +10,13 @@ import { scanCommand } from "./commands/scan.js";
|
|
|
10
10
|
program
|
|
11
11
|
.name("better-i18n")
|
|
12
12
|
.description("Detect hardcoded strings in your React/Next.js app")
|
|
13
|
-
.version("0.1.
|
|
13
|
+
.version("0.1.1");
|
|
14
14
|
program
|
|
15
15
|
.command("scan")
|
|
16
16
|
.description("Scan source files for untranslated strings")
|
|
17
17
|
.option("-d, --dir <path>", "Directory to scan (default: current directory)")
|
|
18
18
|
.option("-f, --format <type>", "Output format: eslint, json", "eslint")
|
|
19
|
+
.option("--max-issues <number>", "Maximum number of issues to display (default: 100)", parseInt)
|
|
19
20
|
.option("--fix", "Auto-fix: wrap hardcoded text with t()")
|
|
20
21
|
.option("--ci", "CI mode: exit with error code if issues found")
|
|
21
22
|
.option("--staged", "Only scan git staged files")
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,OAAO;KACJ,IAAI,CAAC,aAAa,CAAC;KACnB,WAAW,CAAC,oDAAoD,CAAC;KACjE,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,4CAA4C,CAAC;KACzD,MAAM,CAAC,kBAAkB,EAAE,gDAAgD,CAAC;KAC5E,MAAM,CAAC,qBAAqB,EAAE,6BAA6B,EAAE,QAAQ,CAAC;KACtE,MAAM,CAAC,OAAO,EAAE,wCAAwC,CAAC;KACzD,MAAM,CAAC,MAAM,EAAE,+CAA+C,CAAC;KAC/D,MAAM,CAAC,UAAU,EAAE,4BAA4B,CAAC;KAChD,MAAM,CAAC,WAAW,EAAE,sBAAsB,CAAC;KAC3C,MAAM,CAAC,WAAW,CAAC,CAAC;AAEvB,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,OAAO;KACJ,IAAI,CAAC,aAAa,CAAC;KACnB,WAAW,CAAC,oDAAoD,CAAC;KACjE,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,4CAA4C,CAAC;KACzD,MAAM,CAAC,kBAAkB,EAAE,gDAAgD,CAAC;KAC5E,MAAM,CAAC,qBAAqB,EAAE,6BAA6B,EAAE,QAAQ,CAAC;KACtE,MAAM,CACL,uBAAuB,EACvB,oDAAoD,EACpD,QAAQ,CACT;KACA,MAAM,CAAC,OAAO,EAAE,wCAAwC,CAAC;KACzD,MAAM,CAAC,MAAM,EAAE,+CAA+C,CAAC;KAC/D,MAAM,CAAC,UAAU,EAAE,4BAA4B,CAAC;KAChD,MAAM,CAAC,WAAW,EAAE,sBAAsB,CAAC;KAC3C,MAAM,CAAC,WAAW,CAAC,CAAC;AAEvB,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ESLint-style terminal reporter
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* VS Code terminal auto-detects "path:line:column" format and makes it Cmd+clickable
|
|
5
5
|
*/
|
|
6
6
|
import type { Issue } from "../analyzer/types.js";
|
|
7
7
|
/**
|
|
8
8
|
* Report issues in ESLint-style format
|
|
9
9
|
*/
|
|
10
|
-
export declare function reportEslintStyle(issues: Issue[], rootDir: string): void;
|
|
10
|
+
export declare function reportEslintStyle(issues: Issue[], rootDir: string, maxIssues?: number): void;
|
|
11
11
|
//# sourceMappingURL=eslint-style.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eslint-style.d.ts","sourceRoot":"","sources":["../../src/reporters/eslint-style.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"eslint-style.d.ts","sourceRoot":"","sources":["../../src/reporters/eslint-style.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAGlD;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,KAAK,EAAE,EACf,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,GACjB,IAAI,CA4EN"}
|
|
@@ -1,52 +1,66 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ESLint-style terminal reporter
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* VS Code terminal auto-detects "path:line:column" format and makes it Cmd+clickable
|
|
5
5
|
*/
|
|
6
6
|
import { relative } from "node:path";
|
|
7
|
-
import { bold, dim, red,
|
|
7
|
+
import { bold, cyan, dim, red, yellow } from "../utils/colors.js";
|
|
8
8
|
/**
|
|
9
9
|
* Report issues in ESLint-style format
|
|
10
10
|
*/
|
|
11
|
-
export function reportEslintStyle(issues, rootDir) {
|
|
11
|
+
export function reportEslintStyle(issues, rootDir, maxIssues) {
|
|
12
12
|
if (issues.length === 0)
|
|
13
13
|
return;
|
|
14
|
+
const totalIssues = issues.length;
|
|
15
|
+
const displayIssues = maxIssues ? issues.slice(0, maxIssues) : issues;
|
|
16
|
+
const hasMore = maxIssues && totalIssues > maxIssues;
|
|
14
17
|
// Group by file
|
|
15
18
|
const byFile = new Map();
|
|
16
|
-
for (const issue of
|
|
19
|
+
for (const issue of displayIssues) {
|
|
17
20
|
const existing = byFile.get(issue.file) || [];
|
|
18
21
|
existing.push(issue);
|
|
19
22
|
byFile.set(issue.file, existing);
|
|
20
23
|
}
|
|
21
24
|
let errorCount = 0;
|
|
22
|
-
let
|
|
23
|
-
// Print each file
|
|
25
|
+
let missingCount = 0;
|
|
26
|
+
// Print each file's issues grouped by file
|
|
24
27
|
for (const [file, fileIssues] of byFile.entries()) {
|
|
25
28
|
const relPath = relative(rootDir, file);
|
|
26
29
|
console.log();
|
|
27
|
-
|
|
30
|
+
// File header: blue filename + issue count
|
|
31
|
+
const count = dim(`(${fileIssues.length})`);
|
|
32
|
+
console.log(`${cyan(relPath)} ${count}`);
|
|
28
33
|
for (const issue of fileIssues) {
|
|
34
|
+
// Format: " line:col severity message rule"
|
|
35
|
+
// Full path clickable: relPath:line:col
|
|
29
36
|
const loc = dim(`${issue.line}:${issue.column}`);
|
|
30
|
-
const severity = issue.severity === "error" ? red("error") : yellow("
|
|
37
|
+
const severity = issue.severity === "error" ? red("error") : yellow("missing");
|
|
38
|
+
const text = truncateForDisplay(issue.text, 40);
|
|
31
39
|
const rule = dim(`i18n/${issue.type}`);
|
|
32
|
-
const text = truncateForDisplay(issue.text, 50);
|
|
33
40
|
console.log(` ${loc} ${severity} ${text} ${rule}`);
|
|
34
41
|
if (issue.severity === "error") {
|
|
35
42
|
errorCount++;
|
|
36
43
|
}
|
|
37
44
|
else {
|
|
38
|
-
|
|
45
|
+
missingCount++;
|
|
39
46
|
}
|
|
40
47
|
}
|
|
41
48
|
}
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
|
|
49
|
+
// Show "and X more" message if truncated
|
|
50
|
+
if (hasMore) {
|
|
51
|
+
const remaining = totalIssues - maxIssues;
|
|
52
|
+
console.log();
|
|
53
|
+
console.log(dim(`... and ${remaining} more problem${remaining > 1 ? "s" : ""}`));
|
|
54
|
+
}
|
|
55
|
+
// Summary - use total counts, not just displayed
|
|
56
|
+
const totalErrorCount = issues.filter((i) => i.severity === "error").length;
|
|
57
|
+
const totalMissingCount = issues.filter((i) => i.severity === "warning").length;
|
|
58
|
+
const total = totalErrorCount + totalMissingCount;
|
|
45
59
|
const summary = [];
|
|
46
|
-
if (
|
|
47
|
-
summary.push(red(`${
|
|
48
|
-
if (
|
|
49
|
-
summary.push(yellow(`${
|
|
60
|
+
if (totalErrorCount > 0)
|
|
61
|
+
summary.push(red(`${totalErrorCount} error${totalErrorCount > 1 ? "s" : ""}`));
|
|
62
|
+
if (totalMissingCount > 0)
|
|
63
|
+
summary.push(yellow(`${totalMissingCount} missing translation${totalMissingCount > 1 ? "s" : ""}`));
|
|
50
64
|
console.log(bold(`✖ ${total} problem${total > 1 ? "s" : ""} (${summary.join(", ")})`));
|
|
51
65
|
}
|
|
52
66
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eslint-style.js","sourceRoot":"","sources":["../../src/reporters/eslint-style.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,
|
|
1
|
+
{"version":3,"file":"eslint-style.js","sourceRoot":"","sources":["../../src/reporters/eslint-style.ts"],"names":[],"mappings":"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"}
|