Code generation from AST back to source text. esotope-style compact code output, format-preserving reprint, and round-trip AST → source pipelines for codemods and refactoring tools. Sources: glaynge/esotope (BSD-2-Clause).
Scanned 9/9/2026
Install to Claude Code
npx -y skills add yanacuti1121/Yana-AI --skill ast-codegen-patterns --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Ast Codegen Patterns?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/yanacuti1121-ast-codegen-patterns)More formats (shields.io, HTML) on the badges page.
---
name: ast-codegen-patterns
description: Code generation from AST back to source text. esotope-style compact code output, format-preserving reprint, and round-trip AST → source pipelines for codemods and refactoring tools. Sources: glaynge/esotope (BSD-2-Clause).
origin: yana-ai — synthesized from glaynge/esotope (BSD-2-Clause), escodegen (BSD-2-Clause)
license: Apache-2.0
version: 1.0.0
compatibility: yana-ai >= 1.3.49
---
# /ast-codegen-patterns
## When to Use
- Regenerate source from a modified AST (after [[babel-ast-transform]] or [[estree-ast-spec]] walker)
- Format-preserving reprints: preserve whitespace/comments in unmodified subtrees
- Round-trip pipelines: parse → mutate → generate → diff
- Custom code generation: emit domain-specific patterns from data models
## Do NOT use for
- Full Babel transform pipelines (use [[babel-ast-transform]] which includes generate)
- TypeScript codegen from scratch (use [[ts-morph-refactor]] for type-safe generation)
---
## ESTree → source (escodegen)
```javascript
import escodegen from 'escodegen'
import { parse } from 'acorn'
const source = `
const arr = [1, 2, 3]
const doubled = arr.map(x => x * 2)
`
const ast = parse(source, { ecmaVersion: 2022, sourceType: 'module' })
// Mutate AST: rename 'doubled' → 'multiplied'
function rename(node, from, to) {
if (!node || typeof node !== 'object') return
if (node.type === 'Identifier' && node.name === from) node.name = to
for (const key of Object.keys(node)) rename(node[key], from, to)
}
rename(ast, 'doubled', 'multiplied')
const output = escodegen.generate(ast, {
format: {
indent: { style: ' ' },
quotes: 'single',
semicolons: true,
},
comment: true, // preserve comments from original
})
console.log(output)
// const arr = [1, 2, 3];
// const multiplied = arr.map(x => x * 2);
```
---
## Source map–aware generation
```javascript
import escodegen from 'escodegen'
import { SourceMapConsumer } from 'source-map'
const { code, map } = escodegen.generate(ast, {
sourceMap: 'input.js',
sourceMapWithCode: true,
format: { compact: false },
})
// map is a SourceMapGenerator — serialize for output
const sourceMapString = map.toString()
const codeWithMap = code + '\n//# sourceMappingURL=data:application/json;base64,'
+ Buffer.from(sourceMapString).toString('base64')
```
---
## Manual AST builder (no parser needed)
```javascript
// Build `export const VERSION = "1.0.0"` from scratch
function buildVersionExport(version: string) {
return {
type: 'ExportNamedDeclaration',
declaration: {
type: 'VariableDeclaration',
kind: 'const',
declarations: [{
type: 'VariableDeclarator',
id: { type: 'Identifier', name: 'VERSION' },
init: { type: 'Literal', value: version, raw: JSON.stringify(version) },
}],
},
specifiers: [],
source: null,
}
}
const program = {
type: 'Program',
body: [buildVersionExport('1.0.0')],
sourceType: 'module',
}
console.log(escodegen.generate(program))
// export const VERSION = '1.0.0';
```
---
## Round-trip codemod helper
```typescript
import { parse } from 'acorn'
import escodegen from 'escodegen'
export function codemod(
source: string,
mutate: (ast: any) => void,
options: escodegen.GenerateOptions = {}
): string {
const ast = parse(source, {
ecmaVersion: 2022,
sourceType: 'module',
onComment: (block, text, start, end) => {
// attach comments to nearest node for escodegen to reprint
},
})
mutate(ast)
return escodegen.generate(ast, {
comment: true,
format: { indent: { style: ' ' }, ...options },
})
}
```
---
## Anti-Fake-Pass Checklist
```
❌ escodegen.generate on Babel AST → Babel adds non-ESTree nodes; strip them first
❌ comment: false → all comments lost in round-trip
❌ Mutating raw node.loc values → code generation uses loc for source maps; corruption
❌ compact: true in a codemod → diffs become unreadable one-liners
❌ Manual AST missing 'raw' field on Literal → some generators produce undefined
❌ sourceMap: 'filename' must match the original filename exactly or stack traces break
```
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!