JavaScript Formatter Implementation: From String Parsing to AST Beautification
JavaScript Formatter Implementation: From String Parsing to AST Beautification#
Author: JsonKit Team Date: 2026-05-10 15:31 Tool: JavaScript Formatter
Introduction#
In collaborative development, consistent code style is a persistent challenge. Have you ever received code from a colleague with messy indentation and random line breaks that reads like gibberish? A reliable JavaScript formatter becomes a lifesaver in such situations.
Today, let’s dive deep into the implementation principles of JavaScript formatting, from simple string processing to professional AST parsing, and see how to build a practical code beautification tool.
Two Technical Approaches Compared#
1. String Traversal Method (Lightweight Implementation)#
The string traversal approach is the most intuitive implementation. The core idea is to scan code character by character and apply line breaks and indentation based on specific symbols.
function beautifyJs(js, spaces = 2) {
let formatted = ''
let indentLevel = 0
const indentStr = ' '.repeat(spaces)
let inString = false
let stringChar = ''
for (let i = 0; i < js.length; i++) {
const char = js[i]
// Handle string boundaries (avoid misjudging symbols inside strings)
if ((char === '"' || char === "'" || char === '`') && !inString) {
inString = true
stringChar = char
formatted += char
continue
} else if (inString && char === stringChar && js[i - 1] !== '\\') {
inString = false
formatted += char
continue
}
if (inString) {
formatted += char
continue
}
// Handle indentation-critical symbols
if (char === '{') {
formatted += ' {\n' + indentStr.repeat(indentLevel + 1)
indentLevel++
} else if (char === '}') {
indentLevel = Math.max(0, indentLevel - 1)
formatted += '\n' + indentStr.repeat(indentLevel) + '}\n'
} else if (char === ';') {
formatted += ';\n' + indentStr.repeat(indentLevel)
}
}
return formatted.trim()
}
Pros: Small footprint, fast execution, no dependencies, ideal for real-time browser preview.
Cons: Cannot handle complex syntax (arrow functions, nested template strings), regex misjudgment, difficult comment handling.
2. AST Parsing Method (Professional Implementation)#
AST (Abstract Syntax Tree) parsing uses lexical and syntax analysis to parse code into a tree structure, then re-outputs according to unified rules.
import { parse } from '@babel/parser'
import generate from '@babel/generator'
function formatWithAST(code, options = {}) {
const ast = parse(code, {
sourceType: 'module',
plugins: ['jsx', 'typescript']
})
const output = generate(ast, {
indent: { style: ' ' },
compact: false,
retainLines: false
})
return output.code
}
Pros: Guaranteed syntax correctness, supports ES6+/TypeScript/JSX, rich configurable rules.
Cons: Large library size (Babel ecosystem 1MB+), parsing overhead.
Practical Pitfalls and Solutions#
Pitfall 1: Misjudging Symbols Inside Strings#
const obj = {
message: "This is a string with { curly braces } inside"
}
Without string boundary detection, curly braces would be mistakenly identified as code block starts.
Solution: Maintain an inString state machine, track string delimiter characters (', ", `), and handle escape characters.
Pitfall 2: Comment Handling#
// This is a single-line comment, should not be formatted
/* This is a multi-line comment
preserve original line breaks */
Content inside comments should be preserved as-is, not re-indented according to code rules.
Solution: Single-line comments detect // to \n, multi-line comments detect /* to */, skip formatting logic in these ranges.
Pitfall 3: Regex During Minification#
// Simple regex replacement during minification can cause issues
code.replace(/\/\*[\s\S]*?\*\//g, '') // Remove multi-line comments
If code contains strings with /*, the regex would mistakenly delete string content.
Solution: Use AST parser’s comments property to get actual comment positions, or use state machine character-by-character analysis.
Performance Comparison: Minification vs Beautification#
| Operation | 1KB Code | 100KB Code | 1MB Code |
|---|---|---|---|
| String Beautify | < 1ms | 15ms | 180ms |
| AST Beautify | 5ms | 120ms | 1.2s |
| String Minify | < 1ms | 8ms | 95ms |
| AST Minify | 3ms | 80ms | 800ms |
For browser-side real-time preview scenarios, the string method handles most needs adequately. For production deployment, mature tools like Prettier are recommended.
Real-World Use Cases#
- Code Review: Standardize team code style, reduce formatting debates during reviews
- Reverse Engineering: Beautify minified JavaScript for easier analysis of third-party libraries
- Teaching Demos: Expand single-line code to multiple lines for explaining execution flow
- Bundle Optimization: Minification reduces 30-50% file size, speeds up network transfer
Best Practice Recommendations#
- Use beautification in development, minification in production
- Team projects should standardize on Prettier + ESLint configuration
- Browser-side tools should prioritize lightweight string methods
- Complex projects (TS/JSX) must use AST parsing
Related Tools#
- JSON Formatter - Format JSON data with one-click beautify/compress
- CSS Formatter - CSS code beautification and minification
- HTML Formatter - HTML code formatting
This article covers the core implementation principles of JavaScript formatters. For more developer tools, visit JsonKit.