mejora 2.1.0 → 2.2.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 +54 -7
- package/dist/index.d.mts +162 -9
- package/dist/index.mjs +1 -1
- package/dist/run.mjs +18 -18
- package/dist/typescript-ByB3edFF.mjs +3 -0
- package/package.json +1 -1
- package/dist/config-BM38xpP3.mjs +0 -3
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ Snapshots are compared against a baseline.
|
|
|
19
19
|
- New items are regressions and fail the run
|
|
20
20
|
- Removed items are improvements and pass the run
|
|
21
21
|
|
|
22
|
-
Snapshots use the `items` format
|
|
22
|
+
Snapshots use the `items` format to represent issues:
|
|
23
23
|
|
|
24
24
|
```json
|
|
25
25
|
{
|
|
@@ -42,7 +42,7 @@ Snapshots use the `items` format with structured diagnostic information:
|
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
> [!NOTE]
|
|
45
|
-
>
|
|
45
|
+
> Issue identifiers (`id`) are stable across runs and generally insensitive to code movement, while remaining unique for repeated issues.
|
|
46
46
|
|
|
47
47
|
The baseline represents the last accepted state and should be committed to the repository.
|
|
48
48
|
|
|
@@ -156,8 +156,8 @@ The object key is the check identifier and is used in the baseline.
|
|
|
156
156
|
### ESLint
|
|
157
157
|
|
|
158
158
|
- Snapshot type: `"items"`
|
|
159
|
-
- Each lint message is treated as an
|
|
160
|
-
- Regressions are new
|
|
159
|
+
- Each lint message is treated as an issue
|
|
160
|
+
- Regressions are new issues
|
|
161
161
|
|
|
162
162
|
> [!NOTE]
|
|
163
163
|
> `eslint` (^9.34.0) is required as a peer dependency when using the ESLint check
|
|
@@ -165,16 +165,63 @@ The object key is the check identifier and is used in the baseline.
|
|
|
165
165
|
### TypeScript
|
|
166
166
|
|
|
167
167
|
- Snapshot type: `"items"`
|
|
168
|
-
- Each compiler diagnostic is treated as an
|
|
169
|
-
- Regressions are new
|
|
168
|
+
- Each compiler diagnostic is treated as an issue
|
|
169
|
+
- Regressions are new issues
|
|
170
170
|
- Uses the nearest `tsconfig.json` by default, or an explicit one if provided
|
|
171
171
|
|
|
172
172
|
> [!NOTE]
|
|
173
173
|
> `typescript` (^5.0.0) is required as a peer dependency when using the TypeScript check
|
|
174
174
|
|
|
175
|
+
### Custom Checks
|
|
176
|
+
|
|
177
|
+
You can add your own checks by implementing `CheckRunner` and returning an `"items"` snapshot.
|
|
178
|
+
|
|
179
|
+
A custom check is made of two pieces:
|
|
180
|
+
|
|
181
|
+
- A **runner** (registered in `runners`) that knows how to execute your check type
|
|
182
|
+
- A **check config** (declared in `checks`) that includes a matching `type` and any options your runner needs
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
import type { CheckRunner, IssueInput } from "mejora";
|
|
186
|
+
|
|
187
|
+
interface TodoCheckConfig {
|
|
188
|
+
files: string[];
|
|
189
|
+
patterns?: string[];
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
class TodoCheckRunner implements CheckRunner {
|
|
193
|
+
readonly type = "todo";
|
|
194
|
+
|
|
195
|
+
async run(config: TodoCheckConfig) {
|
|
196
|
+
const items: IssueInput[] = [];
|
|
197
|
+
|
|
198
|
+
// ...produce IssueInput entries (file/line/column/rule/message)
|
|
199
|
+
|
|
200
|
+
return { type: "items", items };
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Register the runner and declare a check that uses it:
|
|
206
|
+
|
|
207
|
+
```ts
|
|
208
|
+
import { defineConfig } from "mejora";
|
|
209
|
+
|
|
210
|
+
export default defineConfig({
|
|
211
|
+
runners: [new TodoCheckRunner()],
|
|
212
|
+
checks: {
|
|
213
|
+
"todo-comments": {
|
|
214
|
+
type: "todo",
|
|
215
|
+
files: ["src/**/*.ts"],
|
|
216
|
+
patterns: ["TODO", "FIXME"],
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
});
|
|
220
|
+
```
|
|
221
|
+
|
|
175
222
|
## CI
|
|
176
223
|
|
|
177
|
-
When running in CI, mejora does not write the baseline.
|
|
224
|
+
When running in CI, `mejora` does not write the baseline.
|
|
178
225
|
|
|
179
226
|
Instead, it compares the committed baseline to the expected results from the current codebase.
|
|
180
227
|
|
package/dist/index.d.mts
CHANGED
|
@@ -4,7 +4,54 @@ import * as typescript0 from "typescript";
|
|
|
4
4
|
import { CompilerOptions } from "typescript";
|
|
5
5
|
|
|
6
6
|
//#region src/types.d.ts
|
|
7
|
-
|
|
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
|
+
}
|
|
8
55
|
/**
|
|
9
56
|
* Configuration for an ESLint check.
|
|
10
57
|
*
|
|
@@ -90,11 +137,14 @@ interface TypeScriptCheckConfig {
|
|
|
90
137
|
*/
|
|
91
138
|
tsconfig?: string;
|
|
92
139
|
}
|
|
93
|
-
type
|
|
140
|
+
type CustomCheckConfig = Record<string, unknown> & {
|
|
141
|
+
type: string;
|
|
142
|
+
};
|
|
143
|
+
type CheckConfig$1 = (ESLintCheckConfig & {
|
|
94
144
|
type: "eslint";
|
|
95
145
|
}) | (TypeScriptCheckConfig & {
|
|
96
146
|
type: "typescript";
|
|
97
|
-
});
|
|
147
|
+
}) | CustomCheckConfig;
|
|
98
148
|
/**
|
|
99
149
|
* mejora configuration.
|
|
100
150
|
*
|
|
@@ -138,14 +188,87 @@ interface Config {
|
|
|
138
188
|
* ```ts
|
|
139
189
|
* {
|
|
140
190
|
* "eslint > no-console": eslint({ ... }),
|
|
141
|
-
* "typescript":
|
|
191
|
+
* "typescript": typescriptCheck({ ... }),
|
|
192
|
+
* }
|
|
193
|
+
* ```
|
|
194
|
+
*/
|
|
195
|
+
checks: Record<string, CheckConfig$1>;
|
|
196
|
+
/**
|
|
197
|
+
* Runners to register custom check types.
|
|
198
|
+
*
|
|
199
|
+
* Built-in checks (eslint, typescript) are always available.
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```ts
|
|
203
|
+
* {
|
|
204
|
+
* runners: [myCustomRunner()],
|
|
205
|
+
* checks: {
|
|
206
|
+
* "custom": myCheck({ ... })
|
|
207
|
+
* }
|
|
142
208
|
* }
|
|
143
209
|
* ```
|
|
144
210
|
*/
|
|
145
|
-
|
|
211
|
+
runners?: CheckRunner[];
|
|
212
|
+
}
|
|
213
|
+
//#endregion
|
|
214
|
+
//#region src/check-runner.d.ts
|
|
215
|
+
/**
|
|
216
|
+
* Interface that all check runners must implement.
|
|
217
|
+
*
|
|
218
|
+
* Each check type (eslint, typescript, custom) implements this interface
|
|
219
|
+
* to provide consistent lifecycle hooks for execution.
|
|
220
|
+
*/
|
|
221
|
+
interface CheckRunner<TConfig = unknown> {
|
|
222
|
+
/**
|
|
223
|
+
* Execute the check and return a snapshot of issues.
|
|
224
|
+
*
|
|
225
|
+
* @param config - Check-specific configuration
|
|
226
|
+
*
|
|
227
|
+
* @returns Snapshot containing all issues found
|
|
228
|
+
*/
|
|
229
|
+
run(config: TConfig): Promise<RawSnapshot>;
|
|
230
|
+
/**
|
|
231
|
+
* Setup any infrastructure needed for this check.
|
|
232
|
+
* Called once during runner setup, in parallel with other checks.
|
|
233
|
+
*
|
|
234
|
+
* Examples: creating cache directories, initializing compilation state.
|
|
235
|
+
*
|
|
236
|
+
* Optional - not all checks need infrastructure setup.
|
|
237
|
+
*/
|
|
238
|
+
setup?(): Promise<void>;
|
|
239
|
+
/**
|
|
240
|
+
* Unique identifier for this check type.
|
|
241
|
+
* Must match the `type` field in CheckConfig.
|
|
242
|
+
*
|
|
243
|
+
* @example "eslint"
|
|
244
|
+
*
|
|
245
|
+
* @example "typescript"
|
|
246
|
+
*/
|
|
247
|
+
readonly type: string;
|
|
248
|
+
/**
|
|
249
|
+
* Validate that all dependencies for this check are available.
|
|
250
|
+
* Called once during runner setup before any checks execute.
|
|
251
|
+
*
|
|
252
|
+
* Should throw a descriptive error if dependencies are missing.
|
|
253
|
+
*
|
|
254
|
+
* @throws {Error} If required dependencies are not installed
|
|
255
|
+
*/
|
|
256
|
+
validate?(): Promise<void>;
|
|
146
257
|
}
|
|
147
258
|
//#endregion
|
|
148
|
-
//#region src/
|
|
259
|
+
//#region src/runners/eslint.d.ts
|
|
260
|
+
/**
|
|
261
|
+
* Check runner for ESLint.
|
|
262
|
+
*/
|
|
263
|
+
declare class ESLintCheckRunner implements CheckRunner {
|
|
264
|
+
readonly type = "eslint";
|
|
265
|
+
run(eslintConfig: ESLintCheckConfig): Promise<{
|
|
266
|
+
items: IssueInput[];
|
|
267
|
+
type: "items";
|
|
268
|
+
}>;
|
|
269
|
+
setup(): Promise<void>;
|
|
270
|
+
validate(): Promise<void>;
|
|
271
|
+
}
|
|
149
272
|
/**
|
|
150
273
|
* Create an ESLint check configuration.
|
|
151
274
|
*
|
|
@@ -160,7 +283,19 @@ declare function eslintCheck(config: ESLintCheckConfig): {
|
|
|
160
283
|
type: "eslint";
|
|
161
284
|
};
|
|
162
285
|
//#endregion
|
|
163
|
-
//#region src/
|
|
286
|
+
//#region src/runners/typescript.d.ts
|
|
287
|
+
/**
|
|
288
|
+
* Check runner for TypeScript.
|
|
289
|
+
*/
|
|
290
|
+
declare class TypeScriptCheckRunner implements CheckRunner {
|
|
291
|
+
readonly type = "typescript";
|
|
292
|
+
run(typescriptConfig: TypeScriptCheckConfig): Promise<{
|
|
293
|
+
items: IssueInput[];
|
|
294
|
+
type: "items";
|
|
295
|
+
}>;
|
|
296
|
+
setup(): Promise<void>;
|
|
297
|
+
validate(): Promise<void>;
|
|
298
|
+
}
|
|
164
299
|
/**
|
|
165
300
|
* Create a TypeScript check configuration.
|
|
166
301
|
*
|
|
@@ -177,13 +312,31 @@ declare function typescriptCheck(config: TypeScriptCheckConfig): {
|
|
|
177
312
|
};
|
|
178
313
|
//#endregion
|
|
179
314
|
//#region src/config.d.ts
|
|
315
|
+
type ExtractRunnerByType<TRunners extends readonly CheckRunner[], TType extends string> = Extract<TRunners[number], {
|
|
316
|
+
type: TType;
|
|
317
|
+
}>;
|
|
318
|
+
type ExtractConfig<TRunner> = TRunner extends CheckRunner<infer C> ? C : never;
|
|
319
|
+
type CheckConfig<TRunners extends readonly CheckRunner[], TType extends TRunners[number]["type"]> = ExtractConfig<ExtractRunnerByType<TRunners, TType>> & {
|
|
320
|
+
type: TType;
|
|
321
|
+
};
|
|
322
|
+
type InternalRunners = readonly [ESLintCheckRunner, TypeScriptCheckRunner];
|
|
180
323
|
/**
|
|
181
324
|
* Define mejora configuration.
|
|
182
325
|
*
|
|
183
326
|
* @param config - mejora configuration object.
|
|
184
327
|
*
|
|
328
|
+
* @param config.runners - Optional array of custom check runners to register.
|
|
329
|
+
*
|
|
330
|
+
* @param config.checks - Map of check names to their configurations.
|
|
331
|
+
*
|
|
185
332
|
* @returns The provided configuration object.
|
|
186
333
|
*/
|
|
187
|
-
declare
|
|
334
|
+
declare function defineConfig<const TRunners extends readonly CheckRunner[]>(config: {
|
|
335
|
+
checks: Record<string, CheckConfig<[...InternalRunners, ...TRunners], [...InternalRunners, ...TRunners][number]["type"]>>;
|
|
336
|
+
runners?: TRunners;
|
|
337
|
+
}): {
|
|
338
|
+
checks: Record<string, CheckConfig<[...InternalRunners, ...TRunners], [...InternalRunners, ...TRunners][number]["type"]>>;
|
|
339
|
+
runners?: TRunners;
|
|
340
|
+
};
|
|
188
341
|
//#endregion
|
|
189
|
-
export { type Config, defineConfig, eslintCheck as eslint, eslintCheck, typescriptCheck as typescript, typescriptCheck };
|
|
342
|
+
export { type CheckRunner, type Config, type Issue, type IssueInput, type RawSnapshot, type Snapshot, defineConfig, eslintCheck as eslint, eslintCheck, typescriptCheck as typescript, typescriptCheck };
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{i as e,l as t,n}from"./typescript-ByB3edFF.mjs";export{t as defineConfig,e as eslint,e as eslintCheck,n as typescript,n as typescriptCheck};
|
package/dist/run.mjs
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{
|
|
3
|
-
`,r=e.snapshot.items.length,i=[`${n}${
|
|
4
|
-
`}${e.hasRegression?
|
|
5
|
-
`,r=e.snapshot.items.length;return e.duration===void 0?[`${n}${
|
|
6
|
-
`)}function A(e,t){let n=[];for(let[t,r]of e.results.entries())n.push(...
|
|
2
|
+
import{a as e,c as t,o as n,r,s as i,t as a,u as o}from"./typescript-ByB3edFF.mjs";import{inspect as s,parseArgs as c,styleText as l}from"node:util";import{mkdir as u,readFile as d,writeFile as f}from"node:fs/promises";import{env as p}from"node:process";var m=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)}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],i=e?.();i&&n.push(i)}await Promise.all(n)}};function h(e,t){if(!(e===void 0||t===0))return e/t}function g(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:h(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)}const _=e=>t=>l(e,typeof t==`number`?t.toString():t),v=_(`blue`),y=_(`bold`),b=_(`cyan`),x=_(`dim`),S=_(`green`),C=_(`red`),w=_(`gray`),ee=_(`underline`),te=_(`yellow`);function ne(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 T(e){let t=Math.round(e);return t<1?`<1ms`:ne(t)}function E(e,t){return e===1?t:`${t}s`}const D=` `,re=`${D} `;function ie(e){return e===`initial`?x(`→`):e===`improvement`?S(`↑`):C(`↓`)}function ae(e,t,r){let a=i(e),o=n(e),s=t>0?`:${t}:${r>0?r:1}`:``;return`${a===`.`?``:x(`${a}/`)}${ee(o)}${s?x(s):``}`}function oe(e,t){return[`${ie(t)} ${ae(e.file,e.line,e.column)} ${x(e.rule)}`,e.message]}function O(e,t){let n=[],r=e.slice(0,10);for(let e of r){let[r,i]=oe(e,t);n.push(`${D}${r}`,`${re}${i}`)}let i=e.length-r.length;return i>0&&n.push(`${D}${x(`... and ${i} more`)}`),n}function se(e){return e===void 0?[]:[` ${x(`Duration`)} ${T(e)}`]}function ce(e){return[` ${x(`Issues`)} ${y(e)}`]}function k(e){return[...se(e.duration),...ce(e.snapshot.items.length)]}function le(e){if(!e.hasRegression)return[];let t=e.newIssues.length;return[` ${C(t)} new ${E(t,`issue`)} (${E(t,`regression`)}):`,...O(e.newIssues,`regression`)]}function ue(e){if(!e.hasImprovement)return[];let t=e.removedIssues.length;return[` ${S(t)} ${E(t,`issue`)} fixed (${E(t,`improvement`)}):`,...O(e.removedIssues,`improvement`)]}function de(e,t){let n=t?``:`
|
|
3
|
+
`,r=e.snapshot.items.length,i=[`${n}${v(`ℹ`)} ${e.checkId}:`,` Initial baseline created with ${v(r)} ${E(r,`issue`)}`];return e.snapshot.items.length>0&&i.push(...O(e.snapshot.items,`initial`)),i.push(``,...k(e)),i}function fe(e,t){return[`${t?``:`
|
|
4
|
+
`}${e.hasRegression?C(`✖`):S(`✔`)} ${e.checkId}:`,...le(e),...ue(e),``,...k(e)]}function pe(e,t){let n=t?``:`
|
|
5
|
+
`,r=e.snapshot.items.length;return e.duration===void 0?[`${n}${w(`ℹ`)} ${e.checkId} (${y(r)})`]:[`${n}${w(`ℹ`)} ${e.checkId} (${y(r)}) ${x(T(e.duration))}`]}function me(e,t){return e.isInitial?de(e,t):e.hasRegression||e.hasImprovement?fe(e,t):pe(e,t)}function he(e,t,n){return t?v(`✔ Initial baseline created successfully`):e.hasRegression?n?te(`⚠ Regressions detected (forced)`):`${C(`✗ Regressions detected`)} - Run failed`:e.hasImprovement?`${S(`✔ Improvements detected`)} - Baseline updated`:S(`✔ All checks passed`)}function ge(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=[` ${x(`Improvements`)} ${S(n.totalImprovements)}`,` ${x(`Regressions`)} ${C(n.totalRegressions)}`,` ${x(`Initial`)} ${v(n.totalInitial)}`,` ${x(`Checks`)} ${e.results.length}`,` ${x(`Issues`)} ${y(n.totalIssues)}`],i=h(e.totalDuration,e.results.length);return e.totalDuration!==void 0&&i!==void 0&&r.push(` ${x(`Duration`)} ${T(e.totalDuration)} ${w(`(avg ${T(i)})`)}`),r.push(``,he(e,n.hasAnyInitial,t)),r.join(`
|
|
6
|
+
`)}function A(e,t){let n=[];for(let[t,r]of e.results.entries())n.push(...me(r,t===0));return n.length>0&&n.push(``),n.push(ge(e,t)),n.join(`
|
|
7
7
|
`)}const j=e=>e in p&&p[e]!==`0`&&p[e]!==`false`;var M=j(`CI`)||j(`CONTINUOUS_INTEGRATION`);function N(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 P(e,t){return`${e}${`
|
|
8
|
-
}`.repeat(t)}`}function F(e){let t=(e.match(/\{/g)?.length??0)-(e.match(/\}/g)?.length??0);return t===0?e:t<0?N(e,-t):P(e,t)}function I(e){try{return JSON.parse(e)}catch{return}}function L(e){let t=e.trim();return t.endsWith(`,`)?t.slice(0,-1):t}function
|
|
8
|
+
}`.repeat(t)}`}function F(e){let t=(e.match(/\{/g)?.length??0)-(e.match(/\}/g)?.length??0);return t===0?e:t<0?N(e,-t):P(e,t)}function I(e){try{return JSON.parse(e)}catch{return}}function L(e){let t=e.trim();return t.endsWith(`,`)?t.slice(0,-1):t}function _e(e){return`{
|
|
9
9
|
"version": 2,
|
|
10
10
|
${L(e)}
|
|
11
|
-
}`}function
|
|
12
|
-
`)}function
|
|
13
|
-
`)}function
|
|
14
|
-
`);let a=
|
|
15
|
-
`)}function
|
|
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,n,r){let i=t(n,e);return r?`${i}#L${r}`: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){let t=[`\n### Other Issues (${e.length})\n`];for(let n of e)t.push(`- ${n.rule}: ${V(n.message)}`);return t.push(``),t.join(`
|
|
12
|
+
`)}function we(e,t){if(e.filePath===B)return Ce(e.items);let n=H(e.filePath,t),r=[`\n### ${U(e.filePath,n)} (${e.items.length})\n`];for(let n of e.items)r.push(xe(n,t));return r.push(``),r.join(`
|
|
13
|
+
`)}function Te(e,t,n){let r=t.length,i=[`\n## ${e} (${r} ${E(r,`issue`)})\n`];if(t.length===0)return i.push(`No issues`),i.join(`
|
|
14
|
+
`);let a=Se(t);for(let e of a)i.push(we(e,n));return i.join(`
|
|
15
|
+
`)}function Ee(e){return`${e.replaceAll(/\n{3,}/g,`
|
|
16
16
|
|
|
17
|
-
`).trimEnd()}\n`}function
|
|
17
|
+
`).trimEnd()}\n`}function W(e,t){let n=[`<!-- prettier-ignore-start -->
|
|
18
18
|
`,`# 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
|
-
`).slice(1).map(e=>
|
|
19
|
+
`,`This file represents the current accepted state of the codebase.`];for(let[r,{items:i=[]}]of Object.entries(e.checks))n.push(Te(r,i,t));return n.push(`
|
|
20
|
+
<!-- prettier-ignore-end -->`),Ee(n.join(`
|
|
21
|
+
`))}const De=(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 Oe(e){let t=[e.message];if(e.stack){let n=e.stack.split(`
|
|
22
|
+
`).slice(1).map(e=>x(e.trim())).join(`
|
|
23
23
|
`);t.push(n)}return t.join(`
|
|
24
|
-
`)}function
|
|
24
|
+
`)}function G(...e){return e.map(e=>typeof e==`string`?e:e instanceof Error?Oe(e):s(e,{colors:!1,depth:10})).join(` `)}const K={error:(...e)=>{console.error(C(`✖`),G(...e))},log:(...e)=>{console.log(G(...e))},start:(...e)=>{console.log(b(`◐`),G(...e))},success:(...e)=>{console.log(S(`✔`),G(...e))}};var q=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 De(r,a)?i:{...i,checks:{...i.checks,[n]:r}}}async load(){try{let e=await d(this.baselinePath,`utf8`);if(e.includes(`<<<<<<<`)){K.start(`Merge conflict detected in baseline, auto-resolving...`);let t=be(e);return await this.save(t,!0),K.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,t=!1){if(M&&!t)return;let n=`${JSON.stringify(e,null,2)}\n`,r=this.baselinePath.replace(`.json`,`.md`),a=W(e,i(this.baselinePath));await u(i(this.baselinePath),{recursive:!0}),await Promise.all([f(this.baselinePath,n,`utf8`),f(r,a,`utf8`)])}async resolveMarkdownConflictIfNeeded(e){let t=this.baselinePath.replace(`.json`,`.md`);try{(await d(t,`utf8`)).includes(`<<<<<<<`)&&(K.start(`Merge conflict detected in markdown report, regenerating...`),await f(t,W(JSON.parse(e),i(this.baselinePath)),`utf8`),K.success(`Markdown report regenerated`))}catch{}}};function ke(){return{hasImprovement:!1,hasRegression:!1,hasRelocation:!1,isInitial:!0,newIssues:[],removedIssues:[]}}function Ae(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 J(e=[]){return new Map(e.map(e=>[e.id,e]))}function Y(e){return new Set(e.keys())}function X(e,t){let n=[];for(let r of t){let t=e.get(r);n.push(t)}return n}function je(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 Me(e,t){let n=J(e.items),r=J(t.items),i=Y(n),a=Y(r),o=i.difference(a),s=a.difference(i);return Ae(X(n,o),X(r,s),i.size>o.size?je(n,r):!1)}function Z(e,t){return t?Me(e,t):ke()}function Q(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 Ne(t){let n=Map.groupBy(t,e=>e.signature),r=[];for(let[t,i]of n){i.sort(Q);for(let[n,{signature:a,...o}]of i.entries())r.push({...o,id:e(`${t}:${n}`)})}return r}function Pe(e){return{items:Ne(e.items.map(e=>({...e,signature:`${e.file} - ${e.rule}: ${e.message}`}))).toSorted(Q),type:`items`}}var Fe=class e{baselineManager;registry;constructor(e,t){this.registry=e,this.baselineManager=new q(t)}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);try{let e=m.getRequiredTypes(a);await Promise.all([this.registry.setup(e),this.registry.validate(e)])}catch(e){return K.error(`Setup failed:`,e),{exitCode:2,hasImprovement:!1,hasRegression:!0,results:[],totalDuration:performance.now()-r}}let o=Object.keys(a).length;K.start(`Running ${o} check${o===1?``:`s`}...`);let s=await this.executeChecks(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=q.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 executeChecks(e,t){let n=Object.entries(e).map(async([e,n])=>{try{let r=performance.now(),i=await this.registry.get(n.type).run(n),a=performance.now()-r,o=Pe(i),s=q.getEntry(t,e),c=Z(o,s);return{baseline:s,checkId:e,duration:a,hasImprovement:c.hasImprovement,hasRegression:c.hasRegression,hasRelocation:c.hasRelocation,isInitial:c.isInitial,newIssues:c.newIssues,removedIssues:c.removedIssues,snapshot:o}}catch(t){throw K.error(`Error running check "${e}":`,t),t}});try{return await Promise.all(n)}catch{return null}}};const{values:$}=c({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&&(K.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 m;e.register(new r),e.register(new a);let t=await o();if(t.runners)for(let n of t.runners)e.register(n);let n=await new Fe(e).run(t,{force:$.force,json:$.json,only:$.only,skip:$.skip});$.json?K.log(g(n)):(K.log(``),K.log(A(n,$.force))),process.exit(n.exitCode)}catch(e){e instanceof Error?K.error(e.message):K.error(e),process.exit(2)}export{};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{createRequire as e}from"node:module";import{pathToFileURL as t}from"node:url";import{hash as n}from"node:crypto";var r=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),i=e(import.meta.url),a=r(((e,t)=>{let n=i(`path`),r=i(`fs`),a=i(`os`),o=i(`url`),s=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__:i,f=Object.freeze({".js":d,".json":d,".cjs":d,noExt:u});t.exports.defaultLoadersSync=f;let p=async e=>{try{return(await import(o.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 i={stopDir:a.homedir(),searchPlaces:c(e,r),ignoreEmptySearchPlaces:!0,cache:!0,transform:e=>e,packageProp:[e],...t,loaders:{...r?f:m,...t.loaders}};return i.searchPlaces.forEach(e=>{let t=n.extname(e)||`noExt`,r=i.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}.`)}),i}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:o,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 s(c)),u=n.extname(e)||`noExt`,d=a[u];if(e===`package.json`){let e=g(o,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 s(t));if(r===`package.json`)return b(m,t,d({config:g(o,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 o=async e=>{let n=await import(t(e).href);return n&&typeof n==`object`&&`default`in n?n.default:n};function s(e){return e}const c=async()=>{let e=await(0,a.lilconfig)(`mejora`,{loaders:{".js":o,".mjs":o,".mts":o,".ts":o},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},l=/^[A-Za-z]:\//;function u(e=``){return e&&e.replace(/\\/g,`/`).replace(l,e=>e.toUpperCase())}const d=/^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/,f=/^[A-Za-z]:$/,p=/^\/([A-Za-z]:)?$/;function m(){return typeof process<`u`&&typeof process.cwd==`function`?process.cwd().replace(/\\/g,`/`):`/`}const h=function(...e){e=e.map(e=>u(e));let t=``,n=!1;for(let r=e.length-1;r>=-1&&!n;r--){let i=r>=0?e[r]:m();!i||i.length===0||(t=`${i}/${t}`,n=_(i))}return t=g(t,!n),n&&!_(t)?`/${t}`:t.length>0?t:`.`};function g(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 _=function(e){return d.test(e)},v=function(e,t){let n=h(e).replace(p,`$1`).split(`/`),r=h(t).replace(p,`$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(`/`)},y=function(e){let t=u(e).replace(/\/$/,``).split(`/`).slice(0,-1);return t.length===1&&f.test(t[0])&&(t[0]+=`/`),t.join(`/`)||(_(e)?`/`:`.`)},b=function(e,t){let n=u(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},x=e=>n(`sha256`,e,`hex`),S=(e,t)=>{if(t&&typeof t==`object`&&!Array.isArray(t)){let e=t,n={};for(let t of Object.keys(e).toSorted())n[t]=e[t];return n}return t};function C(e){return x(JSON.stringify(e??null,S))}function w(e,t=process.cwd()){return h(t,`node_modules`,`.cache`,`mejora`,e)}var T=class{type=`eslint`;async run(e){let{ESLint:t}=await import(`eslint`),n=process.cwd(),r=await new t({cache:!0,cacheLocation:`${w(this.type,n)}/${C(e)}.eslintcache`,concurrency:e.concurrency??`auto`,overrideConfig:e.overrides}).lintFiles(e.files),i=[];for(let{filePath:e,messages:t}of r){let r=v(n,e);for(let{column:e,line:n,message:a,ruleId:o}of t)o&&i.push({column:e,file:r,line:n,message:a,rule:o})}return{items:i,type:`items`}}async setup(){let e=process.cwd(),t=w(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 E(e){return{type:`eslint`,...e}}var D=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?h(e.tsconfig):r(u,d,`tsconfig.json`);if(!p)throw Error(`TypeScript config file not found`);let{config:m,error:g}=s(p,f);if(g){let e=typeof g.messageText==`string`?g.messageText:i(g.messageText,`
|
|
2
|
+
`);throw TypeError(`Failed to read TypeScript config: ${e}`)}let _=o(m,c,u,e.overrides?.compilerOptions),y=h(w(this.type,u),`${C({configPath:p,overrides:e.overrides?.compilerOptions??{},parsedOptions:_.options,typescriptVersion:l})}.tsbuildinfo`),b={..._.options,incremental:!0,noEmit:!0,skipLibCheck:_.options.skipLibCheck??!0,tsBuildInfoFile:y},x=t(b,c),S=x.writeFile.bind(x);x.writeFile=(e,t,...n)=>{h(e)===y&&S(e,t,...n)};let T=n({host:x,options:b,projectReferences:_.projectReferences??[],rootNames:_.fileNames}),E=a(T.getProgram());T.emit();let D=h(u),O=D+`/`,k=E.filter(e=>{if(!e.file)return!0;let t=h(e.file.fileName);return t===D||t.startsWith(O)}),A=[];for(let e of k){let t=i(e.messageText,`
|
|
3
|
+
`),n=`TS${e.code}`;if(e.file&&e.start!==void 0){let{character:r,line:i}=e.file.getLineAndCharacterOfPosition(e.start),a=v(u,e.file.fileName);A.push({column:r+1,file:a,line:i+1,message:t,rule:n})}else A.push({column:0,file:`(global)`,line:0,message:t,rule:n})}return{items:A,type:`items`}}async setup(){let e=process.cwd(),t=w(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 O(e){return{type:`typescript`,...e}}export{x as a,v as c,E as i,s as l,O as n,b as o,T as r,y as s,D as t,c as u};
|
package/package.json
CHANGED
package/dist/config-BM38xpP3.mjs
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import{createRequire as e}from"node:module";import{hash as t}from"node:crypto";import{pathToFileURL as n}from"node:url";var r=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),i=e(import.meta.url);const a=/^[A-Za-z]:\//;function o(e=``){return e&&e.replace(/\\/g,`/`).replace(a,e=>e.toUpperCase())}const s=/^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/,c=/^[A-Za-z]:$/,l=/^\/([A-Za-z]:)?$/;function u(){return typeof process<`u`&&typeof process.cwd==`function`?process.cwd().replace(/\\/g,`/`):`/`}const d=function(...e){e=e.map(e=>o(e));let t=``,n=!1;for(let r=e.length-1;r>=-1&&!n;r--){let i=r>=0?e[r]:u();!i||i.length===0||(t=`${i}/${t}`,n=p(i))}return t=f(t,!n),n&&!p(t)?`/${t}`:t.length>0?t:`.`};function f(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 p=function(e){return s.test(e)},m=function(e,t){let n=d(e).replace(l,`$1`).split(`/`),r=d(t).replace(l,`$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(`/`)},h=function(e){let t=o(e).replace(/\/$/,``).split(`/`).slice(0,-1);return t.length===1&&c.test(t[0])&&(t[0]+=`/`),t.join(`/`)||(p(e)?`/`:`.`)},g=function(e,t){let n=o(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},_=e=>t(`sha256`,e,`hex`);function v(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 y(e){let t=Map.groupBy(e,e=>e.signature),n=[];for(let[e,r]of t){r.sort(v);for(let[t,i]of r.entries()){let{signature:r,...a}=i;n.push({...a,id:_(`${e}:${t}`)})}}return n}const b=(e,t)=>{if(t&&typeof t==`object`&&!Array.isArray(t)){let e=t,n={};for(let t of Object.keys(e).toSorted())n[t]=e[t];return n}return t};function x(e){return _(JSON.stringify(e??null,b))}function S(e,t=process.cwd()){return d(t,`node_modules`,`.cache`,`mejora`,e)}async function C(e){let{ESLint:t}=await import(`eslint`),n=process.cwd(),r=await new t({cache:!0,cacheLocation:`${S(`eslint`,n)}/${x(e)}.eslintcache`,concurrency:e.concurrency??`auto`,overrideConfig:e.overrides}).lintFiles(e.files),i=[];for(let{filePath:e,messages:t}of r){let r=m(n,e);for(let{column:e,line:n,message:a,ruleId:o}of t){if(!o)continue;let t=`${r} - ${o}: ${a}`;i.push({column:e,file:r,line:n,message:a,rule:o,signature:t})}}return{items:y(i).toSorted(v),type:`items`}}function w(e){return{type:`eslint`,...e}}const T=`(global)`;async function E(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(),f=c.fileExists.bind(c),p=c.readFile.bind(c),h=e.tsconfig?d(e.tsconfig):r(u,f,`tsconfig.json`);if(!h)throw Error(`TypeScript config file not found`);let{config:g,error:_}=s(h,p);if(_){let e=typeof _.messageText==`string`?_.messageText:i(_.messageText,`
|
|
2
|
-
`);throw TypeError(`Failed to read TypeScript config: ${e}`)}let b=o(g,c,u,e.overrides?.compilerOptions),C=d(S(`typescript`,u),`${x({configPath:h,overrides:e.overrides?.compilerOptions??{},parsedOptions:b.options,typescriptVersion:l})}.tsbuildinfo`),w={...b.options,incremental:!0,noEmit:!0,skipLibCheck:b.options.skipLibCheck??!0,tsBuildInfoFile:C},E=t(w,c),D=E.writeFile.bind(E);E.writeFile=(e,t,...n)=>{d(e)===C&&D(e,t,...n)};let O=n({host:E,options:w,projectReferences:b.projectReferences??[],rootNames:b.fileNames}),k=a(O.getProgram());O.emit();let A=d(u),j=A+`/`,M=k.filter(e=>{if(!e.file)return!0;let t=d(e.file.fileName);return t===A||t.startsWith(j)}),N=[];for(let e of M){let t=i(e.messageText,`
|
|
3
|
-
`),n=`TS${e.code}`;if(e.file&&e.start!==void 0){let{character:r,line:i}=e.file.getLineAndCharacterOfPosition(e.start),a=m(u,e.file.fileName),o=`${a} - ${n}: ${t}`;N.push({column:r+1,file:a,line:i+1,message:t,rule:n,signature:o})}else{let e=`${T} - ${n}: ${t}`;N.push({column:0,file:T,line:0,message:t,rule:n,signature:e})}}return{items:y(N).toSorted(v),type:`items`}}function D(e){return{type:`typescript`,...e}}var O=r(((e,t)=>{let n=i(`path`),r=i(`fs`),a=i(`os`),o=i(`url`),s=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__:i,f=Object.freeze({".js":d,".json":d,".cjs":d,noExt:u});t.exports.defaultLoadersSync=f;let p=async e=>{try{return(await import(o.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 i={stopDir:a.homedir(),searchPlaces:c(e,r),ignoreEmptySearchPlaces:!0,cache:!0,transform:e=>e,packageProp:[e],...t,loaders:{...r?f:m,...t.loaders}};return i.searchPlaces.forEach(e=>{let t=n.extname(e)||`noExt`,r=i.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}.`)}),i}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:o,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 s(c)),u=n.extname(e)||`noExt`,d=a[u];if(e===`package.json`){let e=g(o,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 s(t));if(r===`package.json`)return b(m,t,d({config:g(o,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 k=async e=>{let t=await import(n(e).href);return t&&typeof t==`object`&&`default`in t?t.default:t},A=e=>e,j=async()=>{let e=await(0,O.lilconfig)(`mejora`,{loaders:{".js":k,".mjs":k,".mts":k,".ts":k},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};export{w as a,h as c,D as i,m as l,j as n,C as o,E as r,g as s,A as t,d as u};
|