@playform/eliminate
Version:
Eliminate ↘️
2 lines (1 loc) • 7.71 kB
JavaScript
const{forEachChild:I,getLeadingCommentRanges:C,isAwaitExpression:U,isBinaryExpression:x,isCallExpression:E,isConditionalExpression:P,isFunctionDeclaration:f,isIdentifier:h,isPropertyAccessExpression:_,isThisTypeNode:v,isVariableDeclaration:y,isVariableStatement:b,isYieldExpression:k,NodeFlags:D,SymbolFlags:A,SyntaxKind:{AmpersandAmpersandEqualsToken:O,AmpersandEqualsToken:V,AsteriskEqualsToken:z,AsyncKeyword:w,BarBarEqualsToken:R,BarEqualsToken:q,CaretEqualsToken:M,DefaultKeyword:T,EqualsToken:L,ExportKeyword:d,GreaterThanGreaterThanEqualsToken:F,GreaterThanGreaterThanGreaterThanEqualsToken:B,LessThanLessThanEqualsToken:$,MinusEqualsToken:K,MinusMinusToken:m,PercentEqualsToken:G,PlusEqualsToken:Q,PlusPlusToken:g,PostfixUnaryExpression:Y,PrefixUnaryExpression:j,QuestionQuestionEqualsToken:H,SlashEqualsToken:J},visitEachChild:u,visitNode:c}=await import("typescript");class W{Usage=new Map;Type;Option;Change=!1;constructor(a={}){this.Option={Comment:!0,Max:100,Async:!1,Const:!1,Function:!1,Debug:!1,...a}}_FunctionInline(a,n){const t=(e,r=0)=>{if(r>100)return console.log("Recursion depth limit reached in _FunctionInline"),e;if(f(e)){if(e.typeParameters&&e.typeParameters.length>0||!e.name)return e;const i=this.Type?.getSymbolAtLocation(e.name);if(i){const s=this.Usage.get(i);if(s?.Inline&&s.Reference.length===2){this.Change=!0;return}}}return u(e,i=>t(i,r+1),n)};return c(a,t)}_VariableInline(a,n){const t=(e,r=0)=>{if(r>100)return console.log("Recursion depth limit reached in _VariableInline"),e;if(b(e)){const i=e.declarationList.declarations,s=i.filter(o=>{const p=this.Type?.getSymbolAtLocation(o.name);if(!p)return!0;const l=this.Usage.get(p);return l?!(l.Inline&&l.Reference.length===2):!0});if(s.length===0){this.Change=!0;return}if(s.length!==i.length)return this.Change=!0,n.factory.updateVariableStatement(e,e.modifiers,n.factory.createVariableDeclarationList(s,e.declarationList.flags))}return u(e,i=>t(i,r+1),n)};return c(a,t)}_CallExpressionInline(a,n){const t=(e,r=0)=>{if(r>100)return console.log("Recursion depth limit reached in _CallExpressionInline"),e;if(E(e)){const i=e.expression;if(h(i)){const s=this.Type?.getSymbolAtLocation(i);if(s&&this.Usage.has(s)){const o=this.Usage.get(s);if(f(o.Declaration)&&o.Declaration.typeParameters&&o.Declaration.typeParameters.length>0)return e;if(o.Inline&&o.Reference.length===2&&f(o.Declaration))return this.Change=!0,n.factory.updateCallExpression(e,n.factory.createParenthesizedExpression(n.factory.createArrowFunction(o.Declaration.modifiers,o.Declaration.typeParameters,o.Declaration.parameters,o.Declaration.type,void 0,o.Declaration.body)),e.typeArguments,e.arguments)}}}return u(e,i=>t(i,r+1),n)};return c(a,t)}_BinaryExpressionInline(a,n){const t=(e,r=0)=>{if(r>100)return console.log("Recursion depth limit reached in _BinaryExpressionInline"),e;if(x(e)){const i=c(e.left,t),s=c(e.right,t);if(i!==e.left||s!==e.right)return this.Change=!0,n.factory.createParenthesizedExpression(n.factory.createBinaryExpression(i,e.operatorToken,s))}return u(e,i=>t(i,r+1),n)};return c(a,t)}_ExpressionInline(a,n){const t=(e,r=0)=>{if(r>100)return console.log("Recursion depth limit reached in _ExpressionInline"),e;if(h(e)){if(y(e.parent)&&e.parent.name===e||f(e.parent)&&e.parent.name===e)return e;const i=this.Type?.getSymbolAtLocation(e),s=i&&this.Usage.get(i);if(s?.Inline&&!s.Modified&&s.Reference.length===2&&y(s.Declaration)&&s.Declaration.initializer){const o=this.Iterative(s.Declaration.initializer,n);return this.Change=!0,x(o)||P(o)?n.factory.createParenthesizedExpression(o):o}}return u(e,i=>t(i,r+1),n)};return c(a,t)}Iterative(a,n){try{if(this.Option.Debug)for(const[r,i]of this.Usage)console.log(`Variable: ${r.name}`),console.log(`- Reference: ${i.Reference.length}`),console.log(`- Inline: ${i.Inline}`),console.log(`- Size: ${i.Size}`),console.log(`- Text: ${i.Declaration.getText()}`)}catch(r){console.log(r)}let t=a,e=0;do{this.Change=!1,t=this._FunctionInline(t,n),t=this._VariableInline(t,n),t=this._CallExpressionInline(t,n),t=this._BinaryExpressionInline(t,n),t=this._ExpressionInline(t,n),e++;try{this.Option.Debug&&(console.log(`Iteration: ${e}`),console.log(`Node: ${t.getText()}`))}catch(r){console.log(r)}}while(this.Change&&e<100);return e>=100&&console.log("Potential infinite loop detected in AST transformations!"),t}Transform(a){return this.Type=a.getTypeChecker(),n=>t=>(this.Collect(t),this.Iterative(t,n))}Collect(a){const n=r=>{if(y(r)||f(r)){if(!r.name)return;const i=this.Type?.getSymbolAtLocation(r.name);if(i){let s=!0,o=0;if(y(r)){this.Option.Const&&r.parent?.parent?.flags&D.Const&&(s=!1);const l=r.parent.parent;b(l)&&l.modifiers&&l.modifiers.some(({kind:S})=>S===d||S===T)&&(s=!1),r.initializer&&(s=s&&this.Inline(r.initializer),o=this.Size(r.initializer))}else f(r)&&(this.Option.Function&&(s=!1),r.modifiers?.some(({kind:l})=>l===d||l===T||this.Option.Async&&l===w)&&(s=!1),o=this.Size(r));this.Comment(r)&&(s=!1);const p=new Set;this.Call(r,p),this.Usage.set(i,{Declaration:r,Reference:[],Inline:s,Size:o,Modified:!1,Call:p})}}else if(h(r)){const i=this.Type?.getSymbolAtLocation(r);if(i&&this.Usage.has(i)){const s=this.Usage.get(i);s?.Reference.push(r),s&&this.Modification(r)&&(s.Modified=!0)}}I(r,n)};n(a);const t=new Map;for(const[r,i]of this.Usage)f(i.Declaration)&&t.set(r,i.Call);const e=this.Cycle(t);for(const r of e)for(const i of r){const s=this.Usage.get(i);s&&(s.Inline=!1)}}Cycle(a){const n=new Set,t=new Set,e=[],r=(i,s)=>{if(t.has(i)){e.push(new Set(s.slice(s.indexOf(i))));return}if(!n.has(i)){n.add(i),t.add(i);for(const o of a.get(i)||new Set)r(o,[...s,o]);t.delete(i)}};for(const i of a.keys())n.has(i)||r(i,[i]);return e}Call(a,n){if(E(a)&&h(a.expression)){const t=this.Type?.getSymbolAtLocation(a.expression);t&&n.add(t)}a.forEachChild(t=>this.Call(t,n))}Modification(a){const n=a.parent;if(this.isPostfixUnaryExpression(n)){const t=n;if(t.operator===g||t.operator===m)return!0}if(this.isPrefixUnaryExpression(n)){const t=n;if(t.operator===g||t.operator===m)return!0}return!!(x(n)&&n.left===a&&this.Operator(n.operatorToken.kind))}isPostfixUnaryExpression({kind:a,operator:n}){return a===Y?n===g||n===m:!1}isPrefixUnaryExpression({kind:a,operator:n}){return a===j?n===g||n===m:!1}Operator(a){return[O,V,z,R,q,M,L,F,B,$,K,G,Q,H,J].includes(a)}Size(a){let n=0;const t=e=>{n++,I(e,t)};return t(a),n}Comment(a){return this.Option.Comment?(C(a.getSourceFile().text,a.pos)||[]).length>0:!1}Inline(a){if(this.Size(a)>(this.Option.Max||Number.POSITIVE_INFINITY)||this.Option.Async&&U(a)||v(a)||k(a))return!1;if(_(a)){const t=this.Type?.getTypeAtLocation(a.expression)?.getProperty(a.name.text);if(t?.flags&&t?.flags&A.Accessor)return!1}let n=!0;return a.forEachChild(t=>{this.Inline(t)||(n=!1)}),n}}export{O as AmpersandAmpersandEqualsToken,V as AmpersandEqualsToken,z as AsteriskEqualsToken,w as AsyncKeyword,R as BarBarEqualsToken,q as BarEqualsToken,M as CaretEqualsToken,T as DefaultKeyword,L as EqualsToken,d as ExportKeyword,F as GreaterThanGreaterThanEqualsToken,B as GreaterThanGreaterThanGreaterThanEqualsToken,$ as LessThanLessThanEqualsToken,K as MinusEqualsToken,m as MinusMinusToken,D as NodeFlags,G as PercentEqualsToken,Q as PlusEqualsToken,g as PlusPlusToken,Y as PostfixUnaryExpression,j as PrefixUnaryExpression,H as QuestionQuestionEqualsToken,J as SlashEqualsToken,A as SymbolFlags,W as default,I as forEachChild,C as getLeadingCommentRanges,U as isAwaitExpression,x as isBinaryExpression,E as isCallExpression,P as isConditionalExpression,f as isFunctionDeclaration,h as isIdentifier,_ as isPropertyAccessExpression,v as isThisTypeNode,y as isVariableDeclaration,b as isVariableStatement,k as isYieldExpression,u as visitEachChild,c as visitNode};