@windagency/valora-plugin-compression-typescript 1.0.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/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # @windagency/valora-plugin-compression-typescript
2
+
3
+ Output-compression strategies for the TypeScript / JavaScript ecosystem.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ valora plugin add compression-typescript
9
+ ```
10
+
11
+ Depends on `valora-plugin-compression-universal` (declared via `requires`).
12
+
13
+ ## What it contributes
14
+
15
+ Registers 12 compression strategies via `api.compression.registerStrategy`: `tsc`, `eslint`, `jest`, `vitest`, `pnpm`, `npm`, `npx`, `yarn`, `prettier`, `bun`, `bunx`, `biome`.
16
+
17
+ Each strategy is a pure string-transform that strips redundant lines (e.g. tsc's repeated file paths, eslint's per-rule headers) before output is added to the LLM context.
18
+
19
+ ## Permissions
20
+
21
+ `code-exec` — required by the loader to register a `code` contribution.
22
+
23
+ ## See also
24
+
25
+ - [Plugins user guide](../../documentation/user-guide/plugins.md)
26
+ - [Writing plugins](../../documentation/developer-guide/writing-plugins.md)
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ import { filterBiome, filterEslint, filterPackageManager, filterPrettier, filterTestRunner, filterTsc } from './strategies.js';
2
+ export function register(api) {
3
+ api.compression.registerStrategy('tsc', filterTsc);
4
+ api.compression.registerStrategy('eslint', filterEslint);
5
+ api.compression.registerStrategy('jest', filterTestRunner);
6
+ api.compression.registerStrategy('vitest', filterTestRunner);
7
+ api.compression.registerStrategy('pnpm', filterPackageManager);
8
+ api.compression.registerStrategy('npm', filterPackageManager);
9
+ api.compression.registerStrategy('npx', filterPackageManager);
10
+ api.compression.registerStrategy('yarn', filterPackageManager);
11
+ api.compression.registerStrategy('prettier', filterPrettier);
12
+ api.compression.registerStrategy('bun', filterPackageManager);
13
+ api.compression.registerStrategy('bunx', filterPackageManager);
14
+ api.compression.registerStrategy('biome', filterBiome);
15
+ }
@@ -0,0 +1,264 @@
1
+ const TSC_MAX_EXAMPLES_PER_CODE = 3;
2
+ const ESLINT_MAX_EXAMPLES_PER_RULE = 2;
3
+ const BIOME_MAX_EXAMPLES_PER_RULE = 2;
4
+ export function filterBiome(output, _command) {
5
+ const lines = output.split('\n');
6
+ const byRule = new Map();
7
+ const other = [];
8
+ let inBlock = false;
9
+ for (const line of lines) {
10
+ if (addBiomeViolation(byRule, line)) {
11
+ inBlock = true;
12
+ continue;
13
+ }
14
+ if (inBlock) {
15
+ if (line && !/^\s/.test(line)) {
16
+ inBlock = false;
17
+ other.push(line);
18
+ }
19
+ continue;
20
+ }
21
+ other.push(line);
22
+ }
23
+ return [...other, ...[...byRule.values()].flat()].join('\n');
24
+ }
25
+ export function filterEslint(output, _command) {
26
+ const lines = output.split('\n');
27
+ const byRule = new Map();
28
+ const other = [];
29
+ for (const line of lines) {
30
+ const match = line.match(/^\s+\d+:\d+\s+(error|warning)\s+(\S+)/);
31
+ if (match) {
32
+ const rule = match[2] ?? '';
33
+ const bucket = byRule.get(rule);
34
+ if (!bucket) {
35
+ byRule.set(rule, [line]);
36
+ }
37
+ else if (bucket.length < ESLINT_MAX_EXAMPLES_PER_RULE) {
38
+ bucket.push(line);
39
+ }
40
+ else if (bucket.length === ESLINT_MAX_EXAMPLES_PER_RULE) {
41
+ bucket.push(` ... (more ${rule} violations)`);
42
+ }
43
+ }
44
+ else {
45
+ other.push(line);
46
+ }
47
+ }
48
+ return [...other, ...[...byRule.values()].flat()].join('\n');
49
+ }
50
+ export function filterPackageManager(output, _command) {
51
+ const lines = output.split('\n');
52
+ const result = [];
53
+ let addedCount = 0;
54
+ const flushAdded = () => {
55
+ if (addedCount > 0) {
56
+ result.push(`[${addedCount} packages added]`);
57
+ addedCount = 0;
58
+ }
59
+ };
60
+ for (const line of lines) {
61
+ if (isPackageManagerNoise(line))
62
+ continue;
63
+ if (/^\+ \S+@\S+/.test(line)) {
64
+ addedCount++;
65
+ continue;
66
+ }
67
+ flushAdded();
68
+ result.push(line);
69
+ }
70
+ flushAdded();
71
+ return result.join('\n');
72
+ }
73
+ export function filterPrettier(output, _command) {
74
+ return output
75
+ .split('\n')
76
+ .filter((line) => !/^Checking formatting\.\.\./.test(line))
77
+ .join('\n');
78
+ }
79
+ export function filterTestRunner(output, _command) {
80
+ const lines = collapseCoverageTables(output.split('\n'));
81
+ const kept = [];
82
+ let passCount = 0;
83
+ const flushPassCount = () => {
84
+ if (passCount > 0) {
85
+ kept.push(`[${passCount} test suite${passCount === 1 ? '' : 's'} passed]`);
86
+ passCount = 0;
87
+ }
88
+ };
89
+ for (const line of lines) {
90
+ const isPassLine = /^\s*(✓|PASS\b|passed\b)/.test(line);
91
+ const isFailLine = /^\s*(✗|✕|FAIL\b|×)/.test(line);
92
+ const isSummaryLine = /^(Tests?|Test Files?|Suites?|Duration|Time|Ran all)/.test(line);
93
+ if (isFailLine) {
94
+ flushPassCount();
95
+ kept.push(line);
96
+ }
97
+ else if (isPassLine) {
98
+ passCount++;
99
+ }
100
+ else if (isSummaryLine) {
101
+ flushPassCount();
102
+ kept.push(line);
103
+ }
104
+ else {
105
+ kept.push(line);
106
+ }
107
+ }
108
+ flushPassCount();
109
+ return kept.join('\n');
110
+ }
111
+ export function filterTsc(output, _command) {
112
+ let lines = output.split('\n');
113
+ if (lines.some((l) => /^\[\d+:\d+:\d+ [AP]M\]/.test(l)))
114
+ lines = extractLastWatchCycle(lines);
115
+ if (lines.some((l) => /^={8} Resolving module /.test(l)))
116
+ lines = foldTraceResolution(lines);
117
+ const errorsByCode = new Map();
118
+ const other = [];
119
+ for (const line of lines) {
120
+ if (isCodeFrameLine(line))
121
+ continue;
122
+ const match = line.match(/: (error|warning) (TS\d+):/);
123
+ if (match) {
124
+ const code = match[2] ?? '';
125
+ const bucket = errorsByCode.get(code);
126
+ if (!bucket) {
127
+ errorsByCode.set(code, [line]);
128
+ }
129
+ else if (bucket.length < TSC_MAX_EXAMPLES_PER_CODE) {
130
+ bucket.push(line);
131
+ }
132
+ else if (bucket.length === TSC_MAX_EXAMPLES_PER_CODE) {
133
+ bucket.push(` ... (more ${code} errors)`);
134
+ }
135
+ }
136
+ else {
137
+ other.push(line);
138
+ }
139
+ }
140
+ return [...other, ...[...errorsByCode.values()].flat()].join('\n');
141
+ }
142
+ function addBiomeViolation(byRule, line) {
143
+ const m = line.match(/^(\S+:\d+:\d+)\s+(\S+)\s+━/);
144
+ if (!m)
145
+ return false;
146
+ const rule = m[2] ?? '';
147
+ const ruleShort = rule.split('/').pop() ?? rule;
148
+ const entry = `${m[1]} ${rule}`;
149
+ const bucket = byRule.get(ruleShort);
150
+ if (!bucket) {
151
+ byRule.set(ruleShort, [entry]);
152
+ }
153
+ else if (bucket.length < BIOME_MAX_EXAMPLES_PER_RULE) {
154
+ bucket.push(entry);
155
+ }
156
+ else if (bucket.length === BIOME_MAX_EXAMPLES_PER_RULE) {
157
+ bucket.push(` ... (more ${ruleShort} violations)`);
158
+ }
159
+ return true;
160
+ }
161
+ function collapseCoverageTables(lines) {
162
+ const result = [];
163
+ let fileCount = 0;
164
+ let overall = '';
165
+ let inTable = false;
166
+ const flushTable = () => {
167
+ result.push(`[coverage: ${fileCount} files, overall ${overall}%]`);
168
+ fileCount = 0;
169
+ overall = '';
170
+ inTable = false;
171
+ };
172
+ for (const line of lines) {
173
+ if (/^\s*%\s*Coverage report/.test(line)) {
174
+ inTable = true;
175
+ continue;
176
+ }
177
+ if (!inTable) {
178
+ result.push(line);
179
+ continue;
180
+ }
181
+ if (isCoverageTableNoiseLine(line))
182
+ continue;
183
+ const allFilesMatch = line.match(/^All files\s*\|\s*([\d.]+)/);
184
+ if (allFilesMatch) {
185
+ overall = allFilesMatch[1] ?? '';
186
+ continue;
187
+ }
188
+ if (/^\s+\S/.test(line) && line.includes('|')) {
189
+ fileCount++;
190
+ continue;
191
+ }
192
+ flushTable();
193
+ result.push(line);
194
+ }
195
+ if (inTable)
196
+ flushTable();
197
+ return result;
198
+ }
199
+ function extractLastWatchCycle(lines) {
200
+ const MARKER = /^\[\d+:\d+:\d+ [AP]M\] (Starting compilation in watch mode|File change detected)/;
201
+ let lastIdx = -1;
202
+ for (let i = lines.length - 1; i >= 0; i--) {
203
+ if (MARKER.test(lines[i] ?? '')) {
204
+ lastIdx = i;
205
+ break;
206
+ }
207
+ }
208
+ return lastIdx >= 0 ? lines.slice(lastIdx) : lines;
209
+ }
210
+ function foldTraceResolution(lines) {
211
+ const result = [];
212
+ let inBlock = false;
213
+ for (const line of lines) {
214
+ if (/^={8} Resolving module /.test(line)) {
215
+ inBlock = true;
216
+ continue;
217
+ }
218
+ if (/^={8} Module name /.test(line)) {
219
+ result.push(line);
220
+ inBlock = false;
221
+ continue;
222
+ }
223
+ if (!inBlock)
224
+ result.push(line);
225
+ }
226
+ return result;
227
+ }
228
+ function isCodeFrameLine(line) {
229
+ if (/^\s*\d+\s/.test(line))
230
+ return true;
231
+ if (/^\s*[~^]+\s*$/.test(line))
232
+ return true;
233
+ return false;
234
+ }
235
+ function isCoverageTableNoiseLine(line) {
236
+ if (/^-+\|/.test(line))
237
+ return true;
238
+ if (/^-+/.test(line.trim()))
239
+ return true;
240
+ if (/File\s+\|/.test(line))
241
+ return true;
242
+ return false;
243
+ }
244
+ function isPackageManagerNoise(line) {
245
+ if (/^[⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏]/.test(line))
246
+ return true;
247
+ if (/^Progress:/.test(line))
248
+ return true;
249
+ if (/^npm warn/i.test(line))
250
+ return true;
251
+ if (/^warning /i.test(line))
252
+ return true;
253
+ if (/^warning ".+ >/.test(line))
254
+ return true;
255
+ if (/^found \d+ vulnerabilit/i.test(line))
256
+ return true;
257
+ if (/^npm notice/i.test(line))
258
+ return true;
259
+ if (/\d+\s+packages?\s+are?\s+looking\s+for\s+funding/i.test(line))
260
+ return true;
261
+ if (/npm\s+fund/i.test(line))
262
+ return true;
263
+ return false;
264
+ }
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@windagency/valora-plugin-compression-typescript",
3
+ "version": "1.0.0",
4
+ "description": "Compression strategies for the TypeScript/JavaScript ecosystem: tsc, eslint, jest, vitest, pnpm, npm, npx, yarn.",
5
+ "keywords": [
6
+ "valora",
7
+ "valora-plugin",
8
+ "compression",
9
+ "typescript",
10
+ "eslint",
11
+ "vitest",
12
+ "jest"
13
+ ],
14
+ "author": "Damien TIVELET <damien@wind-agency.com>",
15
+ "license": "MIT",
16
+ "type": "module",
17
+ "engines": {
18
+ "node": ">=22.0.0"
19
+ },
20
+ "volta": {
21
+ "node": "22.21.0",
22
+ "pnpm": "10.19.0"
23
+ },
24
+ "files": [
25
+ "valora-plugin.json",
26
+ "dist"
27
+ ],
28
+ "peerDependencies": {
29
+ "@windagency/valora": ">=0.1.0"
30
+ },
31
+ "devDependencies": {
32
+ "vitest": "^1.0.0",
33
+ "@windagency/valora-plugin-api": "1.0.0"
34
+ },
35
+ "scripts": {
36
+ "build": "tsc -p tsconfig.json",
37
+ "clean": "rm -rf ./dist",
38
+ "lint": "eslint --color",
39
+ "lint:fix": "eslint --color --fix",
40
+ "beautify": "prettier --check \"**/*.+(js|jsx|ts|tsx|json|md|yml|yaml)\"",
41
+ "beautify:fix": "prettier --write \"**/*.+(js|jsx|ts|tsx|json|md|yml|yaml)\"",
42
+ "format": "pnpm beautify:fix && pnpm lint:fix",
43
+ "test": "vitest run"
44
+ }
45
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "valora-plugin-compression-typescript",
3
+ "version": "1.0.0",
4
+ "description": "Compression strategies for the TypeScript/JavaScript ecosystem: tsc, eslint, jest, vitest, pnpm, npm, npx, yarn, prettier, bun, bunx, biome (12 strategies).",
5
+ "engines": { "valora": ">=0.1.0" },
6
+ "contributes": ["code"],
7
+ "permissions": ["code-exec"],
8
+ "requires": ["valora-plugin-compression-universal"],
9
+ "codeEntrypoint": "dist/index.js"
10
+ }