mejora 2.3.2 → 2.3.4
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/dist/check-registry-DHd4j450.mjs +1 -0
- package/dist/index-Dr3lmWeD.d.mts +428 -0
- package/dist/index.d.mts +2 -430
- package/dist/index.mjs +1 -1
- package/dist/run.mjs +22 -22
- package/dist/{typescript-C0a92mCs.mjs → typescript-sQ82Cu7A.mjs} +1 -1
- package/dist/workers/check.d.mts +13 -0
- package/dist/workers/check.mjs +1 -0
- package/package.json +4 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as e,t}from"./typescript-sQ82Cu7A.mjs";var n=class{runners=new Map;static getRequiredTypes(e){return new Set(Object.values(e).map(e=>e.type))}get(e){let t=this.runners.get(e);if(!t)throw Error(`Unknown check type: ${e}`);return t}getTypes(){return new Set(this.runners.keys())}has(e){return this.runners.has(e)}init(n={}){if(this.register(new e),this.register(new t),n.runners)for(let e of n.runners)this.register(e)}register(e){if(this.runners.has(e.type))throw Error(`Check runner already registered: ${e.type}`);this.runners.set(e.type,e)}async setup(e){await this.runLifecycle(e,`setup`)}async validate(e){await this.runLifecycle(e,`validate`)}async runLifecycle(e,t){let n=[];for(let r of e){let e=this.get(r)[t]?.();e&&n.push(e)}await Promise.all(n)}};export{n as t};
|
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
import * as eslint0 from "eslint";
|
|
2
|
+
import { Linter } from "eslint";
|
|
3
|
+
import * as typescript0 from "typescript";
|
|
4
|
+
import { CompilerOptions } from "typescript";
|
|
5
|
+
|
|
6
|
+
//#region src/types.d.ts
|
|
7
|
+
interface Issue {
|
|
8
|
+
/**
|
|
9
|
+
* 1-indexed column number for display.
|
|
10
|
+
*/
|
|
11
|
+
column: number;
|
|
12
|
+
/**
|
|
13
|
+
* Relative path from cwd.
|
|
14
|
+
*/
|
|
15
|
+
file: string;
|
|
16
|
+
/**
|
|
17
|
+
* Hash of canonical representation.
|
|
18
|
+
*
|
|
19
|
+
* @example "a1b2c3d4e5f6g7h8i9j0"
|
|
20
|
+
*/
|
|
21
|
+
id: string;
|
|
22
|
+
/**
|
|
23
|
+
* 1-indexed line number for display.
|
|
24
|
+
*/
|
|
25
|
+
line: number;
|
|
26
|
+
/**
|
|
27
|
+
* The message.
|
|
28
|
+
*/
|
|
29
|
+
message: string;
|
|
30
|
+
/**
|
|
31
|
+
* Identifier for the issue (rule name, diagnostic code, etc).
|
|
32
|
+
*
|
|
33
|
+
* @example "no-nested-ternary" (ESLint)
|
|
34
|
+
*
|
|
35
|
+
* @example "TS2345" (TypeScript)
|
|
36
|
+
*/
|
|
37
|
+
rule: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Issue produced by a check runner.
|
|
41
|
+
*/
|
|
42
|
+
type IssueInput = Omit<Issue, "id">;
|
|
43
|
+
type SnapshotType = "items";
|
|
44
|
+
interface RawSnapshot {
|
|
45
|
+
/**
|
|
46
|
+
* Snapshot items (each item represents an issue produced by the check).
|
|
47
|
+
*/
|
|
48
|
+
items: IssueInput[];
|
|
49
|
+
type: SnapshotType;
|
|
50
|
+
}
|
|
51
|
+
interface Snapshot {
|
|
52
|
+
items: Issue[];
|
|
53
|
+
type: SnapshotType;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Configuration for an ESLint check.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```ts
|
|
60
|
+
* eslint({
|
|
61
|
+
* files: ["src/**\/*.{ts,tsx}"],
|
|
62
|
+
* overrides: {
|
|
63
|
+
* rules: {
|
|
64
|
+
* "no-nested-ternary": "error",
|
|
65
|
+
* },
|
|
66
|
+
* },
|
|
67
|
+
* })
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
interface ESLintCheckConfig {
|
|
71
|
+
/**
|
|
72
|
+
* Concurrency setting for ESLint.
|
|
73
|
+
*
|
|
74
|
+
* @see https://eslint.org/blog/2025/08/multithread-linting/#cli-multithreading-support
|
|
75
|
+
*
|
|
76
|
+
* @default "auto"
|
|
77
|
+
*/
|
|
78
|
+
concurrency?: "auto" | "off" | number;
|
|
79
|
+
/**
|
|
80
|
+
* Glob patterns for files to lint.
|
|
81
|
+
*
|
|
82
|
+
* Passed directly to ESLint's `lintFiles()` method.
|
|
83
|
+
*
|
|
84
|
+
* @example ["src/**\/*.ts", "src/**\/*.tsx"]
|
|
85
|
+
*/
|
|
86
|
+
files: string[];
|
|
87
|
+
/**
|
|
88
|
+
* ESLint configuration to merge with the base config.
|
|
89
|
+
*
|
|
90
|
+
* This is passed to ESLint's `overrideConfig` option and merged with
|
|
91
|
+
* your existing ESLint configuration.
|
|
92
|
+
*
|
|
93
|
+
* Can be a single config object or an array of config objects.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```ts
|
|
97
|
+
* {
|
|
98
|
+
* rules: {
|
|
99
|
+
* "no-console": "error",
|
|
100
|
+
* },
|
|
101
|
+
* }
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
overrides?: Linter.Config | Linter.Config[];
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Configuration for a TypeScript diagnostics check.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```ts
|
|
111
|
+
* typescript({
|
|
112
|
+
* overrides: {
|
|
113
|
+
* compilerOptions: {
|
|
114
|
+
* noImplicitAny: true,
|
|
115
|
+
* },
|
|
116
|
+
* },
|
|
117
|
+
* })
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
interface TypeScriptCheckConfig {
|
|
121
|
+
/**
|
|
122
|
+
* Compiler options to merge with the base tsconfig.
|
|
123
|
+
*
|
|
124
|
+
* These options are merged with (not replacing) the compiler options
|
|
125
|
+
* from your tsconfig file.
|
|
126
|
+
*/
|
|
127
|
+
overrides?: {
|
|
128
|
+
compilerOptions?: CompilerOptions;
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* Path to a TypeScript config file.
|
|
132
|
+
*
|
|
133
|
+
* If not provided, mejora will search for the nearest `tsconfig.json`
|
|
134
|
+
* starting from the current working directory.
|
|
135
|
+
*
|
|
136
|
+
* @example "tsconfig.strict.json"
|
|
137
|
+
*/
|
|
138
|
+
tsconfig?: string;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* A regex pattern configuration.
|
|
142
|
+
*/
|
|
143
|
+
interface RegexPattern {
|
|
144
|
+
/**
|
|
145
|
+
* Human-readable message for matches.
|
|
146
|
+
*
|
|
147
|
+
* @example "TODO comment found"
|
|
148
|
+
*
|
|
149
|
+
* @example "console.log statement"
|
|
150
|
+
*
|
|
151
|
+
* @example (match) => `Found TODO at line ${match.index + 1}`
|
|
152
|
+
*/
|
|
153
|
+
message?: ((match: RegExpExecArray) => string) | string;
|
|
154
|
+
/**
|
|
155
|
+
* The regex pattern to match.
|
|
156
|
+
*
|
|
157
|
+
* @example /\/\/\s*TODO:/gi
|
|
158
|
+
*
|
|
159
|
+
* @example /console\.log/g
|
|
160
|
+
*/
|
|
161
|
+
pattern: RegExp;
|
|
162
|
+
/**
|
|
163
|
+
* Rule identifier for this pattern.
|
|
164
|
+
* If not provided, uses the pattern source as the rule ID.
|
|
165
|
+
*
|
|
166
|
+
* @example "no-todos"
|
|
167
|
+
*
|
|
168
|
+
* @example "no-console-log"
|
|
169
|
+
*/
|
|
170
|
+
rule?: string;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Configuration for regex pattern matching check.
|
|
174
|
+
*/
|
|
175
|
+
interface RegexCheckConfig {
|
|
176
|
+
/**
|
|
177
|
+
* Concurrency for processing files.
|
|
178
|
+
*
|
|
179
|
+
* @default 10
|
|
180
|
+
*/
|
|
181
|
+
concurrency?: number;
|
|
182
|
+
/**
|
|
183
|
+
* Array of glob patterns for files to check.
|
|
184
|
+
*
|
|
185
|
+
* @example ["src/**\/*.ts", "lib/**\/*.js"]
|
|
186
|
+
*/
|
|
187
|
+
files: string[];
|
|
188
|
+
/**
|
|
189
|
+
* Array of glob patterns to ignore.
|
|
190
|
+
*
|
|
191
|
+
* @default ["**\/node_modules/**", "**\/dist/**", "**\/.git/**"]
|
|
192
|
+
*/
|
|
193
|
+
ignore?: string[];
|
|
194
|
+
/**
|
|
195
|
+
* Array of regex patterns to match.
|
|
196
|
+
*/
|
|
197
|
+
patterns: RegexPattern[];
|
|
198
|
+
}
|
|
199
|
+
type CustomCheckConfig = Record<string, unknown> & {
|
|
200
|
+
type: string;
|
|
201
|
+
};
|
|
202
|
+
type CheckConfig$1 = (ESLintCheckConfig & {
|
|
203
|
+
type: "eslint";
|
|
204
|
+
}) | (TypeScriptCheckConfig & {
|
|
205
|
+
type: "typescript";
|
|
206
|
+
}) | CustomCheckConfig;
|
|
207
|
+
/**
|
|
208
|
+
* mejora configuration.
|
|
209
|
+
*
|
|
210
|
+
* Define checks to run and track for regressions.
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```ts
|
|
214
|
+
* import { defineConfig, eslint, typescript } from "mejora";
|
|
215
|
+
*
|
|
216
|
+
* export default defineConfig({
|
|
217
|
+
* checks: {
|
|
218
|
+
* "eslint > no-nested-ternary": eslint({
|
|
219
|
+
* files: ["src/**\/*.{ts,tsx}"],
|
|
220
|
+
* overrides: {
|
|
221
|
+
* rules: {
|
|
222
|
+
* "no-nested-ternary": "error",
|
|
223
|
+
* },
|
|
224
|
+
* },
|
|
225
|
+
* }),
|
|
226
|
+
* "typescript": typescript({
|
|
227
|
+
* overrides: {
|
|
228
|
+
* compilerOptions: {
|
|
229
|
+
* noImplicitAny: true,
|
|
230
|
+
* },
|
|
231
|
+
* },
|
|
232
|
+
* }),
|
|
233
|
+
* },
|
|
234
|
+
* });
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
interface Config {
|
|
238
|
+
/**
|
|
239
|
+
* Check definitions.
|
|
240
|
+
*
|
|
241
|
+
* Each key is a check identifier used in the baseline and output.
|
|
242
|
+
* The identifier can contain any characters.
|
|
243
|
+
*
|
|
244
|
+
* Use `eslint()` and `typescript()` helpers to create check configs.
|
|
245
|
+
*
|
|
246
|
+
* @example
|
|
247
|
+
* ```ts
|
|
248
|
+
* {
|
|
249
|
+
* "eslint > no-console": eslint({ ... }),
|
|
250
|
+
* "typescript": typescriptCheck({ ... }),
|
|
251
|
+
* }
|
|
252
|
+
* ```
|
|
253
|
+
*/
|
|
254
|
+
checks: Record<string, CheckConfig$1>;
|
|
255
|
+
/**
|
|
256
|
+
* Runners to register custom check types.
|
|
257
|
+
*
|
|
258
|
+
* Built-in checks (eslint, typescript) are always available.
|
|
259
|
+
*
|
|
260
|
+
* @example
|
|
261
|
+
* ```ts
|
|
262
|
+
* {
|
|
263
|
+
* runners: [myCustomRunner()],
|
|
264
|
+
* checks: {
|
|
265
|
+
* "custom": myCheck({ ... })
|
|
266
|
+
* }
|
|
267
|
+
* }
|
|
268
|
+
* ```
|
|
269
|
+
*/
|
|
270
|
+
runners?: CheckRunner[];
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Interface that all check runners must implement.
|
|
274
|
+
*
|
|
275
|
+
* Each check type (eslint, typescript, custom) implements this interface
|
|
276
|
+
* to provide consistent lifecycle hooks for execution.
|
|
277
|
+
*/
|
|
278
|
+
interface CheckRunner<TConfig = unknown> {
|
|
279
|
+
/**
|
|
280
|
+
* Execute the check and return a snapshot of issues.
|
|
281
|
+
*
|
|
282
|
+
* @param config - Check-specific configuration
|
|
283
|
+
*
|
|
284
|
+
* @returns Snapshot containing all issues found
|
|
285
|
+
*/
|
|
286
|
+
run(config: TConfig): Promise<RawSnapshot>;
|
|
287
|
+
/**
|
|
288
|
+
* Setup any infrastructure needed for this check.
|
|
289
|
+
* Called once during runner setup, in parallel with other checks.
|
|
290
|
+
*
|
|
291
|
+
* Examples: creating cache directories, initializing compilation state.
|
|
292
|
+
*
|
|
293
|
+
* Optional - not all checks need infrastructure setup.
|
|
294
|
+
*/
|
|
295
|
+
setup?(): Promise<void>;
|
|
296
|
+
/**
|
|
297
|
+
* Unique identifier for this check type.
|
|
298
|
+
* Must match the `type` field in CheckConfig.
|
|
299
|
+
*
|
|
300
|
+
* @example "eslint"
|
|
301
|
+
*
|
|
302
|
+
* @example "typescript"
|
|
303
|
+
*/
|
|
304
|
+
readonly type: string;
|
|
305
|
+
/**
|
|
306
|
+
* Validate that all dependencies for this check are available.
|
|
307
|
+
* Called once during runner setup before any checks execute.
|
|
308
|
+
*
|
|
309
|
+
* Should throw a descriptive error if dependencies are missing.
|
|
310
|
+
*
|
|
311
|
+
* @throws {Error} If required dependencies are not installed
|
|
312
|
+
*/
|
|
313
|
+
validate?(): Promise<void>;
|
|
314
|
+
}
|
|
315
|
+
//#endregion
|
|
316
|
+
//#region src/runners/eslint.d.ts
|
|
317
|
+
/**
|
|
318
|
+
* Check runner for ESLint.
|
|
319
|
+
*/
|
|
320
|
+
declare class ESLintCheckRunner implements CheckRunner {
|
|
321
|
+
readonly type = "eslint";
|
|
322
|
+
run(eslintConfig: ESLintCheckConfig): Promise<{
|
|
323
|
+
items: IssueInput[];
|
|
324
|
+
type: "items";
|
|
325
|
+
}>;
|
|
326
|
+
setup(): Promise<void>;
|
|
327
|
+
validate(): Promise<void>;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Create an ESLint check configuration.
|
|
331
|
+
*
|
|
332
|
+
* @param config - ESLint check configuration options.
|
|
333
|
+
*
|
|
334
|
+
* @returns An ESLint check configuration object.
|
|
335
|
+
*/
|
|
336
|
+
declare function eslintCheck(config: ESLintCheckConfig): {
|
|
337
|
+
concurrency?: "auto" | "off" | number;
|
|
338
|
+
files: string[];
|
|
339
|
+
overrides?: eslint0.Linter.Config | eslint0.Linter.Config[];
|
|
340
|
+
type: "eslint";
|
|
341
|
+
};
|
|
342
|
+
//#endregion
|
|
343
|
+
//#region src/runners/typescript.d.ts
|
|
344
|
+
/**
|
|
345
|
+
* Check runner for TypeScript.
|
|
346
|
+
*/
|
|
347
|
+
declare class TypeScriptCheckRunner implements CheckRunner {
|
|
348
|
+
readonly type = "typescript";
|
|
349
|
+
run(typescriptConfig: TypeScriptCheckConfig): Promise<{
|
|
350
|
+
items: IssueInput[];
|
|
351
|
+
type: "items";
|
|
352
|
+
}>;
|
|
353
|
+
setup(): Promise<void>;
|
|
354
|
+
validate(): Promise<void>;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Create a TypeScript check configuration.
|
|
358
|
+
*
|
|
359
|
+
* @param config - TypeScript check configuration options.
|
|
360
|
+
*
|
|
361
|
+
* @returns A TypeScript check configuration object.
|
|
362
|
+
*/
|
|
363
|
+
declare function typescriptCheck(config: TypeScriptCheckConfig): {
|
|
364
|
+
overrides?: {
|
|
365
|
+
compilerOptions?: typescript0.CompilerOptions;
|
|
366
|
+
};
|
|
367
|
+
tsconfig?: string;
|
|
368
|
+
type: "typescript";
|
|
369
|
+
};
|
|
370
|
+
//#endregion
|
|
371
|
+
//#region src/core/config.d.ts
|
|
372
|
+
type ExtractRunnerByType<TRunners extends readonly CheckRunner[], TType extends string> = Extract<TRunners[number], {
|
|
373
|
+
type: TType;
|
|
374
|
+
}>;
|
|
375
|
+
type ExtractConfig<TRunner> = TRunner extends CheckRunner<infer C> ? C : never;
|
|
376
|
+
type CheckConfig<TRunners extends readonly CheckRunner[], TType extends TRunners[number]["type"]> = ExtractConfig<ExtractRunnerByType<TRunners, TType>> & {
|
|
377
|
+
type: TType;
|
|
378
|
+
};
|
|
379
|
+
type InternalRunners = readonly [ESLintCheckRunner, TypeScriptCheckRunner];
|
|
380
|
+
/**
|
|
381
|
+
* Define mejora configuration.
|
|
382
|
+
*
|
|
383
|
+
* @param config - mejora configuration object.
|
|
384
|
+
*
|
|
385
|
+
* @param config.runners - Optional array of custom check runners to register.
|
|
386
|
+
*
|
|
387
|
+
* @param config.checks - Map of check names to their configurations.
|
|
388
|
+
*
|
|
389
|
+
* @returns The provided configuration object.
|
|
390
|
+
*/
|
|
391
|
+
declare function defineConfig<const TRunners extends readonly CheckRunner[]>(config: {
|
|
392
|
+
checks: Record<string, CheckConfig<[...InternalRunners, ...TRunners], [...InternalRunners, ...TRunners][number]["type"]>>;
|
|
393
|
+
runners?: TRunners;
|
|
394
|
+
}): {
|
|
395
|
+
checks: Record<string, CheckConfig<[...InternalRunners, ...TRunners], [...InternalRunners, ...TRunners][number]["type"]>>;
|
|
396
|
+
runners?: TRunners;
|
|
397
|
+
};
|
|
398
|
+
//#endregion
|
|
399
|
+
//#region src/runners/regex.d.ts
|
|
400
|
+
/**
|
|
401
|
+
* Check runner for regex pattern matching.
|
|
402
|
+
*/
|
|
403
|
+
declare class RegexCheckRunner implements CheckRunner {
|
|
404
|
+
readonly type = "regex";
|
|
405
|
+
run(config: RegexCheckConfig): Promise<{
|
|
406
|
+
items: IssueInput[];
|
|
407
|
+
type: "items";
|
|
408
|
+
}>;
|
|
409
|
+
setup(): Promise<void>;
|
|
410
|
+
validate(): Promise<void>;
|
|
411
|
+
}
|
|
412
|
+
declare const regexRunner: () => RegexCheckRunner;
|
|
413
|
+
/**
|
|
414
|
+
* Create a regex check configuration.
|
|
415
|
+
*
|
|
416
|
+
* @param config - Regex check configuration options.
|
|
417
|
+
*
|
|
418
|
+
* @returns A regex check configuration object.
|
|
419
|
+
*/
|
|
420
|
+
declare function regexCheck(config: RegexCheckConfig): {
|
|
421
|
+
concurrency?: number;
|
|
422
|
+
files: string[];
|
|
423
|
+
ignore?: string[];
|
|
424
|
+
patterns: RegexPattern[];
|
|
425
|
+
type: "regex";
|
|
426
|
+
};
|
|
427
|
+
//#endregion
|
|
428
|
+
export { eslintCheck as a, Issue as c, Snapshot as d, typescriptCheck as i, IssueInput as l, regexRunner as n, CheckRunner as o, defineConfig as r, Config as s, regexCheck as t, RawSnapshot as u };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,430 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import * as typescript0 from "typescript";
|
|
4
|
-
import { CompilerOptions } from "typescript";
|
|
5
|
-
|
|
6
|
-
//#region src/types.d.ts
|
|
7
|
-
interface Issue {
|
|
8
|
-
/**
|
|
9
|
-
* 1-indexed column number for display.
|
|
10
|
-
*/
|
|
11
|
-
column: number;
|
|
12
|
-
/**
|
|
13
|
-
* Relative path from cwd.
|
|
14
|
-
*/
|
|
15
|
-
file: string;
|
|
16
|
-
/**
|
|
17
|
-
* Hash of canonical representation.
|
|
18
|
-
*
|
|
19
|
-
* @example "a1b2c3d4e5f6g7h8i9j0"
|
|
20
|
-
*/
|
|
21
|
-
id: string;
|
|
22
|
-
/**
|
|
23
|
-
* 1-indexed line number for display.
|
|
24
|
-
*/
|
|
25
|
-
line: number;
|
|
26
|
-
/**
|
|
27
|
-
* The message.
|
|
28
|
-
*/
|
|
29
|
-
message: string;
|
|
30
|
-
/**
|
|
31
|
-
* Identifier for the issue (rule name, diagnostic code, etc).
|
|
32
|
-
*
|
|
33
|
-
* @example "no-nested-ternary" (ESLint)
|
|
34
|
-
*
|
|
35
|
-
* @example "TS2345" (TypeScript)
|
|
36
|
-
*/
|
|
37
|
-
rule: string;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Issue produced by a check runner.
|
|
41
|
-
*/
|
|
42
|
-
type IssueInput = Omit<Issue, "id">;
|
|
43
|
-
type SnapshotType = "items";
|
|
44
|
-
interface RawSnapshot {
|
|
45
|
-
/**
|
|
46
|
-
* Snapshot items (each item represents an issue produced by the check).
|
|
47
|
-
*/
|
|
48
|
-
items: IssueInput[];
|
|
49
|
-
type: SnapshotType;
|
|
50
|
-
}
|
|
51
|
-
interface Snapshot {
|
|
52
|
-
items: Issue[];
|
|
53
|
-
type: SnapshotType;
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Configuration for an ESLint check.
|
|
57
|
-
*
|
|
58
|
-
* @example
|
|
59
|
-
* ```ts
|
|
60
|
-
* eslint({
|
|
61
|
-
* files: ["src/**\/*.{ts,tsx}"],
|
|
62
|
-
* overrides: {
|
|
63
|
-
* rules: {
|
|
64
|
-
* "no-nested-ternary": "error",
|
|
65
|
-
* },
|
|
66
|
-
* },
|
|
67
|
-
* })
|
|
68
|
-
* ```
|
|
69
|
-
*/
|
|
70
|
-
interface ESLintCheckConfig {
|
|
71
|
-
/**
|
|
72
|
-
* Concurrency setting for ESLint.
|
|
73
|
-
*
|
|
74
|
-
* @see https://eslint.org/blog/2025/08/multithread-linting/#cli-multithreading-support
|
|
75
|
-
*
|
|
76
|
-
* @default "auto"
|
|
77
|
-
*/
|
|
78
|
-
concurrency?: "auto" | "off" | number;
|
|
79
|
-
/**
|
|
80
|
-
* Glob patterns for files to lint.
|
|
81
|
-
*
|
|
82
|
-
* Passed directly to ESLint's `lintFiles()` method.
|
|
83
|
-
*
|
|
84
|
-
* @example ["src/**\/*.ts", "src/**\/*.tsx"]
|
|
85
|
-
*/
|
|
86
|
-
files: string[];
|
|
87
|
-
/**
|
|
88
|
-
* ESLint configuration to merge with the base config.
|
|
89
|
-
*
|
|
90
|
-
* This is passed to ESLint's `overrideConfig` option and merged with
|
|
91
|
-
* your existing ESLint configuration.
|
|
92
|
-
*
|
|
93
|
-
* Can be a single config object or an array of config objects.
|
|
94
|
-
*
|
|
95
|
-
* @example
|
|
96
|
-
* ```ts
|
|
97
|
-
* {
|
|
98
|
-
* rules: {
|
|
99
|
-
* "no-console": "error",
|
|
100
|
-
* },
|
|
101
|
-
* }
|
|
102
|
-
* ```
|
|
103
|
-
*/
|
|
104
|
-
overrides?: Linter.Config | Linter.Config[];
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Configuration for a TypeScript diagnostics check.
|
|
108
|
-
*
|
|
109
|
-
* @example
|
|
110
|
-
* ```ts
|
|
111
|
-
* typescript({
|
|
112
|
-
* overrides: {
|
|
113
|
-
* compilerOptions: {
|
|
114
|
-
* noImplicitAny: true,
|
|
115
|
-
* },
|
|
116
|
-
* },
|
|
117
|
-
* })
|
|
118
|
-
* ```
|
|
119
|
-
*/
|
|
120
|
-
interface TypeScriptCheckConfig {
|
|
121
|
-
/**
|
|
122
|
-
* Compiler options to merge with the base tsconfig.
|
|
123
|
-
*
|
|
124
|
-
* These options are merged with (not replacing) the compiler options
|
|
125
|
-
* from your tsconfig file.
|
|
126
|
-
*/
|
|
127
|
-
overrides?: {
|
|
128
|
-
compilerOptions?: CompilerOptions;
|
|
129
|
-
};
|
|
130
|
-
/**
|
|
131
|
-
* Path to a TypeScript config file.
|
|
132
|
-
*
|
|
133
|
-
* If not provided, mejora will search for the nearest `tsconfig.json`
|
|
134
|
-
* starting from the current working directory.
|
|
135
|
-
*
|
|
136
|
-
* @example "tsconfig.strict.json"
|
|
137
|
-
*/
|
|
138
|
-
tsconfig?: string;
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* A regex pattern configuration.
|
|
142
|
-
*/
|
|
143
|
-
interface RegexPattern {
|
|
144
|
-
/**
|
|
145
|
-
* Human-readable message for matches.
|
|
146
|
-
*
|
|
147
|
-
* @example "TODO comment found"
|
|
148
|
-
*
|
|
149
|
-
* @example "console.log statement"
|
|
150
|
-
*
|
|
151
|
-
* @example (match) => `Found TODO at line ${match.index + 1}`
|
|
152
|
-
*/
|
|
153
|
-
message?: ((match: RegExpExecArray) => string) | string;
|
|
154
|
-
/**
|
|
155
|
-
* The regex pattern to match.
|
|
156
|
-
*
|
|
157
|
-
* @example /\/\/\s*TODO:/gi
|
|
158
|
-
*
|
|
159
|
-
* @example /console\.log/g
|
|
160
|
-
*/
|
|
161
|
-
pattern: RegExp;
|
|
162
|
-
/**
|
|
163
|
-
* Rule identifier for this pattern.
|
|
164
|
-
* If not provided, uses the pattern source as the rule ID.
|
|
165
|
-
*
|
|
166
|
-
* @example "no-todos"
|
|
167
|
-
*
|
|
168
|
-
* @example "no-console-log"
|
|
169
|
-
*/
|
|
170
|
-
rule?: string;
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Configuration for regex pattern matching check.
|
|
174
|
-
*/
|
|
175
|
-
interface RegexCheckConfig {
|
|
176
|
-
/**
|
|
177
|
-
* Concurrency for processing files.
|
|
178
|
-
*
|
|
179
|
-
* @default 10
|
|
180
|
-
*/
|
|
181
|
-
concurrency?: number;
|
|
182
|
-
/**
|
|
183
|
-
* Array of glob patterns for files to check.
|
|
184
|
-
*
|
|
185
|
-
* @example ["src/**\/*.ts", "lib/**\/*.js"]
|
|
186
|
-
*/
|
|
187
|
-
files: string[];
|
|
188
|
-
/**
|
|
189
|
-
* Array of glob patterns to ignore.
|
|
190
|
-
*
|
|
191
|
-
* @default ["**\/node_modules/**", "**\/dist/**", "**\/.git/**"]
|
|
192
|
-
*/
|
|
193
|
-
ignore?: string[];
|
|
194
|
-
/**
|
|
195
|
-
* Array of regex patterns to match.
|
|
196
|
-
*/
|
|
197
|
-
patterns: RegexPattern[];
|
|
198
|
-
}
|
|
199
|
-
type CustomCheckConfig = Record<string, unknown> & {
|
|
200
|
-
type: string;
|
|
201
|
-
};
|
|
202
|
-
type CheckConfig$1 = (ESLintCheckConfig & {
|
|
203
|
-
type: "eslint";
|
|
204
|
-
}) | (TypeScriptCheckConfig & {
|
|
205
|
-
type: "typescript";
|
|
206
|
-
}) | CustomCheckConfig;
|
|
207
|
-
/**
|
|
208
|
-
* mejora configuration.
|
|
209
|
-
*
|
|
210
|
-
* Define checks to run and track for regressions.
|
|
211
|
-
*
|
|
212
|
-
* @example
|
|
213
|
-
* ```ts
|
|
214
|
-
* import { defineConfig, eslint, typescript } from "mejora";
|
|
215
|
-
*
|
|
216
|
-
* export default defineConfig({
|
|
217
|
-
* checks: {
|
|
218
|
-
* "eslint > no-nested-ternary": eslint({
|
|
219
|
-
* files: ["src/**\/*.{ts,tsx}"],
|
|
220
|
-
* overrides: {
|
|
221
|
-
* rules: {
|
|
222
|
-
* "no-nested-ternary": "error",
|
|
223
|
-
* },
|
|
224
|
-
* },
|
|
225
|
-
* }),
|
|
226
|
-
* "typescript": typescript({
|
|
227
|
-
* overrides: {
|
|
228
|
-
* compilerOptions: {
|
|
229
|
-
* noImplicitAny: true,
|
|
230
|
-
* },
|
|
231
|
-
* },
|
|
232
|
-
* }),
|
|
233
|
-
* },
|
|
234
|
-
* });
|
|
235
|
-
* ```
|
|
236
|
-
*/
|
|
237
|
-
interface Config {
|
|
238
|
-
/**
|
|
239
|
-
* Check definitions.
|
|
240
|
-
*
|
|
241
|
-
* Each key is a check identifier used in the baseline and output.
|
|
242
|
-
* The identifier can contain any characters.
|
|
243
|
-
*
|
|
244
|
-
* Use `eslint()` and `typescript()` helpers to create check configs.
|
|
245
|
-
*
|
|
246
|
-
* @example
|
|
247
|
-
* ```ts
|
|
248
|
-
* {
|
|
249
|
-
* "eslint > no-console": eslint({ ... }),
|
|
250
|
-
* "typescript": typescriptCheck({ ... }),
|
|
251
|
-
* }
|
|
252
|
-
* ```
|
|
253
|
-
*/
|
|
254
|
-
checks: Record<string, CheckConfig$1>;
|
|
255
|
-
/**
|
|
256
|
-
* Runners to register custom check types.
|
|
257
|
-
*
|
|
258
|
-
* Built-in checks (eslint, typescript) are always available.
|
|
259
|
-
*
|
|
260
|
-
* @example
|
|
261
|
-
* ```ts
|
|
262
|
-
* {
|
|
263
|
-
* runners: [myCustomRunner()],
|
|
264
|
-
* checks: {
|
|
265
|
-
* "custom": myCheck({ ... })
|
|
266
|
-
* }
|
|
267
|
-
* }
|
|
268
|
-
* ```
|
|
269
|
-
*/
|
|
270
|
-
runners?: CheckRunner[];
|
|
271
|
-
}
|
|
272
|
-
//#endregion
|
|
273
|
-
//#region src/check-runner.d.ts
|
|
274
|
-
/**
|
|
275
|
-
* Interface that all check runners must implement.
|
|
276
|
-
*
|
|
277
|
-
* Each check type (eslint, typescript, custom) implements this interface
|
|
278
|
-
* to provide consistent lifecycle hooks for execution.
|
|
279
|
-
*/
|
|
280
|
-
interface CheckRunner<TConfig = unknown> {
|
|
281
|
-
/**
|
|
282
|
-
* Execute the check and return a snapshot of issues.
|
|
283
|
-
*
|
|
284
|
-
* @param config - Check-specific configuration
|
|
285
|
-
*
|
|
286
|
-
* @returns Snapshot containing all issues found
|
|
287
|
-
*/
|
|
288
|
-
run(config: TConfig): Promise<RawSnapshot>;
|
|
289
|
-
/**
|
|
290
|
-
* Setup any infrastructure needed for this check.
|
|
291
|
-
* Called once during runner setup, in parallel with other checks.
|
|
292
|
-
*
|
|
293
|
-
* Examples: creating cache directories, initializing compilation state.
|
|
294
|
-
*
|
|
295
|
-
* Optional - not all checks need infrastructure setup.
|
|
296
|
-
*/
|
|
297
|
-
setup?(): Promise<void>;
|
|
298
|
-
/**
|
|
299
|
-
* Unique identifier for this check type.
|
|
300
|
-
* Must match the `type` field in CheckConfig.
|
|
301
|
-
*
|
|
302
|
-
* @example "eslint"
|
|
303
|
-
*
|
|
304
|
-
* @example "typescript"
|
|
305
|
-
*/
|
|
306
|
-
readonly type: string;
|
|
307
|
-
/**
|
|
308
|
-
* Validate that all dependencies for this check are available.
|
|
309
|
-
* Called once during runner setup before any checks execute.
|
|
310
|
-
*
|
|
311
|
-
* Should throw a descriptive error if dependencies are missing.
|
|
312
|
-
*
|
|
313
|
-
* @throws {Error} If required dependencies are not installed
|
|
314
|
-
*/
|
|
315
|
-
validate?(): Promise<void>;
|
|
316
|
-
}
|
|
317
|
-
//#endregion
|
|
318
|
-
//#region src/runners/eslint.d.ts
|
|
319
|
-
/**
|
|
320
|
-
* Check runner for ESLint.
|
|
321
|
-
*/
|
|
322
|
-
declare class ESLintCheckRunner implements CheckRunner {
|
|
323
|
-
readonly type = "eslint";
|
|
324
|
-
run(eslintConfig: ESLintCheckConfig): Promise<{
|
|
325
|
-
items: IssueInput[];
|
|
326
|
-
type: "items";
|
|
327
|
-
}>;
|
|
328
|
-
setup(): Promise<void>;
|
|
329
|
-
validate(): Promise<void>;
|
|
330
|
-
}
|
|
331
|
-
/**
|
|
332
|
-
* Create an ESLint check configuration.
|
|
333
|
-
*
|
|
334
|
-
* @param config - ESLint check configuration options.
|
|
335
|
-
*
|
|
336
|
-
* @returns An ESLint check configuration object.
|
|
337
|
-
*/
|
|
338
|
-
declare function eslintCheck(config: ESLintCheckConfig): {
|
|
339
|
-
concurrency?: "auto" | "off" | number;
|
|
340
|
-
files: string[];
|
|
341
|
-
overrides?: eslint0.Linter.Config | eslint0.Linter.Config[];
|
|
342
|
-
type: "eslint";
|
|
343
|
-
};
|
|
344
|
-
//#endregion
|
|
345
|
-
//#region src/runners/typescript.d.ts
|
|
346
|
-
/**
|
|
347
|
-
* Check runner for TypeScript.
|
|
348
|
-
*/
|
|
349
|
-
declare class TypeScriptCheckRunner implements CheckRunner {
|
|
350
|
-
readonly type = "typescript";
|
|
351
|
-
run(typescriptConfig: TypeScriptCheckConfig): Promise<{
|
|
352
|
-
items: IssueInput[];
|
|
353
|
-
type: "items";
|
|
354
|
-
}>;
|
|
355
|
-
setup(): Promise<void>;
|
|
356
|
-
validate(): Promise<void>;
|
|
357
|
-
}
|
|
358
|
-
/**
|
|
359
|
-
* Create a TypeScript check configuration.
|
|
360
|
-
*
|
|
361
|
-
* @param config - TypeScript check configuration options.
|
|
362
|
-
*
|
|
363
|
-
* @returns A TypeScript check configuration object.
|
|
364
|
-
*/
|
|
365
|
-
declare function typescriptCheck(config: TypeScriptCheckConfig): {
|
|
366
|
-
overrides?: {
|
|
367
|
-
compilerOptions?: typescript0.CompilerOptions;
|
|
368
|
-
};
|
|
369
|
-
tsconfig?: string;
|
|
370
|
-
type: "typescript";
|
|
371
|
-
};
|
|
372
|
-
//#endregion
|
|
373
|
-
//#region src/config.d.ts
|
|
374
|
-
type ExtractRunnerByType<TRunners extends readonly CheckRunner[], TType extends string> = Extract<TRunners[number], {
|
|
375
|
-
type: TType;
|
|
376
|
-
}>;
|
|
377
|
-
type ExtractConfig<TRunner> = TRunner extends CheckRunner<infer C> ? C : never;
|
|
378
|
-
type CheckConfig<TRunners extends readonly CheckRunner[], TType extends TRunners[number]["type"]> = ExtractConfig<ExtractRunnerByType<TRunners, TType>> & {
|
|
379
|
-
type: TType;
|
|
380
|
-
};
|
|
381
|
-
type InternalRunners = readonly [ESLintCheckRunner, TypeScriptCheckRunner];
|
|
382
|
-
/**
|
|
383
|
-
* Define mejora configuration.
|
|
384
|
-
*
|
|
385
|
-
* @param config - mejora configuration object.
|
|
386
|
-
*
|
|
387
|
-
* @param config.runners - Optional array of custom check runners to register.
|
|
388
|
-
*
|
|
389
|
-
* @param config.checks - Map of check names to their configurations.
|
|
390
|
-
*
|
|
391
|
-
* @returns The provided configuration object.
|
|
392
|
-
*/
|
|
393
|
-
declare function defineConfig<const TRunners extends readonly CheckRunner[]>(config: {
|
|
394
|
-
checks: Record<string, CheckConfig<[...InternalRunners, ...TRunners], [...InternalRunners, ...TRunners][number]["type"]>>;
|
|
395
|
-
runners?: TRunners;
|
|
396
|
-
}): {
|
|
397
|
-
checks: Record<string, CheckConfig<[...InternalRunners, ...TRunners], [...InternalRunners, ...TRunners][number]["type"]>>;
|
|
398
|
-
runners?: TRunners;
|
|
399
|
-
};
|
|
400
|
-
//#endregion
|
|
401
|
-
//#region src/runners/regex.d.ts
|
|
402
|
-
/**
|
|
403
|
-
* Check runner for regex pattern matching.
|
|
404
|
-
*/
|
|
405
|
-
declare class RegexCheckRunner implements CheckRunner {
|
|
406
|
-
readonly type = "regex";
|
|
407
|
-
run(config: RegexCheckConfig): Promise<{
|
|
408
|
-
items: IssueInput[];
|
|
409
|
-
type: "items";
|
|
410
|
-
}>;
|
|
411
|
-
setup(): Promise<void>;
|
|
412
|
-
validate(): Promise<void>;
|
|
413
|
-
}
|
|
414
|
-
declare const regexRunner: () => RegexCheckRunner;
|
|
415
|
-
/**
|
|
416
|
-
* Create a regex check configuration.
|
|
417
|
-
*
|
|
418
|
-
* @param config - Regex check configuration options.
|
|
419
|
-
*
|
|
420
|
-
* @returns A regex check configuration object.
|
|
421
|
-
*/
|
|
422
|
-
declare function regexCheck(config: RegexCheckConfig): {
|
|
423
|
-
concurrency?: number;
|
|
424
|
-
files: string[];
|
|
425
|
-
ignore?: string[];
|
|
426
|
-
patterns: RegexPattern[];
|
|
427
|
-
type: "regex";
|
|
428
|
-
};
|
|
429
|
-
//#endregion
|
|
430
|
-
export { type CheckRunner, type Config, type Issue, type IssueInput, type RawSnapshot, type Snapshot, defineConfig, eslintCheck as eslint, eslintCheck, regexCheck as regex, regexCheck, regexRunner, typescriptCheck as typescript, typescriptCheck };
|
|
1
|
+
import { a as eslintCheck, c as Issue, d as Snapshot, i as typescriptCheck, l as IssueInput, n as regexRunner, o as CheckRunner, r as defineConfig, s as Config, t as regexCheck, u as RawSnapshot } from "./index-Dr3lmWeD.mjs";
|
|
2
|
+
export { CheckRunner, Config, Issue, IssueInput, RawSnapshot, Snapshot, defineConfig, eslintCheck as eslint, eslintCheck, regexCheck as regex, regexCheck, regexRunner, typescriptCheck as typescript, typescriptCheck };
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,c as t,h as n,i as r,l as i,n as a,o,p as s,s as c}from"./typescript-
|
|
1
|
+
import{a as e,c as t,h as n,i as r,l as i,n as a,o,p as s,s as c}from"./typescript-sQ82Cu7A.mjs";import{mkdir as l}from"node:fs/promises";import{createReadStream as u}from"node:fs";import{createInterface as d}from"node:readline/promises";const f=[`**/node_modules/**`,`**/dist/**`,`**/.git/**`];function p(e,t){if(t?.length)return t;let n=e.map(e=>/^([^*]+\/)/.exec(e)?.[1]).filter(e=>e!==void 0);return[...f,...n.flatMap(e=>f.map(t=>t.replace(/^\*\*\//,e)))]}async function m(e,t,n){let r=Array.from({length:e.length}),i=0;return await Promise.all(Array.from({length:Math.min(t,e.length)},async()=>{for(;i<e.length;){let t=i++;r[t]=await n(e[t])}})),r}var h=class{type=`regex`;async run(n){let r=process.cwd(),{glob:a}=await import(`tinyglobby`),l=p(n.files,n.ignore),f=await a(n.files,{absolute:!1,cwd:r,ignore:l}),h=n.patterns.map(({message:e,pattern:t,rule:n})=>{let r=t.flags.includes(`g`)?t.flags:`${t.flags}g`;return{message:e,regex:new RegExp(t.source,r),ruleText:n??t.source}}),g=s(o(this.type,r),`${e(n)}.json`),_=await t(g),v={},y=await m(f,n.concurrency??10,async e=>{let t=s(r,e),n=await c(t);if(!n)return[];let i=_[e];if(i?.hash===n)return v[e]=i,i.items;try{let r=[],i=d({crlfDelay:1/0,input:u(t,{encoding:`utf8`})}),a=0;try{for await(let t of i){a++;for(let n of h){n.regex.lastIndex=0;let i;for(;(i=n.regex.exec(t))!==null;){let t=i.index+1,o=typeof n.message==`function`?n.message(i):n.message??`Pattern matched: ${i[0]}`;r.push({column:t,file:e,line:a,message:o,rule:n.ruleText})}}}}finally{i.close()}return v[e]={hash:n,items:r},r}catch{return[]}}),b=[];for(let e of y)b.push(...e);return await i(g,v),{items:b,type:`items`}}async setup(){let e=process.cwd();await l(o(this.type,e),{recursive:!0})}async validate(){try{await import(`tinyglobby`)}catch{throw Error(`${this.type} check requires "tinyglobby" package to be installed. Run: npm install tinyglobby`)}}};const g=()=>new h;function _(e){return{type:`regex`,...e}}export{n as defineConfig,r as eslint,r as eslintCheck,_ as regex,_ as regexCheck,g as regexRunner,a as typescript,a as typescriptCheck};
|
package/dist/run.mjs
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{d as e,f as t,g as n,m as r,
|
|
3
|
-
|
|
4
|
-
`
|
|
5
|
-
|
|
6
|
-
`)}function
|
|
7
|
-
`)}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
${L(e)}
|
|
11
|
-
}`}function R(e){if(typeof e!=`object`||!e)throw TypeError(`Baseline must be an object`);if(`checks`in e&&e.checks&&typeof e.checks==`object`)return{checks:e.checks,version:2};let t={};for(let[n,r]of Object.entries(e))n!==`version`&&(t[n]=r);return{checks:t,version:2}}function z(e){try{let t=I(e.trim());if(t)return R(t);let n=_e(F(L(e)));return R(JSON.parse(n))}catch(e){let t=e instanceof Error?e.message:String(e);throw Error(`Failed to parse baseline during conflict resolution: ${t}`,{cause:e})}}function ve(e){let t=[...e.matchAll(/<<<<<<< .*\n([\s\S]*?)\n=======\n([\s\S]*?)\n>>>>>>> .*$/gm)];if(t.length===0)throw Error(`Could not parse conflict markers in baseline`);return t.map(([,e=``,t=``])=>({ours:e,theirs:t}))}function ye(e){let t=new Map;for(let n of e)for(let[e,{items:r=[]}]of Object.entries(n.checks)){if(r.length===0)continue;let n=t.get(e);n||(n=new Map,t.set(e,n));for(let e of r)n.set(e.id,e)}let n={};for(let[e,r]of t)n[e]={items:[...r.values()].toSorted((e,t)=>e.id.localeCompare(t.id)),type:`items`};return{checks:n,version:2}}function be(e){let t=ve(e),n=[];for(let{ours:e,theirs:r}of t)n.push(z(e),z(r));return ye(n)}const B=`__unparsable__`;function V(e){return e.replaceAll(`<`,`<`).replaceAll(`>`,`>`).replaceAll(`[`,`[`).replaceAll(`]`,`]`)}function H(e,t,n){let i=r(t,e);return n?`${i}#L${n}`:i}function U(e,t){return`[${e}](${t})`}function xe(e,t){let n=H(e.file,t,e.line);return`- ${U(e.line?`Line ${e.line}`:e.file,n)} - ${`${e.rule}: ${V(e.message)}`}`}function Se(e){let t=Object.groupBy(e,e=>e.file||B);return Object.entries(t).map(([e,t=[]])=>({filePath:e,items:t})).toSorted((e,t)=>e.filePath===B?1:t.filePath===B?-1:e.filePath.localeCompare(t.filePath))}function Ce(e,t){let n=e.length,r=E(n,`issue`),i=[`\n### Other Issues · ${t}\n`];for(let t of e)i.push(`- ${t.rule}: ${V(t.message)}`);return i.push(`\n${n} ${r} in Other Issues`,``),i.join(`
|
|
12
|
-
`)}function we(e,t,n){if(e.filePath===B)return Ce(e.items,n);let r=H(e.filePath,t),i=U(e.filePath,r),a=e.items.length,o=E(a,`issue`),s=[`\n### ${i} · ${n}\n`];for(let n of e.items)s.push(xe(n,t));return s.push(`\n${a} ${o} in ${e.filePath}`,``),s.join(`
|
|
13
|
-
`)}function Te(e,t,n){let r=t.length,i=E(r,`issue`),a=[`\n## ${e}\n`];if(t.length===0)return a.push(`No issues`),a.join(`
|
|
14
|
-
`);let o=Se(t);for(let t of o)a.push(we(t,n,e));return a.push(`---\n${r} total ${i} for ${e}`),a.join(`
|
|
15
|
-
`)}function Ee(e){return`${e.replaceAll(/\n{3,}/g,`
|
|
2
|
+
import{d as e,f as t,g as n,m as r,u as i}from"./typescript-sQ82Cu7A.mjs";import{t as a}from"./check-registry-DHd4j450.mjs";import{fileURLToPath as o}from"node:url";import{mkdir as s,readFile as c,writeFile as l}from"node:fs/promises";import{inspect as u,parseArgs as d,styleText as f}from"node:util";import{Tinypool as p}from"tinypool";import{env as m}from"node:process";const h=e=>t=>f(e,typeof t==`number`?t.toString():t),g=h(`blue`),_=h(`bold`),ee=h(`cyan`),v=h(`dim`),y=h(`green`),b=h(`red`),x=h(`gray`),te=h(`underline`),ne=h(`yellow`);function re(e){let t=[e.message];if(e.stack){let n=e.stack.split(`
|
|
3
|
+
`).slice(1).map(e=>v(e.trim())).join(`
|
|
4
|
+
`);t.push(n)}return t.join(`
|
|
5
|
+
`)}function S(...e){return e.map(e=>typeof e==`string`?e:e instanceof Error?re(e):u(e,{colors:!1,depth:10})).join(` `)}const C={error:(...e)=>{console.error(b(`✖`),S(...e))},log:(...e)=>{console.log(S(...e))},start:(...e)=>{console.log(ee(`◐`),S(...e))},success:(...e)=>{console.log(y(`✔`),S(...e))}};function w(e,t){return e.file===t.file?e.line===t.line?e.column-t.column:e.line-t.line:e.file.localeCompare(t.file)}function ie(e){let t=Map.groupBy(e,e=>e.signature),n=[];for(let[e,r]of t){r.sort(w);for(let[t,{signature:a,...o}]of r.entries())n.push({...o,id:i(`${e}:${t}`)})}return n}function T(e){return{items:ie(e.items.map(e=>({...e,signature:`${e.file} - ${e.rule}: ${e.message}`}))).toSorted(w),type:`items`}}const E=e=>e in m&&m[e]!==`0`&&m[e]!==`false`;var ae=E(`CI`)||E(`CONTINUOUS_INTEGRATION`);function D(e,t){return e===1?t:`${t}s`}const O=`__unparsable__`;function k(e){return e.replaceAll(`<`,`<`).replaceAll(`>`,`>`).replaceAll(`[`,`[`).replaceAll(`]`,`]`)}function A(e,t,n){let i=r(t,e);return n?`${i}#L${n}`:i}function j(e,t){return`[${e}](${t})`}function oe(e,t){let n=A(e.file,t,e.line);return`- ${j(e.line?`Line ${e.line}`:e.file,n)} - ${`${e.rule}: ${k(e.message)}`}`}function M(e){let t=Object.groupBy(e,e=>e.file||O);return Object.entries(t).map(([e,t=[]])=>({filePath:e,items:t})).toSorted((e,t)=>e.filePath===O?1:t.filePath===O?-1:e.filePath.localeCompare(t.filePath))}function N(e,t){let n=e.length,r=D(n,`issue`),i=[`\n### Other Issues · ${t}\n`];for(let t of e)i.push(`- ${t.rule}: ${k(t.message)}`);return i.push(`\n${n} ${r} in Other Issues`,``),i.join(`
|
|
6
|
+
`)}function se(e,t,n){if(e.filePath===O)return N(e.items,n);let r=A(e.filePath,t),i=j(e.filePath,r),a=e.items.length,o=D(a,`issue`),s=[`\n### ${i} · ${n}\n`];for(let n of e.items)s.push(oe(n,t));return s.push(`\n${a} ${o} in ${e.filePath}`,``),s.join(`
|
|
7
|
+
`)}function ce(e,t,n){let r=t.length,i=D(r,`issue`),a=[`\n## ${e}\n`];if(t.length===0)return a.push(`No issues`),a.join(`
|
|
8
|
+
`);let o=M(t);for(let t of o)a.push(se(t,n,e));return a.push(`---\n${r} total ${i} for ${e}`),a.join(`
|
|
9
|
+
`)}function le(e){return`${e.replaceAll(/\n{3,}/g,`
|
|
16
10
|
|
|
17
|
-
`).trimEnd()}\n`}function
|
|
11
|
+
`).trimEnd()}\n`}function P(e,t){let n=[`<!-- prettier-ignore-start -->
|
|
18
12
|
`,`# Mejora Baseline
|
|
19
|
-
`,`This file represents the current accepted state of the codebase.`];for(let[r,{items:i=[]}]of Object.entries(e.checks))n.push(
|
|
20
|
-
<!-- prettier-ignore-end -->`),
|
|
21
|
-
`))}const
|
|
22
|
-
`).
|
|
23
|
-
|
|
24
|
-
|
|
13
|
+
`,`This file represents the current accepted state of the codebase.`];for(let[r,{items:i=[]}]of Object.entries(e.checks))n.push(ce(r,i,t));return n.push(`
|
|
14
|
+
<!-- prettier-ignore-end -->`),le(n.join(`
|
|
15
|
+
`))}function ue(){return{hasImprovement:!1,hasRegression:!1,hasRelocation:!1,isInitial:!0,newIssues:[],removedIssues:[]}}function de(e,t,n){return{hasImprovement:t.length>0,hasRegression:e.length>0,hasRelocation:n,isInitial:!1,newIssues:e.toSorted((e,t)=>e.id.localeCompare(t.id)),removedIssues:t.toSorted((e,t)=>e.id.localeCompare(t.id))}}function F(e=[]){return new Map(e.map(e=>[e.id,e]))}function I(e){return new Set(e.keys())}function L(e,t){let n=[];for(let r of t){let t=e.get(r);n.push(t)}return n}function R(e,t){for(let[n,r]of e){let e=t.get(n);if(e&&(r.line!==e.line||r.column!==e.column))return!0}return!1}function z(e,t){let n=F(e.items),r=F(t.items),i=I(n),a=I(r),o=i.difference(a),s=a.difference(i);return de(L(n,o),L(r,s),i.size>o.size?R(n,r):!1)}function B(e,t){return t?z(e,t):ue()}const V=(e,t)=>{if(!t)return!1;let n=e.items,r=t.items;if(n.length!==r.length)return!1;let i=n.toSorted((e,t)=>e.id.localeCompare(t.id)),a=r.toSorted((e,t)=>e.id.localeCompare(t.id));return i.every((e,t)=>{let n=a[t];return e.id===n.id&&e.file===n.file&&e.line===n.line&&e.column===n.column&&e.rule===n.rule&&e.message===n.message})};function H(e,t){let n=e;for(let e=0;e<t;e++){let e=n.trimEnd();if(!e.endsWith(`}`))break;n=e.slice(0,-1)}return n}function fe(e,t){return`${e}${`
|
|
16
|
+
}`.repeat(t)}`}function pe(e){let t=(e.match(/\{/g)?.length??0)-(e.match(/\}/g)?.length??0);return t===0?e:t<0?H(e,-t):fe(e,t)}function me(e){try{return JSON.parse(e)}catch{return}}function U(e){let t=e.trim();return t.endsWith(`,`)?t.slice(0,-1):t}function he(e){return`{
|
|
17
|
+
"version": 2,
|
|
18
|
+
${U(e)}
|
|
19
|
+
}`}function W(e){if(typeof e!=`object`||!e)throw TypeError(`Baseline must be an object`);if(`checks`in e&&e.checks&&typeof e.checks==`object`)return{checks:e.checks,version:2};let t={};for(let[n,r]of Object.entries(e))n!==`version`&&(t[n]=r);return{checks:t,version:2}}function G(e){try{let t=me(e.trim());if(t)return W(t);let n=he(pe(U(e)));return W(JSON.parse(n))}catch(e){let t=e instanceof Error?e.message:String(e);throw Error(`Failed to parse baseline during conflict resolution: ${t}`,{cause:e})}}function ge(e){let t=[...e.matchAll(/<<<<<<< .*\n([\s\S]*?)\n=======\n([\s\S]*?)\n>>>>>>> .*$/gm)];if(t.length===0)throw Error(`Could not parse conflict markers in baseline`);return t.map(([,e=``,t=``])=>({ours:e,theirs:t}))}function _e(e){let t=new Map;for(let n of e)for(let[e,{items:r=[]}]of Object.entries(n.checks)){if(r.length===0)continue;let n=t.get(e);n||(n=new Map,t.set(e,n));for(let e of r)n.set(e.id,e)}let n={};for(let[e,r]of t)n[e]={items:[...r.values()].toSorted((e,t)=>e.id.localeCompare(t.id)),type:`items`};return{checks:n,version:2}}function ve(e){let t=ge(e),n=[];for(let{ours:e,theirs:r}of t)n.push(G(e),G(r));return _e(n)}var K=class e{baselinePath;constructor(e=`.mejora/baseline.json`){this.baselinePath=e}static create(e){return{checks:e,version:2}}static getEntry(e,t){return e?.checks[t]}static update(t,n,r){let i=t??e.create({}),a=i.checks[n];return V(r,a)?i:{...i,checks:{...i.checks,[n]:r}}}async load(){try{let e=await c(this.baselinePath,`utf8`);if(e.includes(`<<<<<<<`)){C.start(`Merge conflict detected in baseline, auto-resolving...`);let t=ve(e);return await this.save(t,!0),C.success(`Baseline conflict resolved`),t}return await this.resolveMarkdownConflictIfNeeded(e),JSON.parse(e)}catch(e){if(e.code===`ENOENT`)return null;throw e}}async save(e,n=!1){if(ae&&!n)return;let r=`${JSON.stringify(e,null,2)}\n`,i=this.baselinePath.replace(`.json`,`.md`),a=P(e,t(this.baselinePath));await s(t(this.baselinePath),{recursive:!0}),await Promise.all([l(this.baselinePath,r,`utf8`),l(i,a,`utf8`)])}async resolveMarkdownConflictIfNeeded(e){let n=this.baselinePath.replace(`.json`,`.md`);try{(await c(n,`utf8`)).includes(`<<<<<<<`)&&(C.start(`Merge conflict detected in markdown report, regenerating...`),await l(n,P(JSON.parse(e),t(this.baselinePath)),`utf8`),C.success(`Markdown report regenerated`))}catch{}}};const ye=o(new URL(`workers/check.mjs`,import.meta.url));var be=class e{baselineManager;registry;constructor(e,t){this.registry=e,this.baselineManager=new K(t)}static async executeChecksParallel(e,t){let n=Object.keys(e),r=new p({filename:ye});try{let e=n.map(async e=>{let n=await r.run({checkId:e}),i=T(n.snapshot),a=K.getEntry(t,e),o=B(i,a);return{baseline:a,checkId:e,duration:n.duration,hasImprovement:o.hasImprovement,hasRegression:o.hasRegression,hasRelocation:o.hasRelocation,isInitial:o.isInitial,newIssues:o.newIssues,removedIssues:o.removedIssues,snapshot:i}});return await Promise.all(e)}catch(e){return C.error(`Parallel execution failed:`,e),null}finally{await r.destroy()}}static filterChecks=(t,n)=>{let r=n.only?e.resolveRegex(n.only,`--only`):null,i=n.skip?e.resolveRegex(n.skip,`--skip`):null;return!r&&!i?t:Object.fromEntries(Object.entries(t).filter(([e])=>!(r&&!r.test(e)||i?.test(e))))};static resolveRegex(e,t){try{return new RegExp(e)}catch{throw Error(`Invalid regex pattern for ${t}: "${e}"`)}}async run(t,n={}){let r=performance.now(),i=await this.baselineManager.load(),a=e.filterChecks(t.checks,n),o=Object.keys(a).length;C.start(`Running ${o} check${o===1?``:`s`}...`);let s=o>1?await e.executeChecksParallel(a,i):await this.executeChecksSequential(a,i);if(!s)return{exitCode:2,hasImprovement:!1,hasRegression:!0,results:[],totalDuration:performance.now()-r};let c=i,l=!1,u=!1,d=!1;for(let e of s)e.hasRegression&&(l=!0),e.hasImprovement&&(u=!0),e.isInitial&&(d=!0),(e.hasImprovement||e.hasRelocation||n.force||e.isInitial)&&(c=K.update(c,e.checkId,{items:e.snapshot.items,type:e.snapshot.type}));return c&&c!==i&&(!l||n.force||d)&&await this.baselineManager.save(c,n.force),{exitCode:l&&!n.force?1:0,hasImprovement:u,hasRegression:l,results:s,totalDuration:performance.now()-r}}async executeChecksSequential(e,t){try{let t=a.getRequiredTypes(e);await Promise.all([this.registry.setup(t),this.registry.validate(t)])}catch(e){return C.error(`Setup failed:`,e),null}let n=[];for(let[r,i]of Object.entries(e))try{let e=performance.now(),a=await this.registry.get(i.type).run(i),o=performance.now()-e,s=T(a),c=K.getEntry(t,r),l=B(s,c);n.push({baseline:c,checkId:r,duration:o,hasImprovement:l.hasImprovement,hasRegression:l.hasRegression,hasRelocation:l.hasRelocation,isInitial:l.isInitial,newIssues:l.newIssues,removedIssues:l.removedIssues,snapshot:s})}catch(e){return C.error(`Error running check "${r}":`,e),null}return n}};function q(e,t){if(!(e===void 0||t===0))return e/t}function xe(e){let{results:t,totalDuration:n}=e,r=t.length,i=[],a=[],o=[],s=[],c=0,l=0,u=0,d=0,f=0,p=[];for(let e of t){let t=e.snapshot.items.length;f+=t,e.isInitial?(u+=t,o.push(e.checkId)):(e.hasImprovement&&(c+=e.removedIssues.length,i.push(e.checkId)),e.hasRegression&&(l+=e.newIssues.length,a.push(e.checkId)),!e.hasImprovement&&!e.hasRegression&&(d+=t,s.push(e.checkId))),p.push({checkId:e.checkId,duration:e.duration,hasImprovement:e.hasImprovement,hasRegression:e.hasRegression,isInitial:e.isInitial,newIssues:e.newIssues,removedIssues:e.removedIssues,totalIssues:t})}let m={checks:p,exitCode:e.exitCode,hasImprovement:e.hasImprovement,hasRegression:e.hasRegression,summary:{avgDuration:q(n,r),checksRun:r,improvementChecks:i,improvements:c,initial:u,initialChecks:o,regressionChecks:a,regressions:l,totalIssues:f,unchanged:d,unchangedChecks:s},totalDuration:n};return JSON.stringify(m,null,2)}function Se(e){if(e<1e3)return`${e}ms`;let t=e/1e3;if(t<60)return t%1==0?`${t}s`:`${t.toFixed(1)}s`;let n=e/6e4;if(n<60)return n%1==0?`${n}m`:`${n.toFixed(1)}m`;let r=e/36e5;return r%1==0?`${r}h`:`${r.toFixed(1)}h`}function J(e){let t=Math.round(e);return t<1?`<1ms`:Se(t)}const Y=` `,Ce=`${Y} `;function we(e){return e===`initial`?v(`→`):e===`improvement`?y(`↑`):b(`↓`)}function Te(n,r,i){let a=t(n),o=e(n),s=r>0?`:${r}:${i>0?i:1}`:``;return`${a===`.`?``:v(`${a}/`)}${te(o)}${s?v(s):``}`}function Ee(e,t){return[`${we(t)} ${Te(e.file,e.line,e.column)} ${v(e.rule)}`,e.message]}function X(e,t){let n=[],r=e.slice(0,10);for(let e of r){let[r,i]=Ee(e,t);n.push(`${Y}${r}`,`${Ce}${i}`)}let i=e.length-r.length;return i>0&&n.push(`${Y}${v(`... and ${i} more`)}`),n}function De(e){return e===void 0?[]:[` ${v(`Duration`)} ${J(e)}`]}function Oe(e){return[` ${v(`Issues`)} ${_(e)}`]}function Z(e){return[...De(e.duration),...Oe(e.snapshot.items.length)]}function Q(e){if(!e.hasRegression)return[];let t=e.newIssues.length;return[` ${b(t)} new ${D(t,`issue`)} (${D(t,`regression`)}):`,...X(e.newIssues,`regression`)]}function ke(e){if(!e.hasImprovement)return[];let t=e.removedIssues.length;return[` ${y(t)} ${D(t,`issue`)} fixed (${D(t,`improvement`)}):`,...X(e.removedIssues,`improvement`)]}function Ae(e,t){let n=t?``:`
|
|
20
|
+
`,r=e.snapshot.items.length,i=[`${n}${g(`ℹ`)} ${e.checkId}:`,` Initial baseline created with ${g(r)} ${D(r,`issue`)}`];return e.snapshot.items.length>0&&i.push(...X(e.snapshot.items,`initial`)),i.push(``,...Z(e)),i}function je(e,t){return[`${t?``:`
|
|
21
|
+
`}${e.hasRegression?b(`✖`):y(`✔`)} ${e.checkId}:`,...Q(e),...ke(e),``,...Z(e)]}function Me(e,t){let n=t?``:`
|
|
22
|
+
`,r=e.snapshot.items.length;return e.duration===void 0?[`${n}${x(`ℹ`)} ${e.checkId} (${_(r)})`]:[`${n}${x(`ℹ`)} ${e.checkId} (${_(r)}) ${v(J(e.duration))}`]}function Ne(e,t){return e.isInitial?Ae(e,t):e.hasRegression||e.hasImprovement?je(e,t):Me(e,t)}function Pe(e,t,n){return t?g(`✔ Initial baseline created successfully`):e.hasRegression?n?ne(`⚠ Regressions detected (forced)`):`${b(`✗ Regressions detected`)} - Run failed`:e.hasImprovement?`${y(`✔ Improvements detected`)} - Baseline updated`:y(`✔ All checks passed`)}function Fe(e,t){let n={hasAnyInitial:!1,totalImprovements:0,totalInitial:0,totalIssues:0,totalRegressions:0};for(let t of e.results){let e=t.snapshot.items.length;if(n.totalIssues+=e,t.isInitial){n.hasAnyInitial=!0,n.totalInitial+=e;continue}let{hasImprovement:r,hasRegression:i}=t;r&&(n.totalImprovements+=t.removedIssues.length),i&&(n.totalRegressions+=t.newIssues.length)}let r=[` ${v(`Improvements`)} ${y(n.totalImprovements)}`,` ${v(`Regressions`)} ${b(n.totalRegressions)}`,` ${v(`Initial`)} ${g(n.totalInitial)}`,` ${v(`Checks`)} ${e.results.length}`,` ${v(`Issues`)} ${_(n.totalIssues)}`],i=q(e.totalDuration,e.results.length);return e.totalDuration!==void 0&&i!==void 0&&r.push(` ${v(`Duration`)} ${J(e.totalDuration)} ${x(`(avg ${J(i)})`)}`),r.push(``,Pe(e,n.hasAnyInitial,t)),r.join(`
|
|
23
|
+
`)}function Ie(e,t){let n=[];for(let[t,r]of e.results.entries())n.push(...Ne(r,t===0));return n.length>0&&n.push(``),n.push(Fe(e,t)),n.join(`
|
|
24
|
+
`)}const{values:$}=d({allowPositionals:!1,options:{force:{default:!1,short:`f`,type:`boolean`},help:{short:`h`,type:`boolean`},json:{default:!1,type:`boolean`},only:{type:`string`},skip:{type:`string`}},strict:!0});$.help&&(C.log(`
|
|
25
25
|
mejora - Prevent regressions by allowing only improvement
|
|
26
26
|
|
|
27
27
|
Usage:
|
|
@@ -40,4 +40,4 @@ Examples:
|
|
|
40
40
|
mejora --json
|
|
41
41
|
mejora --only "eslint > *"
|
|
42
42
|
mejora --skip typescript
|
|
43
|
-
`),process.exit(0));try{let e=new
|
|
43
|
+
`),process.exit(0));try{let e=new a,t=await n();e.init(t);let r=await new be(e).run(t,{force:$.force,json:$.json,only:$.only,skip:$.skip});$.json?C.log(xe(r)):(C.log(``),C.log(Ie(r,$.force))),process.exit(r.exitCode)}catch(e){e instanceof Error?C.error(e.message):C.error(e),process.exit(2)}export{};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{createRequire as e}from"node:module";import{pathToFileURL as t}from"node:url";import{readFile as n,stat as r,writeFile as i}from"node:fs/promises";import{hash as a}from"node:crypto";var o=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),s=e(import.meta.url),c=o(((e,t)=>{let n=s(`path`),r=s(`fs`),i=s(`os`),a=s(`url`),o=r.promises.readFile;function c(e,t){return[`package.json`,`.${e}rc.json`,`.${e}rc.js`,`.${e}rc.cjs`,...t?[]:[`.${e}rc.mjs`],`.config/${e}rc`,`.config/${e}rc.json`,`.config/${e}rc.js`,`.config/${e}rc.cjs`,...t?[]:[`.config/${e}rc.mjs`],`${e}.config.js`,`${e}.config.cjs`,...t?[]:[`${e}.config.mjs`]]}function l(e){return n.dirname(e)||n.sep}let u=(e,t)=>JSON.parse(t),d=typeof __webpack_require__==`function`?__non_webpack_require__:s,f=Object.freeze({".js":d,".json":d,".cjs":d,noExt:u});t.exports.defaultLoadersSync=f;let p=async e=>{try{return(await import(a.pathToFileURL(e).href)).default}catch(t){try{return d(e)}catch(e){throw e.code===`ERR_REQUIRE_ESM`||e instanceof SyntaxError&&e.toString().includes(`Cannot use import statement outside a module`)?t:e}}},m=Object.freeze({".js":p,".mjs":p,".cjs":p,".json":u,noExt:u});t.exports.defaultLoaders=m;function h(e,t,r){let a={stopDir:i.homedir(),searchPlaces:c(e,r),ignoreEmptySearchPlaces:!0,cache:!0,transform:e=>e,packageProp:[e],...t,loaders:{...r?f:m,...t.loaders}};return a.searchPlaces.forEach(e=>{let t=n.extname(e)||`noExt`,r=a.loaders[t];if(!r)throw Error(`Missing loader for extension "${e}"`);if(typeof r!=`function`)throw Error(`Loader for extension "${e}" is not a function: Received ${typeof r}.`)}),a}function g(e,t){return typeof e==`string`&&e in t?t[e]:(Array.isArray(e)?e:e.split(`.`)).reduce((e,t)=>e===void 0?e:e[t],t)||null}function _(e){if(!e)throw Error(`load must pass a non-empty string`)}function v(e,t){if(!e)throw Error(`No loader specified for extension "${t}"`);if(typeof e!=`function`)throw Error(`loader is not a function`)}let y=e=>(t,n,r)=>(e&&t.set(n,r),r);t.exports.lilconfig=function(e,t){let{ignoreEmptySearchPlaces:i,loaders:a,packageProp:s,searchPlaces:c,stopDir:u,transform:d,cache:f}=h(e,t??{},!1),p=new Map,m=new Map,b=y(f);return{async search(e=process.cwd()){let t={config:null,filepath:``},m=new Set,h=e;dirLoop:for(;;){if(f){let e=p.get(h);if(e!==void 0){for(let t of m)p.set(t,e);return e}m.add(h)}for(let e of c){let c=n.join(h,e);try{await r.promises.access(c)}catch{continue}let l=String(await o(c)),u=n.extname(e)||`noExt`,d=a[u];if(e===`package.json`){let e=g(s,await d(c,l));if(e!=null){t.config=e,t.filepath=c;break dirLoop}continue}let f=l.trim()===``;if(!(f&&i)){f?(t.isEmpty=!0,t.config=void 0):(v(d,u),t.config=await d(c,l)),t.filepath=c;break dirLoop}}if(h===u||h===l(h))break dirLoop;h=l(h)}let _=t.filepath===``&&t.config===null?d(null):d(t);if(f)for(let e of m)p.set(e,_);return _},async load(e){_(e);let t=n.resolve(process.cwd(),e);if(f&&m.has(t))return m.get(t);let{base:r,ext:c}=n.parse(t),l=c||`noExt`,u=a[l];v(u,l);let p=String(await o(t));if(r===`package.json`)return b(m,t,d({config:g(s,await u(t,p)),filepath:t}));let h={config:null,filepath:t},y=p.trim()===``;return y&&i?b(m,t,d({config:void 0,filepath:t,isEmpty:!0})):(h.config=y?void 0:await u(t,p),b(m,t,d(y?{...h,isEmpty:y,config:void 0}:h)))},clearLoadCache(){f&&m.clear()},clearSearchCache(){f&&p.clear()},clearCaches(){f&&(m.clear(),p.clear())}}},t.exports.lilconfigSync=function(e,t){let{ignoreEmptySearchPlaces:i,loaders:a,packageProp:o,searchPlaces:s,stopDir:c,transform:u,cache:d}=h(e,t??{},!0),f=new Map,p=new Map,m=y(d);return{search(e=process.cwd()){let t={config:null,filepath:``},p=new Set,m=e;dirLoop:for(;;){if(d){let e=f.get(m);if(e!==void 0){for(let t of p)f.set(t,e);return e}p.add(m)}for(let e of s){let s=n.join(m,e);try{r.accessSync(s)}catch{continue}let c=n.extname(e)||`noExt`,l=a[c],u=String(r.readFileSync(s));if(e===`package.json`){let e=g(o,l(s,u));if(e!=null){t.config=e,t.filepath=s;break dirLoop}continue}let d=u.trim()===``;if(!(d&&i)){d?(t.isEmpty=!0,t.config=void 0):(v(l,c),t.config=l(s,u)),t.filepath=s;break dirLoop}}if(m===c||m===l(m))break dirLoop;m=l(m)}let h=t.filepath===``&&t.config===null?u(null):u(t);if(d)for(let e of p)f.set(e,h);return h},load(e){_(e);let t=n.resolve(process.cwd(),e);if(d&&p.has(t))return p.get(t);let{base:s,ext:c}=n.parse(t),l=c||`noExt`,f=a[l];v(f,l);let h=String(r.readFileSync(t));if(s===`package.json`)return u({config:g(o,f(t,h)),filepath:t});let y={config:null,filepath:t},b=h.trim()===``;return b&&i?m(p,t,u({filepath:t,config:void 0,isEmpty:!0})):(y.config=b?void 0:f(t,h),m(p,t,u(b?{...y,isEmpty:b,config:void 0}:y)))},clearLoadCache(){d&&p.clear()},clearSearchCache(){d&&f.clear()},clearCaches(){d&&(p.clear(),f.clear())}}}}))();const l=async e=>{let n=await import(t(e).href);return n&&typeof n==`object`&&`default`in n?n.default:n};function u(e){return e}const d=async()=>{let e=await(0,c.lilconfig)(`mejora`,{loaders:{".js":l,".mjs":l,".mts":l,".ts":l},searchPlaces:[`mejora.config.ts`,`mejora.config.mts`,`mejora.config.js`,`mejora.config.mjs`]}).search(process.cwd());if(!e?.config)throw Error(`No configuration file found.`);return e.config},f=/^[A-Za-z]:\//;function p(e=``){return e&&e.replace(/\\/g,`/`).replace(f,e=>e.toUpperCase())}const m=/^[/\\]{2}/,h=/^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/,g=/^[A-Za-z]:$/,_=/^\/([A-Za-z]:)?$/,v=function(e){if(e.length===0)return`.`;e=p(e);let t=e.match(m),n=C(e),r=e[e.length-1]===`/`;return e=S(e,!n),e.length===0?n?`/`:r?`./`:`.`:(r&&(e+=`/`),g.test(e)&&(e+=`/`),t?n?`//${e}`:`//./${e}`:n&&!C(e)?`/${e}`:e)},y=function(...e){let t=``;for(let n of e)if(n)if(t.length>0){let e=t[t.length-1]===`/`,r=n[0]===`/`;e&&r?t+=n.slice(1):t+=e||r?n:`/${n}`}else t+=n;return v(t)};function b(){return typeof process<`u`&&typeof process.cwd==`function`?process.cwd().replace(/\\/g,`/`):`/`}const x=function(...e){e=e.map(e=>p(e));let t=``,n=!1;for(let r=e.length-1;r>=-1&&!n;r--){let i=r>=0?e[r]:b();!i||i.length===0||(t=`${i}/${t}`,n=C(i))}return t=S(t,!n),n&&!C(t)?`/${t}`:t.length>0?t:`.`};function S(e,t){let n=``,r=0,i=-1,a=0,o=null;for(let s=0;s<=e.length;++s){if(s<e.length)o=e[s];else if(o===`/`)break;else o=`/`;if(o===`/`){if(!(i===s-1||a===1))if(a===2){if(n.length<2||r!==2||n[n.length-1]!==`.`||n[n.length-2]!==`.`){if(n.length>2){let e=n.lastIndexOf(`/`);e===-1?(n=``,r=0):(n=n.slice(0,e),r=n.length-1-n.lastIndexOf(`/`)),i=s,a=0;continue}else if(n.length>0){n=``,r=0,i=s,a=0;continue}}t&&(n+=n.length>0?`/..`:`..`,r=2)}else n.length>0?n+=`/${e.slice(i+1,s)}`:n=e.slice(i+1,s),r=s-i-1;i=s,a=0}else o===`.`&&a!==-1?++a:a=-1}return n}const C=function(e){return h.test(e)},w=function(e,t){let n=x(e).replace(_,`$1`).split(`/`),r=x(t).replace(_,`$1`).split(`/`);if(r[0][1]===`:`&&n[0][1]===`:`&&n[0]!==r[0])return r.join(`/`);let i=[...n];for(let e of i){if(r[0]!==e)break;n.shift(),r.shift()}return[...n.map(()=>`..`),...r].join(`/`)},T=function(e){let t=p(e).replace(/\/$/,``).split(`/`).slice(0,-1);return t.length===1&&g.test(t[0])&&(t[0]+=`/`),t.join(`/`)||(C(e)?`/`:`.`)},E=function(e,t){let n=p(e).split(`/`),r=``;for(let e=n.length-1;e>=0;e--){let t=n[e];if(t){r=t;break}}return t&&r.endsWith(t)?r.slice(0,-t.length):r},D=e=>a(`sha256`,e,`hex`)
|
|
1
|
+
import{createRequire as e}from"node:module";import{pathToFileURL as t}from"node:url";import{readFile as n,stat as r,writeFile as i}from"node:fs/promises";import{hash as a}from"node:crypto";var o=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),s=e(import.meta.url),c=o(((e,t)=>{let n=s(`path`),r=s(`fs`),i=s(`os`),a=s(`url`),o=r.promises.readFile;function c(e,t){return[`package.json`,`.${e}rc.json`,`.${e}rc.js`,`.${e}rc.cjs`,...t?[]:[`.${e}rc.mjs`],`.config/${e}rc`,`.config/${e}rc.json`,`.config/${e}rc.js`,`.config/${e}rc.cjs`,...t?[]:[`.config/${e}rc.mjs`],`${e}.config.js`,`${e}.config.cjs`,...t?[]:[`${e}.config.mjs`]]}function l(e){return n.dirname(e)||n.sep}let u=(e,t)=>JSON.parse(t),d=typeof __webpack_require__==`function`?__non_webpack_require__:s,f=Object.freeze({".js":d,".json":d,".cjs":d,noExt:u});t.exports.defaultLoadersSync=f;let p=async e=>{try{return(await import(a.pathToFileURL(e).href)).default}catch(t){try{return d(e)}catch(e){throw e.code===`ERR_REQUIRE_ESM`||e instanceof SyntaxError&&e.toString().includes(`Cannot use import statement outside a module`)?t:e}}},m=Object.freeze({".js":p,".mjs":p,".cjs":p,".json":u,noExt:u});t.exports.defaultLoaders=m;function h(e,t,r){let a={stopDir:i.homedir(),searchPlaces:c(e,r),ignoreEmptySearchPlaces:!0,cache:!0,transform:e=>e,packageProp:[e],...t,loaders:{...r?f:m,...t.loaders}};return a.searchPlaces.forEach(e=>{let t=n.extname(e)||`noExt`,r=a.loaders[t];if(!r)throw Error(`Missing loader for extension "${e}"`);if(typeof r!=`function`)throw Error(`Loader for extension "${e}" is not a function: Received ${typeof r}.`)}),a}function g(e,t){return typeof e==`string`&&e in t?t[e]:(Array.isArray(e)?e:e.split(`.`)).reduce((e,t)=>e===void 0?e:e[t],t)||null}function _(e){if(!e)throw Error(`load must pass a non-empty string`)}function v(e,t){if(!e)throw Error(`No loader specified for extension "${t}"`);if(typeof e!=`function`)throw Error(`loader is not a function`)}let y=e=>(t,n,r)=>(e&&t.set(n,r),r);t.exports.lilconfig=function(e,t){let{ignoreEmptySearchPlaces:i,loaders:a,packageProp:s,searchPlaces:c,stopDir:u,transform:d,cache:f}=h(e,t??{},!1),p=new Map,m=new Map,b=y(f);return{async search(e=process.cwd()){let t={config:null,filepath:``},m=new Set,h=e;dirLoop:for(;;){if(f){let e=p.get(h);if(e!==void 0){for(let t of m)p.set(t,e);return e}m.add(h)}for(let e of c){let c=n.join(h,e);try{await r.promises.access(c)}catch{continue}let l=String(await o(c)),u=n.extname(e)||`noExt`,d=a[u];if(e===`package.json`){let e=g(s,await d(c,l));if(e!=null){t.config=e,t.filepath=c;break dirLoop}continue}let f=l.trim()===``;if(!(f&&i)){f?(t.isEmpty=!0,t.config=void 0):(v(d,u),t.config=await d(c,l)),t.filepath=c;break dirLoop}}if(h===u||h===l(h))break dirLoop;h=l(h)}let _=t.filepath===``&&t.config===null?d(null):d(t);if(f)for(let e of m)p.set(e,_);return _},async load(e){_(e);let t=n.resolve(process.cwd(),e);if(f&&m.has(t))return m.get(t);let{base:r,ext:c}=n.parse(t),l=c||`noExt`,u=a[l];v(u,l);let p=String(await o(t));if(r===`package.json`)return b(m,t,d({config:g(s,await u(t,p)),filepath:t}));let h={config:null,filepath:t},y=p.trim()===``;return y&&i?b(m,t,d({config:void 0,filepath:t,isEmpty:!0})):(h.config=y?void 0:await u(t,p),b(m,t,d(y?{...h,isEmpty:y,config:void 0}:h)))},clearLoadCache(){f&&m.clear()},clearSearchCache(){f&&p.clear()},clearCaches(){f&&(m.clear(),p.clear())}}},t.exports.lilconfigSync=function(e,t){let{ignoreEmptySearchPlaces:i,loaders:a,packageProp:o,searchPlaces:s,stopDir:c,transform:u,cache:d}=h(e,t??{},!0),f=new Map,p=new Map,m=y(d);return{search(e=process.cwd()){let t={config:null,filepath:``},p=new Set,m=e;dirLoop:for(;;){if(d){let e=f.get(m);if(e!==void 0){for(let t of p)f.set(t,e);return e}p.add(m)}for(let e of s){let s=n.join(m,e);try{r.accessSync(s)}catch{continue}let c=n.extname(e)||`noExt`,l=a[c],u=String(r.readFileSync(s));if(e===`package.json`){let e=g(o,l(s,u));if(e!=null){t.config=e,t.filepath=s;break dirLoop}continue}let d=u.trim()===``;if(!(d&&i)){d?(t.isEmpty=!0,t.config=void 0):(v(l,c),t.config=l(s,u)),t.filepath=s;break dirLoop}}if(m===c||m===l(m))break dirLoop;m=l(m)}let h=t.filepath===``&&t.config===null?u(null):u(t);if(d)for(let e of p)f.set(e,h);return h},load(e){_(e);let t=n.resolve(process.cwd(),e);if(d&&p.has(t))return p.get(t);let{base:s,ext:c}=n.parse(t),l=c||`noExt`,f=a[l];v(f,l);let h=String(r.readFileSync(t));if(s===`package.json`)return u({config:g(o,f(t,h)),filepath:t});let y={config:null,filepath:t},b=h.trim()===``;return b&&i?m(p,t,u({filepath:t,config:void 0,isEmpty:!0})):(y.config=b?void 0:f(t,h),m(p,t,u(b?{...y,isEmpty:b,config:void 0}:y)))},clearLoadCache(){d&&p.clear()},clearSearchCache(){d&&f.clear()},clearCaches(){d&&(p.clear(),f.clear())}}}}))();const l=async e=>{let n=await import(t(e).href);return n&&typeof n==`object`&&`default`in n?n.default:n};function u(e){return e}const d=async()=>{let e=await(0,c.lilconfig)(`mejora`,{loaders:{".js":l,".mjs":l,".mts":l,".ts":l},searchPlaces:[`mejora.config.ts`,`mejora.config.mts`,`mejora.config.js`,`mejora.config.mjs`]}).search(process.cwd());if(!e?.config)throw Error(`No configuration file found.`);return e.config},f=/^[A-Za-z]:\//;function p(e=``){return e&&e.replace(/\\/g,`/`).replace(f,e=>e.toUpperCase())}const m=/^[/\\]{2}/,h=/^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/,g=/^[A-Za-z]:$/,_=/^\/([A-Za-z]:)?$/,v=function(e){if(e.length===0)return`.`;e=p(e);let t=e.match(m),n=C(e),r=e[e.length-1]===`/`;return e=S(e,!n),e.length===0?n?`/`:r?`./`:`.`:(r&&(e+=`/`),g.test(e)&&(e+=`/`),t?n?`//${e}`:`//./${e}`:n&&!C(e)?`/${e}`:e)},y=function(...e){let t=``;for(let n of e)if(n)if(t.length>0){let e=t[t.length-1]===`/`,r=n[0]===`/`;e&&r?t+=n.slice(1):t+=e||r?n:`/${n}`}else t+=n;return v(t)};function b(){return typeof process<`u`&&typeof process.cwd==`function`?process.cwd().replace(/\\/g,`/`):`/`}const x=function(...e){e=e.map(e=>p(e));let t=``,n=!1;for(let r=e.length-1;r>=-1&&!n;r--){let i=r>=0?e[r]:b();!i||i.length===0||(t=`${i}/${t}`,n=C(i))}return t=S(t,!n),n&&!C(t)?`/${t}`:t.length>0?t:`.`};function S(e,t){let n=``,r=0,i=-1,a=0,o=null;for(let s=0;s<=e.length;++s){if(s<e.length)o=e[s];else if(o===`/`)break;else o=`/`;if(o===`/`){if(!(i===s-1||a===1))if(a===2){if(n.length<2||r!==2||n[n.length-1]!==`.`||n[n.length-2]!==`.`){if(n.length>2){let e=n.lastIndexOf(`/`);e===-1?(n=``,r=0):(n=n.slice(0,e),r=n.length-1-n.lastIndexOf(`/`)),i=s,a=0;continue}else if(n.length>0){n=``,r=0,i=s,a=0;continue}}t&&(n+=n.length>0?`/..`:`..`,r=2)}else n.length>0?n+=`/${e.slice(i+1,s)}`:n=e.slice(i+1,s),r=s-i-1;i=s,a=0}else o===`.`&&a!==-1?++a:a=-1}return n}const C=function(e){return h.test(e)},w=function(e,t){let n=x(e).replace(_,`$1`).split(`/`),r=x(t).replace(_,`$1`).split(`/`);if(r[0][1]===`:`&&n[0][1]===`:`&&n[0]!==r[0])return r.join(`/`);let i=[...n];for(let e of i){if(r[0]!==e)break;n.shift(),r.shift()}return[...n.map(()=>`..`),...r].join(`/`)},T=function(e){let t=p(e).replace(/\/$/,``).split(`/`).slice(0,-1);return t.length===1&&g.test(t[0])&&(t[0]+=`/`),t.join(`/`)||(C(e)?`/`:`.`)},E=function(e,t){let n=p(e).split(`/`),r=``;for(let e=n.length-1;e>=0;e--){let t=n[e];if(t){r=t;break}}return t&&r.endsWith(t)?r.slice(0,-t.length):r},D=e=>a(`sha256`,e,`hex`);function O(){let e=new WeakSet;return(t,n)=>{if(n&&typeof n==`object`){if(e.has(n))return`[Circular]`;if(e.add(n),!Array.isArray(n)){let e=n,t={};for(let n of Object.keys(e).toSorted()){let r=e[n];typeof r==`function`||typeof r==`symbol`||(t[n]=r)}return t}}return n}}function k(e){return D(JSON.stringify(e??null,O()))}function A(e,t=process.cwd()){return x(t,`node_modules`,`.cache`,`mejora`,e)}async function j(e){try{let t=await n(e,`utf8`);return JSON.parse(t)}catch{return{}}}async function M(e,t){try{await i(e,JSON.stringify(t,null,2),`utf8`)}catch{}}async function N(e){try{let t=await r(e);return`${t.mtimeMs}-${t.size}`}catch{return null}}var P=class{type=`eslint`;async run(e){let{ESLint:t}=await import(`eslint`),n=process.cwd(),r=A(this.type,n),i=k(e),a=new Set;if(e.overrides){let t=Array.isArray(e.overrides)?e.overrides:[e.overrides];for(let e of t)if(e.rules)for(let t of Object.keys(e.rules))a.add(t)}let o=a.size>0,s=await new t({cache:!0,cacheLocation:`${r}/${i}.eslintcache`,overrideConfig:e.overrides,...!o&&{concurrency:e.concurrency??`auto`},...o&&{ruleFilter:({ruleId:e})=>a.has(e)}}).lintFiles(e.files),c=[];for(let{filePath:e,messages:t}of s){let r=w(n,e);for(let{column:e,line:n,message:i,ruleId:a}of t)a&&c.push({column:e,file:r,line:n,message:i,rule:a})}return{items:c,type:`items`}}async setup(){let e=process.cwd(),t=A(this.type,e),{mkdir:n}=await import(`node:fs/promises`);await n(t,{recursive:!0})}async validate(){try{await import(`eslint`)}catch{throw Error(`${this.type} check requires "eslint" package to be installed. Run: npm install eslint`)}}};function F(e){return{type:`eslint`,...e}}function I(e,t){return e.replaceAll(/import\("([^"]+)"\)/g,(e,n)=>{try{if(C(n)){let e=w(t,n);if(!e.startsWith(`..`))return`import("${e||`.`}")`}}catch{}return e})}var L=class{type=`typescript`;async run(e){let{createIncrementalCompilerHost:t,createIncrementalProgram:n,findConfigFile:r,flattenDiagnosticMessageText:i,getPreEmitDiagnostics:a,parseJsonConfigFileContent:o,readConfigFile:s,sys:c,version:l}=await import(`typescript`),u=process.cwd(),d=c.fileExists.bind(c),f=c.readFile.bind(c),p=e.tsconfig?x(e.tsconfig):r(u,d,`tsconfig.json`);if(!p)throw Error(`TypeScript config file not found`);let{config:m,error:h}=s(p,f);if(h){let e=typeof h.messageText==`string`?h.messageText:i(h.messageText,`
|
|
2
2
|
`);throw TypeError(`Failed to read TypeScript config: ${e}`)}let g=o(m,c,u,e.overrides?.compilerOptions),_=x(A(this.type,u),`${k({configPath:p,overrides:e.overrides?.compilerOptions??{},parsedOptions:g.options,typescriptVersion:l})}.tsbuildinfo`),v={...g.options,incremental:!0,noEmit:!0,skipLibCheck:g.options.skipLibCheck??!0,tsBuildInfoFile:_},y=t(v,c),b=y.writeFile.bind(y);y.writeFile=(e,t,...n)=>{x(e)===_&&b(e,t,...n)};let S=n({host:y,options:v,projectReferences:g.projectReferences??[],rootNames:g.fileNames}),C=a(S.getProgram());S.emit();let T=x(u),E=T+`/`,D=C.filter(e=>{if(!e.file)return!0;let t=x(e.file.fileName);return t===T||t.startsWith(E)}),O=[];for(let e of D){let t=i(e.messageText,`
|
|
3
3
|
`),n=`TS${e.code}`;if(e.file&&e.start!==void 0){let{character:r,line:i}=e.file.getLineAndCharacterOfPosition(e.start),a=w(u,e.file.fileName);O.push({column:r+1,file:a,line:i+1,message:I(t,u),rule:n})}else O.push({column:0,file:`(global)`,line:0,message:I(t,u),rule:n})}return{items:O,type:`items`}}async setup(){let e=process.cwd(),t=A(this.type,e),{mkdir:n}=await import(`node:fs/promises`);await n(t,{recursive:!0})}async validate(){try{await import(`typescript`)}catch{throw Error(`${this.type} check requires "typescript" package to be installed. Run: npm install typescript`)}}};function R(e){return{type:`typescript`,...e}}export{k as a,j as c,E as d,T as f,d as g,u as h,F as i,M as l,w as m,R as n,A as o,y as p,P as r,N as s,L as t,D as u};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { u as RawSnapshot } from "../index-Dr3lmWeD.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/workers/check.d.ts
|
|
4
|
+
declare function checkWorker({
|
|
5
|
+
checkId
|
|
6
|
+
}: {
|
|
7
|
+
checkId: string;
|
|
8
|
+
}): Promise<{
|
|
9
|
+
duration: number;
|
|
10
|
+
snapshot: RawSnapshot;
|
|
11
|
+
}>;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { checkWorker as default };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{g as e}from"../typescript-sQ82Cu7A.mjs";import{t}from"../check-registry-DHd4j450.mjs";let n=null,r=null;const i=new Map;async function a({checkId:a}){n||(r??=(async()=>{n=await e()})(),await r);let o=n?.checks[a];if(!o)throw Error(`Check not found in config: ${a}`);let s=i.get(o.type);if(!s){s=new t,s.init(n);let e=new Set([o.type]);await Promise.all([s.setup(e),s.validate(e)]),i.set(o.type,s)}let c=performance.now(),l=await s.get(o.type).run(o);return{duration:performance.now()-c,snapshot:l}}export{a as default};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mejora",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.4",
|
|
4
4
|
"description": "Prevent regressions. Allow improvement.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"regression",
|
|
@@ -36,6 +36,9 @@
|
|
|
36
36
|
"files": [
|
|
37
37
|
"dist"
|
|
38
38
|
],
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"tinypool": "^2.1.0"
|
|
41
|
+
},
|
|
39
42
|
"peerDependencies": {
|
|
40
43
|
"eslint": "^9.34.0",
|
|
41
44
|
"tinyglobby": "^0.2.0",
|