mejora 2.2.2 → 2.3.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 CHANGED
@@ -125,9 +125,10 @@ Create one of:
125
125
  Example:
126
126
 
127
127
  ```ts
128
- import { defineConfig, eslint, typescript } from "mejora";
128
+ import { defineConfig, eslint, regex, regexRunner, typescript } from "mejora";
129
129
 
130
130
  export default defineConfig({
131
+ runners: [regexRunner()],
131
132
  checks: {
132
133
  "eslint > no-nested-ternary": eslint({
133
134
  files: ["src/**/*.{ts,tsx,js,jsx}"],
@@ -137,18 +138,36 @@ export default defineConfig({
137
138
  },
138
139
  },
139
140
  }),
140
- "typescript": typescript({
141
+ "typescript > noImplicitAny": typescript({
141
142
  overrides: {
142
143
  compilerOptions: {
143
144
  noImplicitAny: true,
144
145
  },
145
146
  },
146
147
  }),
148
+ "no-todos": regex({
149
+ files: ["src/**/*"],
150
+ patterns: [
151
+ {
152
+ pattern: /\/\/\s*TODO(?:\((?<owner>[^)]+)\))?:\s*(?<task>.*)/gi,
153
+ message: (match) => {
154
+ const task = match.groups?.task?.trim() || "no description";
155
+ const owner = match.groups?.owner;
156
+ const truncated =
157
+ task.length > 80 ? `${task.slice(0, 80)}...` : task;
158
+
159
+ return owner ? `[${owner}] ${truncated}` : truncated;
160
+ },
161
+ rule: "todo",
162
+ },
163
+ ],
164
+ }),
147
165
  },
148
166
  });
149
167
  ```
150
168
 
151
169
  Each entry in `checks` is an explicit check.
170
+
152
171
  The object key is the check identifier and is used in the baseline.
153
172
 
154
173
  ## Supported Checks
@@ -172,6 +191,13 @@ The object key is the check identifier and is used in the baseline.
172
191
  > [!NOTE]
173
192
  > `typescript` (^5.0.0) is required as a peer dependency when using the TypeScript check
174
193
 
194
+ ### Regex
195
+
196
+ - Snapshot type: `"items"`
197
+ - Each pattern match is treated as an issue
198
+ - Regressions are new matches
199
+ - Works on any file type (not just code)
200
+
175
201
  ### Custom Checks
176
202
 
177
203
  You can add your own checks by implementing `CheckRunner` and returning an `"items"` snapshot.
@@ -184,19 +210,17 @@ A custom check is made of two pieces:
184
210
  ```ts
185
211
  import type { CheckRunner, IssueInput } from "mejora";
186
212
 
187
- interface TodoCheckConfig {
213
+ interface CustomCheckConfig {
188
214
  files: string[];
189
- patterns?: string[];
215
+ // your custom options
190
216
  }
191
217
 
192
- class TodoCheckRunner implements CheckRunner {
193
- readonly type = "todo";
218
+ class CustomCheckRunner implements CheckRunner {
219
+ readonly type = "custom";
194
220
 
195
- async run(config: TodoCheckConfig) {
221
+ async run(config: CustomCheckConfig) {
196
222
  const items: IssueInput[] = [];
197
-
198
223
  // ...produce IssueInput entries (file/line/column/rule/message)
199
-
200
224
  return { type: "items", items };
201
225
  }
202
226
  }
@@ -208,12 +232,12 @@ Register the runner and declare a check that uses it:
208
232
  import { defineConfig } from "mejora";
209
233
 
210
234
  export default defineConfig({
211
- runners: [new TodoCheckRunner()],
235
+ runners: [new CustomCheckRunner()],
212
236
  checks: {
213
- "todo-comments": {
214
- type: "todo",
237
+ "my-custom-check": {
238
+ type: "custom",
215
239
  files: ["src/**/*.ts"],
216
- patterns: ["TODO", "FIXME"],
240
+ // your custom options
217
241
  },
218
242
  },
219
243
  });
package/dist/index.d.mts CHANGED
@@ -137,6 +137,65 @@ interface TypeScriptCheckConfig {
137
137
  */
138
138
  tsconfig?: string;
139
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
+ }
140
199
  type CustomCheckConfig = Record<string, unknown> & {
141
200
  type: string;
142
201
  };
@@ -339,4 +398,33 @@ declare function defineConfig<const TRunners extends readonly CheckRunner[]>(con
339
398
  runners?: TRunners;
340
399
  };
341
400
  //#endregion
342
- export { type CheckRunner, type Config, type Issue, type IssueInput, type RawSnapshot, type Snapshot, defineConfig, eslintCheck as eslint, eslintCheck, typescriptCheck as typescript, typescriptCheck };
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 };
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{i as e,l as t,n}from"./typescript-eNO5KFTb.mjs";export{t as defineConfig,e as eslint,e as eslintCheck,n as typescript,n as typescriptCheck};
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-C0a92mCs.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,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{a as e,c as t,o as n,r,s as i,t as a,u as o}from"./typescript-eNO5KFTb.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]?.();e&&n.push(e)}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?``:`
2
+ import{d as e,f as t,g as n,m as r,r as i,t as a,u as o}from"./typescript-C0a92mCs.mjs";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{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]?.();e&&n.push(e)}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=>f(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(n,r,i){let a=t(n),o=e(n),s=r>0?`:${r}:${i>0?i: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
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
4
  `}${e.hasRegression?C(`✖`):S(`✔`)} ${e.checkId}:`,...le(e),...ue(e),``,...k(e)]}function pe(e,t){let n=t?``:`
5
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(`
@@ -8,7 +8,7 @@ import{a as e,c as t,o as n,r,s as i,t as a,u as o}from"./typescript-eNO5KFTb.mj
8
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 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(`<`,`&lt;`).replaceAll(`>`,`&gt;`).replaceAll(`[`,`&#91;`).replaceAll(`]`,`&#93;`)}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(`
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(`<`,`&lt;`).replaceAll(`>`,`&gt;`).replaceAll(`[`,`&#91;`).replaceAll(`]`,`&#93;`)}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){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
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
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
14
  `);let a=Se(t);for(let e of a)i.push(we(e,n));return i.join(`
@@ -21,7 +21,7 @@ import{a as e,c as t,o as n,r,s as i,t as a,u as o}from"./typescript-eNO5KFTb.mj
21
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
22
  `).slice(1).map(e=>x(e.trim())).join(`
23
23
  `);t.push(n)}return t.join(`
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(`
24
+ `)}function G(...e){return e.map(e=>typeof e==`string`?e:e instanceof Error?Oe(e):u(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 c(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,n=!1){if(M&&!n)return;let r=`${JSON.stringify(e,null,2)}\n`,i=this.baselinePath.replace(`.json`,`.md`),a=W(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(`<<<<<<<`)&&(K.start(`Merge conflict detected in markdown report, regenerating...`),await l(n,W(JSON.parse(e),t(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(e){let t=Map.groupBy(e,e=>e.signature),n=[];for(let[e,r]of t){r.sort(Q);for(let[t,{signature:i,...a}]of r.entries())n.push({...a,id:o(`${e}:${t}`)})}return n}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:$}=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&&(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 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{};
43
+ `),process.exit(0));try{let e=new m;e.register(new i),e.register(new a);let t=await n();if(t.runners)for(let n of t.runners)e.register(n);let r=await new Fe(e).run(t,{force:$.force,json:$.json,only:$.only,skip:$.skip});$.json?K.log(g(r)):(K.log(``),K.log(A(r,$.force))),process.exit(r.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{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`),O=(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 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
+ `);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
+ `),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};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mejora",
3
- "version": "2.2.2",
3
+ "version": "2.3.0",
4
4
  "description": "Prevent regressions. Allow improvement.",
5
5
  "keywords": [
6
6
  "regression",
@@ -38,12 +38,16 @@
38
38
  ],
39
39
  "peerDependencies": {
40
40
  "eslint": "^9.34.0",
41
+ "tinyglobby": "^0.2.0",
41
42
  "typescript": "^5.0.0"
42
43
  },
43
44
  "peerDependenciesMeta": {
44
45
  "eslint": {
45
46
  "optional": true
46
47
  },
48
+ "tinyglobby": {
49
+ "optional": true
50
+ },
47
51
  "typescript": {
48
52
  "optional": true
49
53
  }
@@ -1,3 +0,0 @@
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}}function D(e,t){return e.replaceAll(/import\("([^"]+)"\)/g,(e,n)=>{try{if(_(n)){let e=v(t,n);if(!e.startsWith(`..`))return`import("${e||`.`}")`}}catch{}return e})}var O=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 O=h(u),k=O+`/`,A=E.filter(e=>{if(!e.file)return!0;let t=h(e.file.fileName);return t===O||t.startsWith(k)}),j=[];for(let e of A){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);j.push({column:r+1,file:a,line:i+1,message:D(t,u),rule:n})}else j.push({column:0,file:`(global)`,line:0,message:D(t,u),rule:n})}return{items:j,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 k(e){return{type:`typescript`,...e}}export{x as a,v as c,E as i,s as l,k as n,b as o,T as r,y as s,O as t,c as u};