exfoliate
v0.0.8
Published
Function inliner for reducing code complexity
Readme
exfoliate - JavaScript Function Inliner
A comprehensive AST-based function inliner for reducing code complexity and flattening nested function calls.
Features
Smart Inlining Strategy
- Single-use functions are inlined: Functions called exactly once are automatically inlined
- Multi-use functions are preserved: Functions called multiple times remain as reusable methods
- Predictable and reliable: Uses topological sorting to inline dependencies in the correct order
Complete Scope Management
- Variable conflict resolution: Automatically renames variables that would conflict
- Parameter substitution: Replaces function parameters with actual arguments
- Shadowing prevention: Handles variable shadowing correctly
Early Return Handling
- Semantic preservation: Correctly handles early returns using control flow flags
- Nested returns: Properly transforms returns inside if statements and blocks
- Control flow integrity: Ensures code after early returns doesn't execute
Example
Before:
export class D {
constructor() {
this._super_C_constructor();
console.log('d');
}
_super_A_constructor() {
console.log('a');
}
_super_B_constructor() {
this._super_A_constructor();
console.log('b');
}
_super_C_constructor() {
this._super_B_constructor();
console.log('c');
}
}After:
export class D {
constructor() {
console.log('a');
console.log('b');
console.log('c');
console.log('d');
}
}Usage
import { inline } from './inliner.js';
import { readFileSync } from 'fs';
const code = readFileSync('./your-file.js', 'utf-8');
const inlinedCode = await inline(code);
console.log(inlinedCode);How It Works
1. Call Graph Analysis
Analyzes which functions call which, and counts how many times each function is called.
2. Candidate Selection
Identifies functions called exactly once as candidates for inlining.
3. Topological Ordering
Sorts functions so that dependencies are inlined first (leaves to root).
4. AST Transformation
For each inlined function:
- Clone the function body
- Rename local variables to avoid conflicts
- Substitute parameters with arguments
- Handle return statements with control flow flags if needed
- Replace the call site with the transformed body
5. Code Generation
Generates clean, formatted code using astring and prettier.
Advanced Features
Early Return Transformation
Original:
function validate(value) {
if (value < 0) {
return false;
}
if (value > 100) {
return false;
}
return true;
}Inlined:
let result$1;
let returned_result$1 = false;
if (!returned_result$1) {
if (num < 0) {
result$1 = false;
returned_result$1 = true;
}
}
if (!returned_result$1) {
if (num > 100) {
result$1 = false;
returned_result$1 = true;
}
}
if (!returned_result$1) {
result$1 = true;
}Variable Shadowing Resolution
Original:
function shadowTest() {
const temp = 5;
const result = helper(temp);
return result;
}
function helper(x) {
const temp = x + 10; // Shadows outer temp
return temp;
}Inlined:
function shadowTest() {
const temp = 5;
const temp$1 = temp + 10; // Renamed to avoid conflict
const result = temp$1;
return result;
}Multi-use Function Preservation
// _reusable_log is called 3 times, so it's NOT inlined
_reusable_log(message) {
console.log('[LOG]', message);
}
method1() {
this._reusable_log('From method1');
return 1;
}
method2() {
this._reusable_log('From method2');
return 2;
}Test Results
From the test module:
- Original code: 3,848 characters
- Inlined code: 2,923 characters
- Reduction: ~24%
- Functions analyzed: 32
- Inline candidates: 15
- Functions inlined: 15
- Preserved (multi-use): 2 (
_reusable_log,_multiple_a)
Use Cases
- Flattening inheritance chains: Inline super constructor calls
- Removing helper abstraction overhead: Inline single-use helper methods
- Simplifying code flow: Make code more linear and easier to understand
- Improving AI collaboration: Reduce indirection for better AI code analysis
Architecture
ScopeTracker: Manages variable bindings and generates unique namesCallGraphAnalyzer: Builds call graph and counts function usageSimpleVariableRenamer: Renames variables to avoid conflictsParameterSubstituter: Replaces parameter references with argumentsReturnHandler: Transforms return statements for inliningInliner: Main orchestrator that coordinates the inlining process
Limitations
- Recursive functions cannot be inlined (detected and rejected)
- External function calls are not analyzed
- Dynamic calls (e.g., via
call,apply) are not tracked - Requires valid JavaScript that parses with acorn
Dependencies
acorn: JavaScript parserastring: AST to code generatorprettier: Code formatter
License
MIT
