rollup-plugin-circular-dependencies
Version:
Detect circular dependencies in Rollup projects
2 lines (1 loc) • 5.17 kB
JavaScript
import{createFilter as e}from"@rollup/pluginutils";import{dirname as t,join as o,relative as n}from"node:path";import r from"chalk";import{isObject as i,isNil as s,isString as u}from"lodash-es";import{existsSync as d,mkdirSync as c,writeFileSync as l}from"node:fs";const a={JSON:function(){return e=>Array.isArray(e)||i(e)?JSON.stringify(e,null,2):e??""},Pretty:function(e){const{colors:t=!0}=e||{};return e=>{if(!s(e)&&i(e)&&0===Object.keys(e).length)return"";if(!function(e){if(e&&i(e)){const[t]=Object.values(e);if(Array.isArray(t)){const[e]=t;if(Array.isArray(e)&&e.every(u))return!0}}return!1}(e))throw new Error("Pretty formatter can only be used with original output");const o=[];for(const n of Object.entries(e)){const[e,i]=n;let s="";s+=t?r.yellow(e):e;for(const e of i)s+="\n "+e.join(t?r.blue(" -> "):" -> ");o.push(s)}return o.join("\n\n")}}};function f(e,t){const o=new Set,n=e.moduleNodes;!function e(t){o.add(t.id);const r=function(e){return e.importedIds.reduce(((e,t)=>{const o=n.get(t);return o&&e.push(o),e}),[])}(t);for(const n of r)o.has(n.id)||e(n),t.children.add(n)}(t)}function h(e,t,o){const n=[];let r=e;do{if(n.push(r),0===r.children.size)break;r=Array.from(r.children).find((e=>t.has(e.id)))}while(r&&r!==e);const i=n.sort(((e,t)=>e.id<t.id?-1:1)),s=i.map((e=>e.id)).join("-");o.set(s,i)}class p{constructor(e){Object.defineProperty(this,"ctx",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.ctx=e.context}shouldPrint(e){return!0}}class m extends p{shouldPrint(){return Boolean(this.ctx.options.outputFilePath)}print(e){const o=e?e.toString():"",n=t(this.ctx.options.outputFilePath);d(n)||c(n,{recursive:!0}),l(this.ctx.options.outputFilePath,o,{encoding:"utf-8"})}}class b extends p{shouldPrint(e){const t=!this.ctx.options.outputFilePath,o=e||0===e||"string"==typeof e&&e.length>0;return t&&o}print(e){console.info("\n\n"+e?.toString()+"\n")}}const w="Circular dependencies has been detected";function y(e,t,o){const n=function(e){return e.reduce(((e,t)=>{const o=t[0];return e[o]??(e[o]=[]),e[o].push(t),e}),{})}(function(e){return e.map((e=>e.map((e=>e.id))))}((r=t,Array.from(r.values()).filter((e=>e.length)))));var r;const i=e.options.formatOut(function(e,t){const o={};for(const[n,r]of Object.entries(t))o[e.options.formatOutModulePath(n)]=r.map((t=>t.map((t=>e.options.formatOutModulePath(t)))));return o}(e,n));e.options.onEnd({rawOutput:n,formattedOutput:i},o);for(const t of[new m(s={context:e}),new b(s)])t.shouldPrint(i)&&t.print(i);var s;!function(e,t,o){const n=t.options.throwOnError?o.error:o.warn;Object.keys(e).length>0&&n(w)}(n,e,o)}const P=[/[\\/]node_modules[\\/]/,/[\\/]\.git[\\/]/];function O(e){const{enabled:t=!0,include:n=[/\.[jt]sx?$/],throwOnError:r=!0,formatOutModulePath:i,formatOut:s,onStart:u,onDetected:d,onEnd:c}=e;let{exclude:l=P,outputFilePath:a=""}=e;return l=function(e){if(Array.isArray(e))return[...e,...P];if(e)return[e,...P];return P}(l),a=function(e){if(e)return o(process.cwd(),e);return e}(a),{enabled:t,include:n,exclude:l,throwOnError:r,outputFilePath:a,formatOutModulePath:i??g,formatOut:s??v(a),onStart:u??(()=>{}),onDetected:d??(()=>{}),onEnd:c??(()=>{})}}function g(e){return n(process.cwd(),e)}function v(e){return t=>e?a.JSON()(t):a.Pretty({colors:!0})(t)}class N{constructor(t){Object.defineProperty(this,"options",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"shouldProcessModule",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_moduleNode",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"moduleNodes",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.options=O(t),this.shouldProcessModule=e(this.options.include,this.options.exclude),this.moduleNodes=new Map}get moduleNode(){return this._moduleNode}set moduleNode(e){this._moduleNode||(this._moduleNode=e)}}class j{constructor(e){Object.defineProperty(this,"id",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"importedIds",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"children",{enumerable:!0,configurable:!0,writable:!0,value:new Set}),this.id=e.id,this.importedIds=[...e.importedIds,...e.dynamicallyImportedIds]}}function x(e={}){const t=new N(e);return{name:"circular-dependencies",options(e){const t=e.onLog;e.onLog=(e,o,n)=>{"CIRCULAR_DEPENDENCY"!==o.code&&t?.(e,o,n)}},moduleParsed(e){if(!t.options.enabled||!t.shouldProcessModule(e.id))return;const o=new j(e);t.moduleNode=o,t.moduleNodes.set(e.id,o)},generateBundle(){const e=this;if(!t.moduleNode)return void(t.options.enabled&&e.info('No files to check. Check the "include" or "exclude" pattern in the "circular-dependencies" plugin options.'));t.options.onStart(e),f(t,t.moduleNode);const o=function(e,t,o){const n=new Map,r=new Set,i=new Set;return function t(s,u){if(!r.has(s.id)){u.add(s.id);for(const r of s.children)u.has(r.id)?(i.has(r.id)||e.options.onDetected(r.id,o),i.add(r.id),h(r,u,n)):t(r,u);r.add(s.id),u.delete(s.id)}}(t,new Set),n}(t,t.moduleNode,e);y(t,o,e)}}}export{a as DefaultFormatters,x as circularDependencies,x as default};