@ngcompass/planner 0.1.1-beta → 0.1.3-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import {minimatch}from'minimatch';import {debug,time,Err,InfrastructureErrorCollector,timeLog,Ok,createInfrastructureError}from'@ngcompass/common';export{Err,Ok}from'@ngcompass/common';import*as k from'path';import k__default from'path';import*as I from'fs/promises';import {readdir,readFile}from'fs/promises';import {computeHash,initHasher}from'@ngcompass/cache';var ve=(e,t)=>t.filter(s=>Fe(e,Array.isArray(s.files)?s.files:[s.files])),ae=(e,t,s)=>{let a=ve(e,s);if(a.length===0)return t;let r=new Map(t);for(let l of a)if(l.rules)for(let[n,i]of Object.entries(l.rules)){let o=r.get(n);if(!o)continue;let p=be(i);p.severity==="off"?r.delete(n):r.set(n,{...o,severity:p.severity,options:{...o.options,...p.options}});}return r},Fe=(e,t)=>t.some(s=>minimatch(e.replace(/\\/g,"/"),s,{dot:true})),be=e=>typeof e=="string"?{severity:e,options:{}}:typeof e=="object"&&e!==null&&"severity"in e?{severity:e.severity,options:e.options??{}}:{severity:"off",options:{}};var re=/\@(Component|Directive|Pipe|Injectable|NgModule)\s*[\(\{]/,E=e=>{let t=k__default.basename(e),s=k__default.extname(e);return t.endsWith(".component.ts")?"component":t.endsWith(".directive.ts")?"directive":t.endsWith(".pipe.ts")?"pipe":t.endsWith(".service.ts")?"service":t.endsWith(".module.ts")?"module":t.endsWith(".guard.ts")?"guard":s===".html"?"template":s===".css"||s===".scss"||s===".sass"||s===".less"?"style":t.endsWith(".config.ts")||s===".json"?"config":t.endsWith(".spec.ts")||t.endsWith(".test.ts")?"spec":s===".ts"?"logic":"unknown"},Se=e=>k__default.extname(e)===".ts",Ce=e=>k__default.extname(e)===".html",$e=e=>{let t=k__default.extname(e);return t===".css"||t===".scss"||t===".sass"||t===".less"},Ae=e=>k__default.basename(e).endsWith(".spec.ts"),F=e=>k__default.basename(e).endsWith(".component.ts"),b=e=>{let t=k__default.basename(e);for(let s of [".component.ts",".directive.ts",".pipe.ts",".service.ts",".module.ts",".guard.ts",".spec.ts"])if(t.endsWith(s))return t.slice(0,-s.length);return k__default.basename(e,k__default.extname(e))};var U=async(e,t,s={})=>{let a=performance.now();if(debug("incremental",`Filtering ${e.length} tasks by cache...`),s.forceRerun)return He(e);let r=e.map(c=>c.taskId);if(r.length===0)return Ie();let l=await t.hasMany(r);debug("incremental",`Found ${l.size}/${e.length} tasks in cache`);let{skippedTasks:n,tasks:i}=je(e,l),o=await Be(t,n,s),p=Oe(e.length,n.length,i.length);return Ne(a,p),{skippedTasks:n,tasks:i,cachedResults:o,stats:p}},Re=async(e,t)=>{if(e.length===0)return true;let s=e.map(a=>a.taskId);return (await t.hasMany(s)).size===e.length},Pe=async(e,t)=>{if(e.length===0)return 0;let s=e.map(a=>a.taskId);return (await t.hasMany(s)).size/e.length},Ee=async(e,t,s={})=>{if(debug("incremental","Pruning stale cache entries..."),e.length===0)return debug("incremental","No tasks to prune"),0;let a=await t.getManyWithMetadata(e);if(a.size===0)return debug("incremental","Cache is empty, nothing to prune"),0;let{now:r,maxAgeMs:l,minHits:n}=Me(s),i=We(a,r,l,n),o=await Le(t,i);return debug("incremental",`Pruned ${o} stale entries`),o},He=e=>{debug("incremental","Force rerun enabled - skipping cache check");let t={totalTasks:e.length,cachedTasks:0,pendingTasks:e.length,cacheHitRate:0,timeSavedEstimate:0};return {skippedTasks:[],tasks:e,cachedResults:new Map,stats:t}},Ie=()=>({skippedTasks:[],tasks:[],cachedResults:new Map,stats:{totalTasks:0,cachedTasks:0,pendingTasks:0,cacheHitRate:0,timeSavedEstimate:0}}),je=(e,t)=>{let s=[],a=[];for(let r of e)t.has(r.taskId)?s.push(r):a.push(r);return {skippedTasks:s,tasks:a}},Be=async(e,t,s)=>{if(!s.loadCachedResults||t.length===0)return new Map;debug("incremental",`Loading ${t.length} cached results...`);let a=t.map(l=>l.taskId),r=await e.getMany(a);return debug("incremental",`Loaded ${r.size} cached results`),r},Oe=(e,t,s)=>{let a=e>0?t/e:0;return {totalTasks:e,cachedTasks:t,pendingTasks:s,cacheHitRate:a,timeSavedEstimate:100*a}},Ne=(e,t)=>{let s=performance.now()-e;debug("incremental",`Cache filtering completed in ${s.toFixed(2)}ms`),debug("incremental",`Cache hit rate: ${(100*t.cacheHitRate).toFixed(1)}%`),debug("incremental",`Skipping ${t.cachedTasks} tasks, executing ${t.pendingTasks} tasks`);},Me=e=>({now:Date.now(),maxAgeMs:e.maxAge??6048e5,minHits:e.minHits??1}),We=(e,t,s,a)=>{let r=[];for(let[,l]of e){let n=t-l.metadata.timestamp>s,i=l.metadata.hits<a;(n||i)&&r.push(l.metadata.taskId);}return r},Le=async(e,t)=>{let s=0;for(let a of t)await e.delete(a),s++;return s};var _=[".css",".scss",".sass",".less"],_e=/templateUrl\s*:\s*['"`]([^'"`\n]+)['"`]/,De=/\bstyleUrl(?!s)\s*:\s*['"`]([^'"`\n]+)['"`]/,Ge=/\bstyleUrls\s*:\s*\[([^\]]+)\]/,le=/['"`]([^'"`\n]+\.(?:css|scss|sass|less))['"`]/g,Ke=async(e,t)=>{try{let s=await readFile(e,"utf-8"),a=_e.exec(s);return a?k__default.resolve(t,a[1]):void 0}catch{return}},qe=async(e,t)=>{try{let s=await readFile(e,"utf-8"),a=[],r=De.exec(s);r&&a.push(k__default.resolve(t,r[1]));let l=Ge.exec(s);if(l){let n;for(le.lastIndex=0;(n=le.exec(l[1]))!==null;)a.push(k__default.resolve(t,n[1]));}return a}catch{return []}},D=async(e,t,s,a,r,l)=>{let n=k__default.dirname(e),i=b(e),o=await H(n,l),p=A(e,t),c=tt(n,i,o,s);if(!c){let h=await Ke(e,n);h&&(c=A(h,s));}let u=st(e,n,i,o,a);u.length===0&&F(e)&&(u=(await qe(e,n)).map(h=>A(h,a)));let d=at(n,i,o,r);return {typescript:p,template:c,styles:u.length>0?u:void 0,spec:d}},Ye=async(e,t,s)=>{let a=k__default.dirname(e),r=b(e),l=await H(a,s);return t==="template"?Qe(r,l):t==="style"?!!F(e)&&Ze(r,l):et(r,l)},Ve=async(e,t)=>{if(!F(e))return [];let s=k__default.dirname(e),a=b(e),r=await H(s,t);return _.flatMap(l=>{let n=K(a,l);return r.includes(n)?[k__default.join(s,n)]:[]})},Je=async(e,t)=>{if(!F(e))return null;let s=k__default.dirname(e),a=b(e),r=await H(s,t),l=G(a);return r.includes(l)?k__default.join(s,l):null},Xe=async(e,t)=>{let s=k__default.dirname(e),a=b(e),r=await H(s,t),l=q(a);return r.includes(l)?k__default.join(s,l):null},H=async(e,t)=>{let s=t?.get(e);if(s)return s;try{let a=await readdir(e);return t?.set(e,a),a}catch(a){return debug("planner",`Failed to read directory: ${e}. Error: ${a instanceof Error?a.message:String(a)}`),[]}},A=(e,t)=>({path:e,needsAst:t,hash:""}),G=e=>`${e}.component.html`,K=(e,t)=>`${e}.component${t}`,q=e=>`${e}.spec.ts`,Qe=(e,t)=>t.includes(G(e)),Ze=(e,t)=>_.some(s=>t.includes(K(e,s))),et=(e,t)=>t.includes(q(e)),tt=(e,t,s,a)=>{let r=G(t);return s.includes(r)?A(k__default.join(e,r),a):void 0},st=(e,t,s,a,r)=>{if(!F(e))return [];let l=[];for(let n of _){let i=K(s,n);a.includes(i)&&l.push(A(k__default.join(t,i),r));}return l},at=(e,t,s,a)=>{let r=q(t);return s.includes(r)?A(k__default.join(e,r),a):void 0};var ie=async(e,t,s)=>{for(let a=0;a<e.length;a+=500){let r=e.slice(a,a+500);await Promise.all(r.map(async l=>{if(!s.has(l))try{let n=await I.stat(l),i=n.mtimeMs,o=n.size,p=await t.get(l);if(p&&p.mtime===i&&p.size===o)return void s.set(l,p.hash);let c=await R(l);s.set(l,c),await t.set(l,{mtime:i,size:o,hash:c});}catch{return}}));}t.flush&&await t.flush();},R=async(e,t)=>{let s=t?.get(e);if(s)return s;try{let a=await I.readFile(e,"utf-8"),r=computeHash(a);return t?.set(e,r),r}catch(a){return debug("planner",`Failed to hash file: ${e}. Error: ${a instanceof Error?a.message:String(a)}`),""}};var oe=async(e,t)=>{if(e.length===0)return "";let s=await Promise.all(e.map(async a=>`${a}:${await R(a,t)}`));return s.sort(),computeHash(s.join("|"))},pe=e=>{let t=new WeakSet,s=a=>{if(a&&typeof a=="object"){if(t.has(a))return "[Circular]";if(t.add(a),Array.isArray(a))return a.map(s);let r={};for(let l of Object.keys(a).sort())r[l]=s(a[l]);return r}return a};return JSON.stringify(s(e))},Y=e=>computeHash(pe(e.map(t=>({name:t.name,severity:t.severity,options:t.options})).sort((t,s)=>t.name.localeCompare(s.name)))),V=(e,t)=>{let s=[];if(s.push(e.typescript.hash),e.template&&s.push(e.template.hash),e.styles){let a=e.styles.map(r=>r.hash).sort();s.push(...a);}return e.spec&&s.push(e.spec.hash),s.push(Y(t)),computeHash(s.join("::"))},lt=async e=>{let t=[e.typescript.path];return e.template&&t.push(e.template.path),e.styles&&t.push(...e.styles.map(s=>s.path)),e.spec&&t.push(e.spec.path),oe(t)},nt=async e=>{try{let t=await I.stat(e);return computeHash(`${e}::${t.size}::${t.mtimeMs}`)}catch{return ""}},ce=(e,t,s,a)=>{let r=[];if(a&&(r.push(a.toolVersion),r.push(a.ruleRegistryHash)),r.push(e),r.push(t.typescript.path),r.push(t.typescript.hash),t.template&&r.push(t.template.hash),t.styles?.length){let l=t.styles.map(n=>n.hash).sort().join("::");r.push(l);}return t.spec&&r.push(t.spec.hash),r.push(pe(s)),computeHash(r.join("::"))},ue=async(e,t,s,a)=>{let r=await Promise.all(e.map(async n=>`${n}:${s.get(n)??await R(n,s)}`));r.sort();let l=[];return l.push(...r),l.push(Y(Array.from(t.values()))),a&&(l.push(`tool:${a.toolVersion}`),l.push(`parser:${a.parserVersion}`),l.push(`registry:${a.ruleRegistryHash}`),l.push(`platform:${a.platform}`)),computeHash(l.join("||"))};var he=(e,t)=>{let{dependencyType:s}=e.metadata;return s==="standalone"||s==="imports"?ut(t):s==="component"?t==="component"||t==="directive"||t==="angular-class":s==="styles"?t==="component":s==="spec"&&t==="spec"},ot=(e,t)=>{let s=[];for(let a of e.values())a.metadata.requires[t]&&s.push(a);return s};var pt=e=>{let t={standalone:[],component:[],styles:[],imports:[],spec:[]};for(let s of e.values())t[s.metadata.dependencyType].push(s);return t},me=async(e,t,s,a)=>{let r=ht(s,t);if(!r.apply)return debug("planner",` - Rule ${s.name} skipped: ${r.reason}`),null;let l=de(s),n=await ct(e,s,a);return {taskId:ce(s.name,n,s.options,a?.cacheKeyCtx),ruleName:s.name,filePath:e,severity:s.severity,options:s.options,inputs:n,needsTypeChecker:l.needsTypeChecker,needsProjectContext:l.needsProjectContext||void 0}},J=async(e,t,s,a)=>{let r=[];for(let l of s.values()){let n=await me(e,t,l,a);n&&r.push(n);}return r},ct=async(e,t,s)=>{let a=de(t),r=await mt(e,s),l={typescript:await X(r.typescript.path,a.needsTsAst,s)},n=dt(e,r,t,a,l,s);n&&(l.template=n);let i=await ft(r,t,a,s);i&&(l.styles=i);let o=await yt(r,a,s);return o&&(l.spec=o),l},ut=e=>e!=="template"&&e!=="style"&&e!=="config"&&e!=="unknown",ht=(e,t)=>he(e,t)?e.severity==="off"?{apply:false,reason:"disabled ('off')"}:{apply:true,reason:"applicable"}:{apply:false,reason:`does not apply to ${t}`},de=e=>{let t=e.metadata.requires;return {needsTsAst:!!t.tsAst,needsHtmlAst:!!t.htmlAst,needsCssAst:!!t.cssAst,needsSpecAst:!!t.specAst,needsTypeChecker:!!t.typeChecker,needsProjectContext:!!t.projectContext}},mt=async(e,t)=>{let s=t?.resourceCache?.get(e);if(s)return s;if(t?.componentGraph){let r=t.componentGraph.getResources(e);if(r){t.graphStats&&t.graphStats.hits++;let l={typescript:{path:e,hash:"",needsAst:false},styles:r.stylePaths.map(n=>({path:n,hash:"",needsAst:false}))};return r.templatePath&&(l.template={path:r.templatePath,hash:"",needsAst:false}),r.specPath&&(l.spec={path:r.specPath,hash:"",needsAst:false}),t?.resourceCache?.set(e,l),l}t.graphStats&&t.graphStats.misses++;}t?.graphStats&&t.graphStats.fallbacks++;let a=await D(e,true,true,true,true,t?.directoryCache);return t?.resourceCache?.set(e,a),a},X=async(e,t,s)=>({path:e,hash:await R(e,s?.hashCache),needsAst:t}),dt=(e,t,s,a,r,l)=>{let{dependencyType:n}=s.metadata,i=a.needsHtmlAst&&(n==="component"||n==="styles");return t.template?{path:t.template.path,hash:l?.hashCache?.get(t.template.path)??t.template.hash??"",needsAst:i}:n==="component"&&a.needsHtmlAst?{path:e,hash:r.typescript.hash,needsAst:true}:void 0},ft=async(e,t,s,a)=>{if(!e.styles||e.styles.length===0)return;let r=s.needsCssAst&&t.metadata.dependencyType==="styles";return Promise.all(e.styles.map(l=>X(l.path,r,a)))},yt=async(e,t,s)=>{if(e.spec)return X(e.spec.path,t.needsSpecAst,s)};function P(e,t){debug("planner","Generating execution indexes...");let s=Q(e,"typescript"),a=Q(e,"html"),r=Q(e,"css"),l=kt(e),n=t?At(t):{},i=t?Rt(t):Pt(),o=Tt(e),p=wt(e),c=vt(e),u=bt(e);return Ht(e,t,s,a,r,o),{filesNeedingTsAst:s,filesNeedingHtmlAst:a,filesNeedingCssAst:r,filesNeedingTypeChecker:l,tasksByFile:n,tasksBySeverityLevel:i,tasksByRule:o,filesByType:p,tasksBySeverity:c,stats:u}}var Q=(e,t)=>{let s=new Set;for(let[a,r]of Object.entries(e))r.tasks.some(l=>gt(l,t))&&s.add(a);return Array.from(s).sort()},gt=(e,t)=>{switch(t){case "typescript":return !!e.inputs.typescript.needsAst;case "html":return !!e.inputs.template?.needsAst;case "css":return !!e.inputs.styles?.some(s=>s.needsAst)}},kt=e=>{let t=new Set;for(let[s,a]of Object.entries(e))a.tasks.some(r=>r.needsTypeChecker===true||r.needsProjectContext===true)&&t.add(s);return Array.from(t).sort()},Tt=e=>{let t={};for(let[s,a]of Object.entries(e))for(let r of a.tasks)(t[r.ruleName]??=[]).push(s);for(let s of Object.keys(t))t[s].sort();return t},wt=e=>{let t=xt();for(let[s,a]of Object.entries(e))t[a.file.type].push(s);for(let s of Object.keys(t))t[s].sort();return t},xt=()=>({component:[],directive:[],pipe:[],service:[],module:[],guard:[],logic:[],"angular-class":[],spec:[],template:[],style:[],config:[],unknown:[]}),vt=e=>{let t=Ft();for(let s of Object.values(e))for(let a of s.tasks)t[a.severity]++;return t},Ft=()=>({off:0,warn:0,error:0}),bt=e=>{let t=Object.values(e),s=t.length,a=0,r=0,l=0,n=0;for(let i of t)a+=i.tasks.length,i.tasks.some(o=>!!o.inputs.template)&&r++,i.tasks.some(o=>!!o.inputs.styles?.length)&&l++,i.tasks.some(o=>!!o.inputs.spec)&&n++;return {totalFiles:s,totalTasks:a,avgTasksPerFile:s>0?a/s:0,filesWithTemplates:r,filesWithStyles:l,filesWithSpecs:n}},St=(e,t)=>{let s=new Set;for(let a of t){let r=e[a];if(r)for(let l of r)s.add(l);}return Array.from(s).sort()},Ct=e=>e.stats.totalTasks,$t=(e,t)=>e.tasksBySeverity[t],At=e=>{let t={};for(let s of e)(t[s.filePath]??=[]).push(s);for(let s of Object.keys(t))t[s].sort((a,r)=>a.ruleName.localeCompare(r.ruleName));return t},Rt=e=>{let t=Et();for(let s of e)t[s.severity].push(s);for(let s of Object.keys(t))t[s].sort((a,r)=>{let l=a.filePath.localeCompare(r.filePath);return l!==0?l:a.ruleName.localeCompare(r.ruleName)});return t},Pt=()=>({off:[],warn:[],error:[]}),Et=()=>({off:[],warn:[],error:[]}),Ht=(e,t,s,a,r,l)=>{debug("planner","Indexing complete:"),debug("planner",` - TypeScript AST needed: ${s.length} files`),debug("planner",` - HTML AST needed: ${a.length} files`),debug("planner",` - CSS AST needed: ${r.length} files`),debug("planner",` - Unique rules to run: ${Object.keys(l).length}`),t&&debug("planner",` - Total tasks: ${t.length}`);};var fe=e=>{let t=new j,s=new j,a=new j,r=new Z,l=Object.values(e.plan).map(n=>It(n,t,s,a,r));return {v:1,r:t.values(),o:r.values(),f:s.values(),h:a.values(),t:l}},ye=e=>{let{r:t,o:s,f:a,h:r,t:l}=e,n={},i=[];for(let p of l){let{filePath:c,fileType:u,fileHash:d,ruleTasks:h}=Bt(p,t,a,r,s);for(let y of(n[c]={file:{path:c,type:u,hash:d},tasks:h},h))i.push(Nt(c,y));}let o=P(n,i);return {tasks:i,plan:n,indexes:o,skippedTasks:[]}},It=(e,t,s,a,r)=>{let l=s.id(e.file.path),n=a.idOrMinusOne(e.file.hash),i=e.tasks.map(o=>jt(o,t,s,a,r));return [l,e.file.type,n,i]},jt=(e,t,s,a,r)=>{let l=t.id(e.ruleName),n=r.id(e.options),i=a.idOrMinusOne(e.cacheKey),o=N(e.inputs.typescript,s,a),p=e.inputs.template?N(e.inputs.template,s,a):void 0,c=e.inputs.styles&&e.inputs.styles.length>0?e.inputs.styles.map(h=>N(h,s,a)):void 0,u=e.inputs.spec?N(e.inputs.spec,s,a):void 0,d=+!!e.needsTypeChecker;return [l,e.severity,n,i,o,p,c,u,d]},N=(e,t,s)=>[t.id(e.path),s.idOrMinusOne(e.hash),+!!e.needsAst],Bt=(e,t,s,a,r)=>{let[l,n,i,o]=e;return {filePath:s[l],fileType:n,fileHash:ee(i,a),ruleTasks:o.map(c=>Ot(c,t,s,a,r))}},Ot=(e,t,s,a,r)=>{let[l,n,i,o,p,c,u,d,h]=e,y=t[l],f=r[i],L=ee(o,a),$={typescript:M(p,s,a)};return c&&($.template=M(c,s,a)),u&&($.styles=u.map(g=>M(g,s,a))),d&&($.spec=M(d,s,a)),{ruleName:y,severity:n,options:f,cacheKey:L,inputs:$,needsTypeChecker:h===1||void 0}},M=(e,t,s)=>({path:t[e[0]],hash:ee(e[1],s),needsAst:e[2]===1}),ee=(e,t)=>e>=0?t[e]:"",Nt=(e,t)=>({taskId:t.cacheKey,filePath:e,ruleName:t.ruleName,severity:t.severity,options:t.options,inputs:t.inputs,needsTypeChecker:t.needsTypeChecker}),j=class{map=new Map;list=[];id(t){let s=this.map.get(t);if(s!==void 0)return s;let a=this.list.length;return this.map.set(t,a),this.list.push(t),a}idOrMinusOne(t){return t?this.id(t):-1}values(){return this.list}},Z=class{map=new Map;list=[];id(t){let s=this.map.get(t);if(s!==void 0)return s;let a=this.list.length;return this.map.set(t,a),this.list.push(t),a}values(){return this.list}};var te=e=>{let t=new Map;for(let s of e){let a=t.get(s.filePath);a?a.push(s):t.set(s.filePath,[s]);}return t};var Mt=/templateUrl\s*:\s*['"`]([^'"`\n]+)['"`]/,Wt=/\bstyleUrl(?!s)\s*:\s*['"`]([^'"`\n]+)['"`]/,Lt=/\bstyleUrls\s*:\s*\[([^\]]+)\]/,ge=/['"`]([^'"`\n]+\.(?:css|scss|sass|less))['"`]/g;async function zt(e,t,s){try{let a=await readFile(e,"utf-8"),r=Mt.exec(a);if(!r)return;let l=k.resolve(t,r[1]);return s.has(l)?l:void 0}catch{return}}async function Ut(e,t,s){try{let a=await readFile(e,"utf-8"),r=[],l=Wt.exec(a);if(l){let i=k.resolve(t,l[1]);s.has(i)&&r.push(i);}let n=Lt.exec(a);if(n){let i;for(ge.lastIndex=0;(i=ge.exec(n[1]))!==null;){let o=k.resolve(t,i[1]);s.has(o)&&r.push(o);}}return r}catch{return []}}var W=class{graph=new Map;async build(t){this.graph.clear();let s=new Set(t),a=new Map;for(let r of t){let l=k.dirname(r),n=a.get(l);n?n.push(r):a.set(l,[r]);}for(let[r,l]of a){let n=new Set(l);for(let i of l.filter(o=>o.endsWith(".component.ts"))){let o=k.basename(i,".component.ts"),p=k.join(r,o),c=[`${p}.component.html`,`${p}.html`].find(h=>n.has(h));c||(c=await zt(i,r,s));let u=l.filter(h=>{if(!h.startsWith(p))return false;let y=k.extname(h);return (h===`${p}.component${y}`||h===`${p}${y}`)&&/\.(css|scss|sass|less)$/.test(y)});u.length===0&&(u=await Ut(i,r,s));let d={tsPath:i,templatePath:c,stylePaths:u,specPath:n.has(`${p}.component.spec.ts`)?`${p}.component.spec.ts`:n.has(`${p}.spec.ts`)?`${p}.spec.ts`:void 0,type:"component"};this.graph.set(i,d);}}}getResources(t){return this.graph.get(t)}};var Yt=async e=>{let t="buildExecutionPlan";time(t);try{let s,a,r,l;await initHasher();let{files:n,rules:i}=e;debug("planner",`Building execution plan for ${n.length} files and ${i.size} rules`);let o=Jt(n,i);if(o)return Err(o);let p=Xt(e),c=new Map,u=new InfrastructureErrorCollector,d=await Qt(e,p,u);if(!d&&e.cache){debug("planner","Warming up hash cache from metadata index...");let g=performance.now();await ie(e.files,e.cache.metas,p.hashCache),debug("planner",`Metadata warmup took ${(performance.now()-g).toFixed(2)}ms`);}if(!d){let g=new W;await g.build(e.files),p.componentGraph=g,p.graphStats={hits:0,misses:0,fallbacks:0},debug("planner","Component dependency graph built");}if(d&&d.precomputedAnalysis)return timeLog(t,"planner","Full analysis cached \u2014 returning precomputed result"),Ok(d);if(d)timeLog(t,"planner","Execution plan loaded from cache"),s=d.tasks;else {if(debug("planner","Building tasks..."),s=await ss(n,i,p,c,e.parallelThreshold,e.workerCount,e.overrides),e.debug&&p.graphStats){let{hits:g,misses:v,fallbacks:z}=p.graphStats;debug("planner",`Graph stats \u2014 hits: ${g}, misses: ${v}, fallbacks: ${z}`);}if(e.cache&&p.globalHash){debug("planner","Converting all tasks to full plan for cache...");let g=Te(s,i,c),v=P(g,s),z={tasks:s,plan:g,indexes:v,skippedTasks:[],globalHash:p.globalHash};await Zt(e,p,z);}}let h=s,y=[];if(e.cache){debug("planner","Filtering cached tasks...");let g=await U(s,e.cache.results,e.incremental);h=g.tasks,y=g.skippedTasks,a=g.cachedResults,r=[...new Set(h.map(v=>v.filePath))],l=[...new Set(y.map(v=>v.filePath))].filter(v=>!r.includes(v));}debug("planner","Converting tasks to file-centric plan...");let f=Te(h,i,c);debug("planner",`Building indexes for ${h.length} tasks...`);let L=P(f,h),$={tasks:h,plan:f,indexes:L,skippedTasks:y,cachedResults:a,globalHash:p.globalHash,changedFiles:r,cachedFiles:l};return timeLog(t,"planner","Execution plan built"),Ok($)}catch(s){return debug("planner",`Error building plan: ${s.message}`),Err(Error(`Failed to build execution plan: ${s.message}`))}},Vt=e=>{let{stats:t}=e.indexes,s=[];return s.push("--- Execution Plan Summary ---"),s.push(`Total files: ${t.totalFiles}`),s.push(`Total tasks: ${t.totalTasks}`),s.push(`Avg tasks per file: ${t.avgTasksPerFile.toFixed(1)}`),s.push(`Files with templates: ${t.filesWithTemplates}`),s.push(`Files with styles: ${t.filesWithStyles}`),s.push(`Files with specs: ${t.filesWithSpecs}`),s.push(""),s.join(`
2
- `)},Jt=(e,t)=>e.length===0?Error("No files to analyze"):t.size===0?Error("No rules configured"):null,Xt=e=>({hashCache:new Map,resourceCache:new Map,directoryCache:new Map,cacheKeyCtx:e?.cacheKeyCtx}),Qt=async(e,t,s)=>{let a;if(!e.cache)return null;let{files:r,rules:l}=e,n=await ue(r,l,t.hashCache,e.cacheKeyCtx);if(t.globalHash=n,e.incremental?.forceRerun)return null;let i=e.cache.analysis,o=await i.get(n);if(o)return e.debug&&debug("planner","Analysis results cached (Short-circuit enabled)"),{tasks:[],plan:{},indexes:{filesNeedingTsAst:[],filesNeedingHtmlAst:[],filesNeedingCssAst:[],filesNeedingTypeChecker:[],tasksByFile:{},tasksByRule:{},tasksBySeverityLevel:{off:[],warn:[],error:[]},filesByType:{component:[],directive:[],pipe:[],service:[],module:[],guard:[],logic:[],"angular-class":[],spec:[],template:[],style:[],config:[],unknown:[]},tasksBySeverity:{off:0,warn:0,error:0},stats:{totalFiles:0,totalTasks:0,avgTasksPerFile:0,filesWithTemplates:0,filesWithStyles:0,filesWithSpecs:0}},skippedTasks:[],globalHash:n,precomputedAnalysis:o};let p=performance.now(),c=await e.cache.plans.get(n),u=performance.now();if(!c)return null;let d=JSON.stringify(c).length,h=performance.now();try{a=c.v===1?ye(c):c;}catch(f){debug("planner","Plan cache deserialization failed \u2014 deleting corrupted entry and rebuilding");try{await e.cache.plans.delete?.(n);}catch{}return s&&s.record(createInfrastructureError("CacheCorruption",{cause:f instanceof Error?f.message:String(f),phase:"planner",recoverable:true,details:{globalHash:n}})),null}let y=performance.now();return e.debug&&(debug("planner","Plan cache HIT"),debug("planner",` Size: ${(d/1024).toFixed(1)}KB`),debug("planner",` IO: ${(u-p).toFixed(2)}ms`),debug("planner",` Deser: ${(y-h).toFixed(2)}ms`)),{...a,globalHash:n}},Zt=async(e,t,s)=>{if(!e.cache||!t.globalHash)return;let a=performance.now();debug("planner","Saving execution plan to cache...");let r=fe(s);await e.cache.plans.set(t.globalHash,r);let l=performance.now()-a;debug("planner",` Plan cache saved in ${l.toFixed(2)}ms`);},es=(e,t)=>{let s=new Set(e.map(r=>r.ruleName)),a=[];for(let r of s){let l=t.get(r);l&&a.push(l);}return a},ts=(e,t)=>e.length===0?"":V(e[0].inputs,t),ss=async(e,t,s,a,r=1e4,l=4,n)=>{if(await as(e,a),e.length>=r){let i=await ls(e,t,a,l,n);if(i)return i}return rs(e,t,s,a,n)},as=async(e,t)=>{if(!t)return;let s=e.filter(r=>!t.has(r)&&E(r)==="logic");if(s.length===0)return;debug("planner",`Level-2 classification: scanning ${s.length} unclassified .ts files for Angular decorators`);let a=performance.now();await Promise.all(s.map(async r=>{try{let l=await readFile(r,"utf8");t.set(r,re.test(l)?"angular-class":"logic");}catch{t.set(r,"logic");}})),debug("planner",`Level-2 classification complete in ${(performance.now()-a).toFixed(1)}ms \u2014 upgraded ${[...t.values()].filter(r=>r==="angular-class").length} files to 'angular-class'`);},rs=async(e,t,s,a,r)=>{let l=[];for(let n of e){let i=we(n,a),o=r?.length?ae(n,t,r):t,p=await J(n,i,o,s);l.push(...p);}return l},ls=async(e,t,s,a,r)=>{debug("planner",`Parallelizing task discovery across ${a} workers...`);try{let l=await ns();if(!l)return debug("planner","Worker script not found, falling back to sequential execution"),null;debug("planner",`Using worker: ${l}`);let n=is(e,a);debug("planner",`Split ${e.length} files into ${n.length} chunks`);let i=await os(n,l,t,s,r);return debug("planner",`Workers completed. Generated ${i.length} tasks.`),i}catch(l){return debug("planner",`Parallel execution failed, falling back to sequential: ${String(l)}`),null}},ns=async()=>{let{Worker:e}=await import('worker_threads'),{fileURLToPath:t}=await import('url'),{dirname:s,join:a}=await import('path'),{existsSync:r}=await import('fs'),l=s(t(import.meta.url));for(let n of [a(l,"worker.js"),a(l,"worker.cjs"),a(l,"worker.ts"),a(l,"planner","worker.js"),a(l,"planner","worker.cjs")])if(r(n))return n;return null},is=(e,t)=>{let s=Math.ceil(e.length/t),a=[];for(let r=0;r<e.length;r+=s)a.push(e.slice(r,r+s));return a},os=async(e,t,s,a,r)=>{let{Worker:l}=await import('worker_threads'),n=Array.from(s.entries()),i=a?Array.from(a.entries()):void 0,o=r?.length?[...r]:void 0,p=e.map((c,u)=>new Promise((d,h)=>{let y=new l(t,{workerData:{files:c,rulesEntries:n,fileTypeCacheEntries:i,overridesData:o}});y.on("message",f=>d(f.tasks)),y.on("error",f=>{debug("planner",`Worker ${u} error: ${String(f)}`),h(f instanceof Error?f:Error(String(f)));}),y.on("exit",f=>{f!==0&&h(Error(`Worker ${u} stopped with exit code ${f}`));});}));return (await Promise.all(p)).flat()},we=(e,t)=>{if(!t)return E(e);let s=t.get(e);if(s)return s;let a=E(e);return t.set(e,a),a},Te=(e,t,s)=>{let a=te(e),r={};for(let[l,n]of a){let i=we(l,s),o=es(n,t),p=ts(n,o),c=n.map(u=>({ruleName:u.ruleName,severity:u.severity,options:u.options,cacheKey:u.taskId,inputs:u.inputs,needsTypeChecker:u.needsTypeChecker}));r[l]={file:{path:l,type:i,hash:p},tasks:c};}return r};var ps=(e,t)=>({files:e.files,rules:t.rules,rootDir:t.rootDir,cache:t.cache,debug:t.debug,incremental:t.incremental,cacheKeyCtx:t.cacheKeyCtx,parallelThreshold:t.parallelThreshold,workerCount:t.workerCount}),cs=e=>e.files.length>0,us=e=>e.files.length;export{Re as areAllTasksCached,Yt as buildExecutionPlan,P as buildIndexes,me as buildTask,J as buildTasksForFile,V as calculateFileHash,E as detectFileType,D as discoverResources,U as filterCachedTasks,ot as filterRulesByAstRequirement,b as getBaseName,Pe as getCacheHitRate,Vt as getExecutionPlanSummary,St as getFilesForRules,us as getScanFileCount,Xe as getSpecFile,Ve as getStyleFiles,$t as getTasksCountBySeverity,Je as getTemplateFile,Ct as getTotalTasks,pt as groupRulesByDependencyType,te as groupTasksByFile,cs as hasScanFiles,R as hashFile,nt as hashFileStats,oe as hashFiles,Y as hashRules,lt as hashTaskInputs,F as isComponentFile,Ae as isSpecFile,$e as isStyleFile,Ce as isTemplateFile,Se as isTypeScriptFile,Ee as pruneStaleCache,Ye as resourceExists,ps as scanResultToPlanInput,he as shouldApplyRule};//# sourceMappingURL=index.js.map
1
+ import {minimatch}from'minimatch';import {debug,time,Err,InfrastructureErrorCollector,timeLog,Ok,createInfrastructureError}from'@ngcompass/common';export{Err,Ok}from'@ngcompass/common';import*as k from'path';import k__default from'path';import*as I from'fs/promises';import {readdir,readFile}from'fs/promises';import {computeHash,initHasher}from'@ngcompass/cache';var ve=(e,t)=>t.filter(s=>Fe(e,Array.isArray(s.files)?s.files:[s.files])),ae=(e,t,s)=>{let a=ve(e,s);if(a.length===0)return t;let r=new Map(t);for(let l of a)if(l.rules)for(let[n,i]of Object.entries(l.rules)){let o=r.get(n);if(!o)continue;let p=be(i);p.severity==="off"?r.delete(n):r.set(n,{...o,severity:p.severity,options:{...o.options,...p.options}});}return r},Fe=(e,t)=>t.some(s=>minimatch(e.replace(/\\/g,"/"),s,{dot:true})),be=e=>typeof e=="string"?{severity:e,options:{}}:typeof e=="object"&&e!==null&&"severity"in e?{severity:e.severity,options:e.options??{}}:{severity:"off",options:{}};var re=/\@(Component|Directive|Pipe|Injectable|NgModule)\s*[\(\{]/,E=e=>{let t=k__default.basename(e),s=k__default.extname(e);return t.endsWith(".component.ts")?"component":t.endsWith(".directive.ts")?"directive":t.endsWith(".pipe.ts")?"pipe":t.endsWith(".service.ts")?"service":t.endsWith(".module.ts")?"module":t.endsWith(".guard.ts")?"guard":s===".html"?"template":s===".css"||s===".scss"||s===".sass"||s===".less"?"style":t.endsWith(".config.ts")||s===".json"?"config":t.endsWith(".spec.ts")||t.endsWith(".test.ts")?"spec":s===".ts"?"logic":"unknown"},Se=e=>k__default.extname(e)===".ts",Ce=e=>k__default.extname(e)===".html",$e=e=>{let t=k__default.extname(e);return t===".css"||t===".scss"||t===".sass"||t===".less"},Ae=e=>k__default.basename(e).endsWith(".spec.ts"),F=e=>k__default.basename(e).endsWith(".component.ts"),b=e=>{let t=k__default.basename(e);for(let s of [".component.ts",".directive.ts",".pipe.ts",".service.ts",".module.ts",".guard.ts",".spec.ts"])if(t.endsWith(s))return t.slice(0,-s.length);return k__default.basename(e,k__default.extname(e))};var U=async(e,t,s={})=>{let a=performance.now();if(debug("incremental",`Filtering ${e.length} tasks by cache...`),s.forceRerun)return He(e);let r=e.map(c=>c.taskId);if(r.length===0)return Ie();let l=await t.hasMany(r);debug("incremental",`Found ${l.size}/${e.length} tasks in cache`);let{skippedTasks:n,tasks:i}=je(e,l),o=await Be(t,n,s),p=Oe(e.length,n.length,i.length);return Ne(a,p),{skippedTasks:n,tasks:i,cachedResults:o,stats:p}},Re=async(e,t)=>{if(e.length===0)return true;let s=e.map(a=>a.taskId);return (await t.hasMany(s)).size===e.length},Pe=async(e,t)=>{if(e.length===0)return 0;let s=e.map(a=>a.taskId);return (await t.hasMany(s)).size/e.length},Ee=async(e,t,s={})=>{if(debug("incremental","Pruning stale cache entries..."),e.length===0)return debug("incremental","No tasks to prune"),0;let a=await t.getManyWithMetadata(e);if(a.size===0)return debug("incremental","Cache is empty, nothing to prune"),0;let{now:r,maxAgeMs:l,minHits:n}=Me(s),i=We(a,r,l,n),o=await Le(t,i);return debug("incremental",`Pruned ${o} stale entries`),o},He=e=>{debug("incremental","Force rerun enabled - skipping cache check");let t={totalTasks:e.length,cachedTasks:0,pendingTasks:e.length,cacheHitRate:0,timeSavedEstimate:0};return {skippedTasks:[],tasks:e,cachedResults:new Map,stats:t}},Ie=()=>({skippedTasks:[],tasks:[],cachedResults:new Map,stats:{totalTasks:0,cachedTasks:0,pendingTasks:0,cacheHitRate:0,timeSavedEstimate:0}}),je=(e,t)=>{let s=[],a=[];for(let r of e)t.has(r.taskId)?s.push(r):a.push(r);return {skippedTasks:s,tasks:a}},Be=async(e,t,s)=>{if(!s.loadCachedResults||t.length===0)return new Map;debug("incremental",`Loading ${t.length} cached results...`);let a=t.map(l=>l.taskId),r=await e.getMany(a);return debug("incremental",`Loaded ${r.size} cached results`),r},Oe=(e,t,s)=>{let a=e>0?t/e:0;return {totalTasks:e,cachedTasks:t,pendingTasks:s,cacheHitRate:a,timeSavedEstimate:100*a}},Ne=(e,t)=>{let s=performance.now()-e;debug("incremental",`Cache filtering completed in ${s.toFixed(2)}ms`),debug("incremental",`Cache hit rate: ${(100*t.cacheHitRate).toFixed(1)}%`),debug("incremental",`Skipping ${t.cachedTasks} tasks, executing ${t.pendingTasks} tasks`);},Me=e=>({now:Date.now(),maxAgeMs:e.maxAge??6048e5,minHits:e.minHits??1}),We=(e,t,s,a)=>{let r=[];for(let[,l]of e){let n=t-l.metadata.timestamp>s,i=l.metadata.hits<a;(n||i)&&r.push(l.metadata.taskId);}return r},Le=async(e,t)=>{let s=0;for(let a of t)await e.delete(a),s++;return s};var _=[".css",".scss",".sass",".less"],_e=/templateUrl\s*:\s*['"`]([^'"`\n]+)['"`]/,De=/\bstyleUrl(?!s)\s*:\s*['"`]([^'"`\n]+)['"`]/,Ge=/\bstyleUrls\s*:\s*\[([^\]]+)\]/,le=/['"`]([^'"`\n]+\.(?:css|scss|sass|less))['"`]/g,Ke=async(e,t)=>{try{let s=await readFile(e,"utf-8"),a=_e.exec(s);return a?k__default.resolve(t,a[1]):void 0}catch{return}},qe=async(e,t)=>{try{let s=await readFile(e,"utf-8"),a=[],r=De.exec(s);r&&a.push(k__default.resolve(t,r[1]));let l=Ge.exec(s);if(l){let n;for(le.lastIndex=0;(n=le.exec(l[1]))!==null;)a.push(k__default.resolve(t,n[1]));}return a}catch{return []}},D=async(e,t,s,a,r,l)=>{let n=k__default.dirname(e),i=b(e),o=await H(n,l),p=A(e,t),c=tt(n,i,o,s);if(!c){let h=await Ke(e,n);h&&(c=A(h,s));}let u=st(e,n,i,o,a);u.length===0&&F(e)&&(u=(await qe(e,n)).map(h=>A(h,a)));let d=at(n,i,o,r);return {typescript:p,template:c,styles:u.length>0?u:void 0,spec:d}},Ye=async(e,t,s)=>{let a=k__default.dirname(e),r=b(e),l=await H(a,s);return t==="template"?Qe(r,l):t==="style"?!!F(e)&&Ze(r,l):et(r,l)},Ve=async(e,t)=>{if(!F(e))return [];let s=k__default.dirname(e),a=b(e),r=await H(s,t);return _.flatMap(l=>{let n=K(a,l);return r.includes(n)?[k__default.join(s,n)]:[]})},Je=async(e,t)=>{if(!F(e))return null;let s=k__default.dirname(e),a=b(e),r=await H(s,t),l=G(a);return r.includes(l)?k__default.join(s,l):null},Xe=async(e,t)=>{let s=k__default.dirname(e),a=b(e),r=await H(s,t),l=q(a);return r.includes(l)?k__default.join(s,l):null},H=async(e,t)=>{let s=t?.get(e);if(s)return s;try{let a=await readdir(e);return t?.set(e,a),a}catch(a){return debug("planner",`Failed to read directory: ${e}. Error: ${a instanceof Error?a.message:String(a)}`),[]}},A=(e,t)=>({path:e,needsAst:t,hash:""}),G=e=>`${e}.component.html`,K=(e,t)=>`${e}.component${t}`,q=e=>`${e}.spec.ts`,Qe=(e,t)=>t.includes(G(e)),Ze=(e,t)=>_.some(s=>t.includes(K(e,s))),et=(e,t)=>t.includes(q(e)),tt=(e,t,s,a)=>{let r=G(t);return s.includes(r)?A(k__default.join(e,r),a):void 0},st=(e,t,s,a,r)=>{if(!F(e))return [];let l=[];for(let n of _){let i=K(s,n);a.includes(i)&&l.push(A(k__default.join(t,i),r));}return l},at=(e,t,s,a)=>{let r=q(t);return s.includes(r)?A(k__default.join(e,r),a):void 0};var ie=async(e,t,s)=>{for(let a=0;a<e.length;a+=500){let r=e.slice(a,a+500);await Promise.all(r.map(async l=>{if(!s.has(l))try{let n=await I.stat(l),i=n.mtimeMs,o=n.size,p=await t.get(l);if(p&&p.mtime===i&&p.size===o)return void s.set(l,p.hash);let c=await R(l);s.set(l,c),await t.set(l,{mtime:i,size:o,hash:c});}catch{return}}));}t.flush&&await t.flush();},R=async(e,t)=>{let s=t?.get(e);if(s)return s;try{let a=await I.readFile(e,"utf-8"),r=computeHash(a);return t?.set(e,r),r}catch(a){return debug("planner",`Failed to hash file: ${e}. Error: ${a instanceof Error?a.message:String(a)}`),""}};var oe=async(e,t)=>{if(e.length===0)return "";let s=await Promise.all(e.map(async a=>`${a}:${await R(a,t)}`));return s.sort(),computeHash(s.join("|"))},pe=e=>{let t=new WeakSet,s=a=>{if(a&&typeof a=="object"){if(t.has(a))return "[Circular]";if(t.add(a),Array.isArray(a))return a.map(s);let r={};for(let l of Object.keys(a).sort())r[l]=s(a[l]);return r}return a};return JSON.stringify(s(e))},Y=e=>computeHash(pe(e.map(t=>({name:t.name,severity:t.severity,options:t.options})).sort((t,s)=>t.name.localeCompare(s.name)))),V=(e,t)=>{let s=[];if(s.push(e.typescript.hash),e.template&&s.push(e.template.hash),e.styles){let a=e.styles.map(r=>r.hash).sort();s.push(...a);}return e.spec&&s.push(e.spec.hash),s.push(Y(t)),computeHash(s.join("::"))},lt=async e=>{let t=[e.typescript.path];return e.template&&t.push(e.template.path),e.styles&&t.push(...e.styles.map(s=>s.path)),e.spec&&t.push(e.spec.path),oe(t)},nt=async e=>{try{let t=await I.stat(e);return computeHash(`${e}::${t.size}::${t.mtimeMs}`)}catch{return ""}},ce=(e,t,s,a)=>{let r=[];if(a&&(r.push(a.toolVersion),r.push(a.ruleRegistryHash)),r.push(e),r.push(t.typescript.path),r.push(t.typescript.hash),t.template&&r.push(t.template.hash),t.styles?.length){let l=t.styles.map(n=>n.hash).sort().join("::");r.push(l);}return t.spec&&r.push(t.spec.hash),r.push(pe(s)),computeHash(r.join("::"))},ue=async(e,t,s,a)=>{let r=[];for(let n=0;n<e.length;n+=500){let i=e.slice(n,n+500),o=await Promise.all(i.map(async p=>`${p}:${s.get(p)??await R(p,s)}`));r.push(...o);}r.sort();let l=[];return l.push(...r),l.push(Y(Array.from(t.values()))),a&&(l.push(`tool:${a.toolVersion}`),l.push(`parser:${a.parserVersion}`),l.push(`registry:${a.ruleRegistryHash}`),l.push(`platform:${a.platform}`)),computeHash(l.join("||"))};var he=(e,t)=>{let{dependencyType:s}=e.metadata;return s==="standalone"||s==="imports"?ut(t):s==="component"?t==="component"||t==="directive"||t==="angular-class":s==="styles"?t==="component":s==="spec"&&t==="spec"},ot=(e,t)=>{let s=[];for(let a of e.values())a.metadata.requires[t]&&s.push(a);return s};var pt=e=>{let t={standalone:[],component:[],styles:[],imports:[],spec:[]};for(let s of e.values())t[s.metadata.dependencyType].push(s);return t},me=async(e,t,s,a)=>{let r=ht(s,t);if(!r.apply)return debug("planner",` - Rule ${s.name} skipped: ${r.reason}`),null;let l=de(s),n=await ct(e,s,a);return {taskId:ce(s.name,n,s.options,a?.cacheKeyCtx),ruleName:s.name,filePath:e,severity:s.severity,options:s.options,inputs:n,needsTypeChecker:l.needsTypeChecker,needsProjectContext:l.needsProjectContext||void 0}},J=async(e,t,s,a)=>{let r=[];for(let l of s.values()){let n=await me(e,t,l,a);n&&r.push(n);}return r},ct=async(e,t,s)=>{let a=de(t),r=await mt(e,s),l={typescript:await X(r.typescript.path,a.needsTsAst,s)},n=dt(e,r,t,a,l,s);n&&(l.template=n);let i=await ft(r,t,a,s);i&&(l.styles=i);let o=await yt(r,a,s);return o&&(l.spec=o),l},ut=e=>e!=="template"&&e!=="style"&&e!=="config"&&e!=="unknown",ht=(e,t)=>he(e,t)?e.severity==="off"?{apply:false,reason:"disabled ('off')"}:{apply:true,reason:"applicable"}:{apply:false,reason:`does not apply to ${t}`},de=e=>{let t=e.metadata.requires;return {needsTsAst:!!t.tsAst,needsHtmlAst:!!t.htmlAst,needsCssAst:!!t.cssAst,needsSpecAst:!!t.specAst,needsTypeChecker:!!t.typeChecker,needsProjectContext:!!t.projectContext}},mt=async(e,t)=>{let s=t?.resourceCache?.get(e);if(s)return s;if(t?.componentGraph){let r=t.componentGraph.getResources(e);if(r){t.graphStats&&t.graphStats.hits++;let l={typescript:{path:e,hash:"",needsAst:false},styles:r.stylePaths.map(n=>({path:n,hash:"",needsAst:false}))};return r.templatePath&&(l.template={path:r.templatePath,hash:"",needsAst:false}),r.specPath&&(l.spec={path:r.specPath,hash:"",needsAst:false}),t?.resourceCache?.set(e,l),l}t.graphStats&&t.graphStats.misses++;}t?.graphStats&&t.graphStats.fallbacks++;let a=await D(e,true,true,true,true,t?.directoryCache);return t?.resourceCache?.set(e,a),a},X=async(e,t,s)=>({path:e,hash:await R(e,s?.hashCache),needsAst:t}),dt=(e,t,s,a,r,l)=>{let{dependencyType:n}=s.metadata,i=a.needsHtmlAst&&(n==="component"||n==="styles");return t.template?{path:t.template.path,hash:l?.hashCache?.get(t.template.path)??t.template.hash??"",needsAst:i}:n==="component"&&a.needsHtmlAst?{path:e,hash:r.typescript.hash,needsAst:true}:void 0},ft=async(e,t,s,a)=>{if(!e.styles||e.styles.length===0)return;let r=s.needsCssAst&&t.metadata.dependencyType==="styles";return Promise.all(e.styles.map(l=>X(l.path,r,a)))},yt=async(e,t,s)=>{if(e.spec)return X(e.spec.path,t.needsSpecAst,s)};function P(e,t){debug("planner","Generating execution indexes...");let s=Q(e,"typescript"),a=Q(e,"html"),r=Q(e,"css"),l=kt(e),n=t?At(t):{},i=t?Rt(t):Pt(),o=Tt(e),p=wt(e),c=vt(e),u=bt(e);return Ht(e,t,s,a,r,o),{filesNeedingTsAst:s,filesNeedingHtmlAst:a,filesNeedingCssAst:r,filesNeedingTypeChecker:l,tasksByFile:n,tasksBySeverityLevel:i,tasksByRule:o,filesByType:p,tasksBySeverity:c,stats:u}}var Q=(e,t)=>{let s=new Set;for(let[a,r]of Object.entries(e))r.tasks.some(l=>gt(l,t))&&s.add(a);return Array.from(s).sort()},gt=(e,t)=>{switch(t){case "typescript":return !!e.inputs.typescript.needsAst;case "html":return !!e.inputs.template?.needsAst;case "css":return !!e.inputs.styles?.some(s=>s.needsAst)}},kt=e=>{let t=new Set;for(let[s,a]of Object.entries(e))a.tasks.some(r=>r.needsTypeChecker===true||r.needsProjectContext===true)&&t.add(s);return Array.from(t).sort()},Tt=e=>{let t={};for(let[s,a]of Object.entries(e))for(let r of a.tasks)(t[r.ruleName]??=[]).push(s);for(let s of Object.keys(t))t[s].sort();return t},wt=e=>{let t=xt();for(let[s,a]of Object.entries(e))t[a.file.type].push(s);for(let s of Object.keys(t))t[s].sort();return t},xt=()=>({component:[],directive:[],pipe:[],service:[],module:[],guard:[],logic:[],"angular-class":[],spec:[],template:[],style:[],config:[],unknown:[]}),vt=e=>{let t=Ft();for(let s of Object.values(e))for(let a of s.tasks)t[a.severity]++;return t},Ft=()=>({off:0,warn:0,error:0}),bt=e=>{let t=Object.values(e),s=t.length,a=0,r=0,l=0,n=0;for(let i of t)a+=i.tasks.length,i.tasks.some(o=>!!o.inputs.template)&&r++,i.tasks.some(o=>!!o.inputs.styles?.length)&&l++,i.tasks.some(o=>!!o.inputs.spec)&&n++;return {totalFiles:s,totalTasks:a,avgTasksPerFile:s>0?a/s:0,filesWithTemplates:r,filesWithStyles:l,filesWithSpecs:n}},St=(e,t)=>{let s=new Set;for(let a of t){let r=e[a];if(r)for(let l of r)s.add(l);}return Array.from(s).sort()},Ct=e=>e.stats.totalTasks,$t=(e,t)=>e.tasksBySeverity[t],At=e=>{let t={};for(let s of e)(t[s.filePath]??=[]).push(s);for(let s of Object.keys(t))t[s].sort((a,r)=>a.ruleName.localeCompare(r.ruleName));return t},Rt=e=>{let t=Et();for(let s of e)t[s.severity].push(s);for(let s of Object.keys(t))t[s].sort((a,r)=>{let l=a.filePath.localeCompare(r.filePath);return l!==0?l:a.ruleName.localeCompare(r.ruleName)});return t},Pt=()=>({off:[],warn:[],error:[]}),Et=()=>({off:[],warn:[],error:[]}),Ht=(e,t,s,a,r,l)=>{debug("planner","Indexing complete:"),debug("planner",` - TypeScript AST needed: ${s.length} files`),debug("planner",` - HTML AST needed: ${a.length} files`),debug("planner",` - CSS AST needed: ${r.length} files`),debug("planner",` - Unique rules to run: ${Object.keys(l).length}`),t&&debug("planner",` - Total tasks: ${t.length}`);};var fe=e=>{let t=new j,s=new j,a=new j,r=new Z,l=Object.values(e.plan).map(n=>It(n,t,s,a,r));return {v:1,r:t.values(),o:r.values(),f:s.values(),h:a.values(),t:l}},ye=e=>{let{r:t,o:s,f:a,h:r,t:l}=e,n={},i=[];for(let p of l){let{filePath:c,fileType:u,fileHash:d,ruleTasks:h}=Bt(p,t,a,r,s);for(let y of(n[c]={file:{path:c,type:u,hash:d},tasks:h},h))i.push(Nt(c,y));}let o=P(n,i);return {tasks:i,plan:n,indexes:o,skippedTasks:[]}},It=(e,t,s,a,r)=>{let l=s.id(e.file.path),n=a.idOrMinusOne(e.file.hash),i=e.tasks.map(o=>jt(o,t,s,a,r));return [l,e.file.type,n,i]},jt=(e,t,s,a,r)=>{let l=t.id(e.ruleName),n=r.id(e.options),i=a.idOrMinusOne(e.cacheKey),o=N(e.inputs.typescript,s,a),p=e.inputs.template?N(e.inputs.template,s,a):void 0,c=e.inputs.styles&&e.inputs.styles.length>0?e.inputs.styles.map(h=>N(h,s,a)):void 0,u=e.inputs.spec?N(e.inputs.spec,s,a):void 0,d=+!!e.needsTypeChecker;return [l,e.severity,n,i,o,p,c,u,d]},N=(e,t,s)=>[t.id(e.path),s.idOrMinusOne(e.hash),+!!e.needsAst],Bt=(e,t,s,a,r)=>{let[l,n,i,o]=e;return {filePath:s[l],fileType:n,fileHash:ee(i,a),ruleTasks:o.map(c=>Ot(c,t,s,a,r))}},Ot=(e,t,s,a,r)=>{let[l,n,i,o,p,c,u,d,h]=e,y=t[l],f=r[i],L=ee(o,a),$={typescript:M(p,s,a)};return c&&($.template=M(c,s,a)),u&&($.styles=u.map(g=>M(g,s,a))),d&&($.spec=M(d,s,a)),{ruleName:y,severity:n,options:f,cacheKey:L,inputs:$,needsTypeChecker:h===1||void 0}},M=(e,t,s)=>({path:t[e[0]],hash:ee(e[1],s),needsAst:e[2]===1}),ee=(e,t)=>e>=0?t[e]:"",Nt=(e,t)=>({taskId:t.cacheKey,filePath:e,ruleName:t.ruleName,severity:t.severity,options:t.options,inputs:t.inputs,needsTypeChecker:t.needsTypeChecker}),j=class{map=new Map;list=[];id(t){let s=this.map.get(t);if(s!==void 0)return s;let a=this.list.length;return this.map.set(t,a),this.list.push(t),a}idOrMinusOne(t){return t?this.id(t):-1}values(){return this.list}},Z=class{map=new Map;list=[];id(t){let s=this.map.get(t);if(s!==void 0)return s;let a=this.list.length;return this.map.set(t,a),this.list.push(t),a}values(){return this.list}};var te=e=>{let t=new Map;for(let s of e){let a=t.get(s.filePath);a?a.push(s):t.set(s.filePath,[s]);}return t};var Mt=/templateUrl\s*:\s*['"`]([^'"`\n]+)['"`]/,Wt=/\bstyleUrl(?!s)\s*:\s*['"`]([^'"`\n]+)['"`]/,Lt=/\bstyleUrls\s*:\s*\[([^\]]+)\]/,ge=/['"`]([^'"`\n]+\.(?:css|scss|sass|less))['"`]/g;async function zt(e,t,s){try{let a=await readFile(e,"utf-8"),r=Mt.exec(a);if(!r)return;let l=k.resolve(t,r[1]);return s.has(l)?l:void 0}catch{return}}async function Ut(e,t,s){try{let a=await readFile(e,"utf-8"),r=[],l=Wt.exec(a);if(l){let i=k.resolve(t,l[1]);s.has(i)&&r.push(i);}let n=Lt.exec(a);if(n){let i;for(ge.lastIndex=0;(i=ge.exec(n[1]))!==null;){let o=k.resolve(t,i[1]);s.has(o)&&r.push(o);}}return r}catch{return []}}var W=class{graph=new Map;async build(t){this.graph.clear();let s=new Set(t),a=new Map;for(let r of t){let l=k.dirname(r),n=a.get(l);n?n.push(r):a.set(l,[r]);}for(let[r,l]of a){let n=new Set(l);for(let i of l.filter(o=>o.endsWith(".component.ts"))){let o=k.basename(i,".component.ts"),p=k.join(r,o),c=[`${p}.component.html`,`${p}.html`].find(h=>n.has(h));c||(c=await zt(i,r,s));let u=l.filter(h=>{if(!h.startsWith(p))return false;let y=k.extname(h);return (h===`${p}.component${y}`||h===`${p}${y}`)&&/\.(css|scss|sass|less)$/.test(y)});u.length===0&&(u=await Ut(i,r,s));let d={tsPath:i,templatePath:c,stylePaths:u,specPath:n.has(`${p}.component.spec.ts`)?`${p}.component.spec.ts`:n.has(`${p}.spec.ts`)?`${p}.spec.ts`:void 0,type:"component"};this.graph.set(i,d);}}}getResources(t){return this.graph.get(t)}};var Yt=async e=>{let t="buildExecutionPlan";time(t);try{let s,a,r,l;await initHasher();let{files:n,rules:i}=e;debug("planner",`Building execution plan for ${n.length} files and ${i.size} rules`);let o=Jt(n,i);if(o)return Err(o);let p=Xt(e),c=new Map,u=new InfrastructureErrorCollector;if(e.cache){debug("planner","Warming up hash cache from metadata index...");let g=performance.now();await ie(e.files,e.cache.metas,p.hashCache),debug("planner",`Metadata warmup took ${(performance.now()-g).toFixed(2)}ms`);}let d=await Qt(e,p,u);if(!d){let g=new W;await g.build(e.files),p.componentGraph=g,p.graphStats={hits:0,misses:0,fallbacks:0},debug("planner","Component dependency graph built");}if(d&&d.precomputedAnalysis)return timeLog(t,"planner","Full analysis cached \u2014 returning precomputed result"),Ok(d);if(d)timeLog(t,"planner","Execution plan loaded from cache"),s=d.tasks;else {if(debug("planner","Building tasks..."),s=await ss(n,i,p,c,e.parallelThreshold,e.workerCount,e.overrides),e.debug&&p.graphStats){let{hits:g,misses:v,fallbacks:z}=p.graphStats;debug("planner",`Graph stats \u2014 hits: ${g}, misses: ${v}, fallbacks: ${z}`);}if(e.cache&&p.globalHash){debug("planner","Converting all tasks to full plan for cache...");let g=Te(s,i,c),v=P(g,s),z={tasks:s,plan:g,indexes:v,skippedTasks:[],globalHash:p.globalHash};await Zt(e,p,z);}}let h=s,y=[];if(e.cache){debug("planner","Filtering cached tasks...");let g=await U(s,e.cache.results,e.incremental);h=g.tasks,y=g.skippedTasks,a=g.cachedResults,r=[...new Set(h.map(v=>v.filePath))],l=[...new Set(y.map(v=>v.filePath))].filter(v=>!r.includes(v));}debug("planner","Converting tasks to file-centric plan...");let f=Te(h,i,c);debug("planner",`Building indexes for ${h.length} tasks...`);let L=P(f,h),$={tasks:h,plan:f,indexes:L,skippedTasks:y,cachedResults:a,globalHash:p.globalHash,changedFiles:r,cachedFiles:l};return timeLog(t,"planner","Execution plan built"),Ok($)}catch(s){return debug("planner",`Error building plan: ${s.message}`),Err(Error(`Failed to build execution plan: ${s.message}`))}},Vt=e=>{let{stats:t}=e.indexes,s=[];return s.push("--- Execution Plan Summary ---"),s.push(`Total files: ${t.totalFiles}`),s.push(`Total tasks: ${t.totalTasks}`),s.push(`Avg tasks per file: ${t.avgTasksPerFile.toFixed(1)}`),s.push(`Files with templates: ${t.filesWithTemplates}`),s.push(`Files with styles: ${t.filesWithStyles}`),s.push(`Files with specs: ${t.filesWithSpecs}`),s.push(""),s.join(`
2
+ `)},Jt=(e,t)=>e.length===0?Error("No files to analyze"):t.size===0?Error("No rules configured"):null,Xt=e=>({hashCache:new Map,resourceCache:new Map,directoryCache:new Map,cacheKeyCtx:e?.cacheKeyCtx}),Qt=async(e,t,s)=>{let a;if(!e.cache)return null;let{files:r,rules:l}=e,n=await ue(r,l,t.hashCache,e.cacheKeyCtx);if(t.globalHash=n,e.incremental?.forceRerun)return null;let i=e.cache.analysis,o=await i.get(n);if(o)return e.debug&&debug("planner","Analysis results cached (Short-circuit enabled)"),{tasks:[],plan:{},indexes:{filesNeedingTsAst:[],filesNeedingHtmlAst:[],filesNeedingCssAst:[],filesNeedingTypeChecker:[],tasksByFile:{},tasksByRule:{},tasksBySeverityLevel:{off:[],warn:[],error:[]},filesByType:{component:[],directive:[],pipe:[],service:[],module:[],guard:[],logic:[],"angular-class":[],spec:[],template:[],style:[],config:[],unknown:[]},tasksBySeverity:{off:0,warn:0,error:0},stats:{totalFiles:0,totalTasks:0,avgTasksPerFile:0,filesWithTemplates:0,filesWithStyles:0,filesWithSpecs:0}},skippedTasks:[],globalHash:n,precomputedAnalysis:o};let p=performance.now(),c=await e.cache.plans.get(n),u=performance.now();if(!c)return null;let d=JSON.stringify(c).length,h=performance.now();try{a=c.v===1?ye(c):c;}catch(f){debug("planner","Plan cache deserialization failed \u2014 deleting corrupted entry and rebuilding");try{await e.cache.plans.delete?.(n);}catch{}return s&&s.record(createInfrastructureError("CacheCorruption",{cause:f instanceof Error?f.message:String(f),phase:"planner",recoverable:true,details:{globalHash:n}})),null}let y=performance.now();return e.debug&&(debug("planner","Plan cache HIT"),debug("planner",` Size: ${(d/1024).toFixed(1)}KB`),debug("planner",` IO: ${(u-p).toFixed(2)}ms`),debug("planner",` Deser: ${(y-h).toFixed(2)}ms`)),{...a,globalHash:n}},Zt=async(e,t,s)=>{if(!e.cache||!t.globalHash)return;let a=performance.now();debug("planner","Saving execution plan to cache...");let r=fe(s);await e.cache.plans.set(t.globalHash,r);let l=performance.now()-a;debug("planner",` Plan cache saved in ${l.toFixed(2)}ms`);},es=(e,t)=>{let s=new Set(e.map(r=>r.ruleName)),a=[];for(let r of s){let l=t.get(r);l&&a.push(l);}return a},ts=(e,t)=>e.length===0?"":V(e[0].inputs,t),ss=async(e,t,s,a,r=1e4,l=4,n)=>{if(await as(e,a),e.length>=r){let i=await ls(e,t,a,l,n);if(i)return i}return rs(e,t,s,a,n)},as=async(e,t)=>{if(!t)return;let s=e.filter(r=>!t.has(r)&&E(r)==="logic");if(s.length===0)return;debug("planner",`Level-2 classification: scanning ${s.length} unclassified .ts files for Angular decorators`);let a=performance.now();for(let r=0;r<s.length;r+=256){let l=s.slice(r,r+256);await Promise.all(l.map(async n=>{try{let i=await readFile(n,"utf8");t.set(n,re.test(i)?"angular-class":"logic");}catch{t.set(n,"logic");}}));}debug("planner",`Level-2 classification complete in ${(performance.now()-a).toFixed(1)}ms \u2014 upgraded ${[...t.values()].filter(r=>r==="angular-class").length} files to 'angular-class'`);},rs=async(e,t,s,a,r)=>{let l=[];for(let n of e){let i=we(n,a),o=r?.length?ae(n,t,r):t,p=await J(n,i,o,s);l.push(...p);}return l},ls=async(e,t,s,a,r)=>{debug("planner",`Parallelizing task discovery across ${a} workers...`);try{let l=await ns();if(!l)return debug("planner","Worker script not found, falling back to sequential execution"),null;debug("planner",`Using worker: ${l}`);let n=is(e,a);debug("planner",`Split ${e.length} files into ${n.length} chunks`);let i=await os(n,l,t,s,r);return debug("planner",`Workers completed. Generated ${i.length} tasks.`),i}catch(l){return debug("planner",`Parallel execution failed, falling back to sequential: ${String(l)}`),null}},ns=async()=>{let{Worker:e}=await import('worker_threads'),{fileURLToPath:t}=await import('url'),{dirname:s,join:a}=await import('path'),{existsSync:r}=await import('fs'),l=s(t(import.meta.url));for(let n of [a(l,"worker.js"),a(l,"worker.cjs"),a(l,"worker.ts"),a(l,"planner","worker.js"),a(l,"planner","worker.cjs")])if(r(n))return n;return null},is=(e,t)=>{let s=Math.ceil(e.length/t),a=[];for(let r=0;r<e.length;r+=s)a.push(e.slice(r,r+s));return a},os=async(e,t,s,a,r)=>{let{Worker:l}=await import('worker_threads'),n=Array.from(s.entries()),i=a?Array.from(a.entries()):void 0,o=r?.length?[...r]:void 0,p=e.map((c,u)=>new Promise((d,h)=>{let y=new l(t,{workerData:{files:c,rulesEntries:n,fileTypeCacheEntries:i,overridesData:o}});y.on("message",f=>d(f.tasks)),y.on("error",f=>{debug("planner",`Worker ${u} error: ${String(f)}`),h(f instanceof Error?f:Error(String(f)));}),y.on("exit",f=>{f!==0&&h(Error(`Worker ${u} stopped with exit code ${f}`));});}));return (await Promise.all(p)).flat()},we=(e,t)=>{if(!t)return E(e);let s=t.get(e);if(s)return s;let a=E(e);return t.set(e,a),a},Te=(e,t,s)=>{let a=te(e),r={};for(let[l,n]of a){let i=we(l,s),o=es(n,t),p=ts(n,o),c=n.map(u=>({ruleName:u.ruleName,severity:u.severity,options:u.options,cacheKey:u.taskId,inputs:u.inputs,needsTypeChecker:u.needsTypeChecker}));r[l]={file:{path:l,type:i,hash:p},tasks:c};}return r};var ps=(e,t)=>({files:e.files,rules:t.rules,rootDir:t.rootDir,cache:t.cache,debug:t.debug,incremental:t.incremental,cacheKeyCtx:t.cacheKeyCtx,parallelThreshold:t.parallelThreshold,workerCount:t.workerCount}),cs=e=>e.files.length>0,us=e=>e.files.length;export{Re as areAllTasksCached,Yt as buildExecutionPlan,P as buildIndexes,me as buildTask,J as buildTasksForFile,V as calculateFileHash,E as detectFileType,D as discoverResources,U as filterCachedTasks,ot as filterRulesByAstRequirement,b as getBaseName,Pe as getCacheHitRate,Vt as getExecutionPlanSummary,St as getFilesForRules,us as getScanFileCount,Xe as getSpecFile,Ve as getStyleFiles,$t as getTasksCountBySeverity,Je as getTemplateFile,Ct as getTotalTasks,pt as groupRulesByDependencyType,te as groupTasksByFile,cs as hasScanFiles,R as hashFile,nt as hashFileStats,oe as hashFiles,Y as hashRules,lt as hashTaskInputs,F as isComponentFile,Ae as isSpecFile,$e as isStyleFile,Ce as isTemplateFile,Se as isTypeScriptFile,Ee as pruneStaleCache,Ye as resourceExists,ps as scanResultToPlanInput,he as shouldApplyRule};//# sourceMappingURL=index.js.map
3
3
  //# sourceMappingURL=index.js.map