name: pass-workflow description: "Universal guide for all unmangleJS pass development tasks. Covers creating, modifying, debugging, refactoring, reviewing, and documenting passes. Integrates with existing project documentation - see CLAUDE.md for complete Pass System guide."
Pass Development Workflow
Universal guide for all unmangleJS pass operations.
📚 Essential Prerequisites
Before working on passes, read these:
-
- Complete guide to pass architecture and lifecycle
- Development workflow and best practices
- Five-file sync rule
-
Babel API Gotchas → docs/en/babel-api-gotchas.md
- Critical pitfalls when working with Babel
- Scope and binding issues
- Reference invalidation
-
Utils Overview → docs/en/utils-overview.md
- Available utility functions
- When to use utils vs implementing in pass
🎯 Quick Task Navigator
What do you want to do?
🆕 Create New Pass
Step-by-step workflow:
- Design: What obfuscation pattern does this pass target?
- Implement: See Pass Structure → references/pass-structure.md
- Test: See Testing Guide → references/testing-guide.md
-
Document: Follow pattern in
docs/en/passes/constant-folding.md -
Register: Add to
src/passes/registry.tsandsrc/passes/index.ts
Quick Template:
# Copy existing pass as template
cp src/passes/constant-folding.ts src/passes/my-pass.ts
# Edit to implement your transformation
Validation:
npm test tests/passes/my-pass.test.ts
npm run lint
npm run build
✏️ Modify Existing Pass
When adding transformations or fixing bugs:
-
Read current implementation:
# View all files for the pass ls -1 src/passes/<name>.ts \ tests/passes/<name>.test.ts \ examples/<name>.js \ docs/en/passes/<name>.md \ docs/zh-CN/passes/<name>.md -
Add tests first (TDD):
// tests/passes/<name>.test.ts it("should handle new pattern", async () => { const input = "<obfuscated>"; const { code } = await unmangle(input, [yourPass]); expect(code).toContain("<deobfuscated>"); }); -
Implement transformation:
- See Babel patterns → CLAUDE.md
- Use utils from
src/utils/(see Utils Overview → docs/en/utils-overview.md) - Mark dirty:
ctx.markAstDirty(),ctx.markScopeDirty()
-
Update all 5 files:
- Implementation
- Tests
- Examples
- English docs
- Chinese docs
Validation:
npm test tests/passes/<name>.test.ts
./bin/unmanglejs.js examples/<name>.js -p
🐛 Debug Pass Issues
Debugging workflow:
-
Isolate the issue:
cat > tmp/debug.js << 'EOF' // Minimal reproduction const x = <problematic code>; EOF ./bin/unmanglejs.js tmp/debug.js -p -d -
Check common issues:
- ❌ Forgot
ctx.markAstDirty()? - ❌ Using
path.nodeafterreplaceWith()? - ❌ Missing
path.skip()after replacement? - ❌ Scope issues? Read Babel API Gotchas → docs/en/babel-api-gotchas.md
- ❌ Forgot
-
Add logging:
ctx.log.at(path).debug("Checking pattern"); ctx.log.at(path).debug("Pattern matched, transforming"); -
Test with single pass:
./bin/unmanglejs.js input.js -p <pass-name> -d
Common debugging scenarios:
-
Infinite loop: Missing
path.skip()→ see Babel Gotchas → docs/en/babel-api-gotchas.md -
Wrong transformations: Check transformation logic, verify with
tryEvaluateConstant() - Scope errors: Read Scope Management → docs/en/babel-api-gotchas.md
🔄 Refactor Pass Code
When to refactor:
- Code duplication across passes → extract to
src/utils/ - Complex visitor logic → simplify with helper functions
- Performance issues → see CLI Performance → docs/en/cli.md
Extraction workflow:
- Identify reusable logic
-
Extract to
src/utils/<name>.ts -
Create utils tests:
tests/utils/<name>.test.ts - Update imports in all passes using the logic
-
Validate:
npm test tests/utils/ npm test
Example:
// BEFORE: In multiple passes
if (path.node.type === "Identifier" && path.node.name.length > 10) { }
// AFTER: Extract to utils
// src/utils/identifier.ts
export function isLongIdentifier(path: NodePath<t.Identifier>): boolean {
return path.node.name.length > 10;
}
// In pass
import { isLongIdentifier } from "../utils/identifier.js";
if (isLongIdentifier(path)) { }
📝 Update Pass Documentation
Documentation resources:
For structure reference:
- constant-folding.md → docs/en/passes/constant-folding.md
- proxy-object-removal.md → docs/en/passes/proxy-object-removal.md
Five-file sync checklist:
-
src/passes/<name>.ts- Implementation -
tests/passes/<name>.test.ts- Tests -
examples/<name>.js- Examples -
docs/en/passes/<name>.md- English docs -
docs/zh-CN/passes/<name>.md- Chinese docs
Validation:
# Test examples match docs
./bin/unmanglejs.js examples/<name>.js -p
# Verify structure
grep "^##" docs/en/passes/<name>.md
grep "^##" docs/zh-CN/passes/<name>.md
# Should have matching section counts
🧪 Fix Pass Tests
Testing resources:
Common test issues:
-
Tests timeout (>10s):
- Cause: Infinite loop in visitor
- Fix: Add
path.skip()after replacement
-
Transformation not applied:
- Cause: Pattern matching too restrictive
- Fix: Adjust conditions, use
tryEvaluateConstant()
-
Test expects wrong output:
- Cause: Test is brittle or outdated
- Fix: Update test to match actual deobfuscation behavior
⚙️ Adjust Pass Execution Order
Pass order is defined in: src/passes/registry.ts
Current order:
export const PASS_REGISTRY: Record<string, Pass> = {
"string-array-decode": allPasses.stringArrayDecodePass,
"proxy-object-removal": allPasses.proxyObjectRemoval,
"array-unpacking": allPasses.arrayUnpacking,
// ... (see full file)
};
To change order:
- Edit
src/passes/registry.ts - Reorder keys (object key insertion order defines execution order)
- Test with specific passes:
./bin/unmanglejs.js input.js -p pass1,pass2,pass3
Verification:
./bin/unmanglejs.js --list-passes
🗑️ Remove Deprecated Pass
Safe removal workflow:
-
Remove from registry:
# src/passes/registry.ts - remove pass from PASS_REGISTRY # src/passes/index.ts - remove export -
Delete all 5 files:
rm src/passes/<name>.ts rm tests/passes/<name>.test.ts rm examples/<name>.js rm docs/en/passes/<name>.md rm docs/zh-CN/passes/<name>.md -
Validate:
npm test npm run build ./bin/unmanglejs.js --list-passes # Verify removed
🔧 Essential Quick Reference
The Five-File Rule
Each public pass SHOULD maintain 5 files:
-
src/passes/<pass-name>.ts- Implementation -
tests/passes/<pass-name>.test.ts- Tests -
examples/<pass-name>.js- Examples -
docs/en/passes/<pass-name>.md- English docs -
docs/zh-CN/passes/<pass-name>.md- Chinese docs
Note: Internal utility passes or helper transformations may omit documentation files.
Critical Commands
# Test single pass
npm test tests/passes/<name>.test.ts
# Run with custom passes
./bin/unmanglejs.js input.js -p pass1,pass2,pass3
# Check pass order
./bin/unmanglejs.js --list-passes
# Debug output
./bin/unmanglejs.js input.js -p -d
# Test examples
./bin/unmanglejs.js examples/<name>.js -p
Common Gotchas
- ❌ Don't forget
ctx.markAstDirty()after modifications - ❌ Don't use
path.nodeafterreplaceWith() - ❌ Don't call other passes directly
- ❌ Don't share context across passes
- ✅ Do use
tryEvaluateConstant()for literals - ✅ Do use
getIdentifierBinding()for function names - ✅ Do clone nodes with
t.cloneNode()when reusing - ✅ Do use
path.skip()after replacement
Utils Available
Import from src/utils/:
-
tryEvaluateConstant(path)- Safely evaluate literals -
getIdentifierBinding(path)- Handle hoisting correctly -
valueToExpression(value, node)- Convert values to AST -
generateUniqueName(scope)- Create non-colliding names
See Utils Overview → docs/en/utils-overview.md for complete reference.
📖 Detailed References
Core Project Documentation
- CLAUDE.md - Pass System - Complete pass development guide
- Babel API Gotchas - Critical Babel pitfalls
- Passes Overview - All passes with examples
- Utils Overview - Available utilities
- CLI Reference - Command-line usage
Skill-Specific References
- Pass Structure → references/pass-structure.md - Implementation patterns
- Testing Guide → references/testing-guide.md - Test strategies
- Checklists → workflows/checklist.md - Universal checklists
Example Pass Documentation
Use these as templates for documenting new passes:
- constant-folding.md → docs/en/passes/constant-folding.md
- proxy-object-removal.md → docs/en/passes/proxy-object-removal.md
- sequence-flattening.md → docs/en/passes/sequence-flattening.md
🚀 Getting Started
New to pass development?
- Read Pass System → CLAUDE.md
- Read Babel API Gotchas → docs/en/babel-api-gotchas.md
- Study example:
src/passes/constant-folding.ts - Follow Create New Pass workflow above
Experienced developer?
Jump to the task navigator above.
chat Comments (0)
Sign in to join the discussion and leave a comment.
Skill Details
Related Skills
Build your own?
Join 12,000+ developers contributing to the Claude ecosystem.
No comments yet. Be the first to share your thoughts!