A JavaScript parser built from the Hermes engine that supports ES6, Flow, and JSX syntax
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Utilities for modifying and transforming AST nodes with immutable patterns and parent pointer management.
Main class for transforming AST nodes with callback-based mutation and automatic parent pointer management.
/**
* A simple class for recursively transforming AST trees
*/
class SimpleTransform {
/**
* Transform AST tree with callback (static method)
* @param node - Root AST node to transform
* @param options - Transformation configuration
* @returns Transformed node or null if removed
*/
static transform(node: ESNode, options: TransformOptions): ESNode | null;
/**
* Transform Program node specifically
* @param program - Program AST node to transform
* @param options - Transformation configuration
* @returns Transformed Program node
*/
static transformProgram(program: Program, options: TransformOptions): Program;
/**
* Create new node with property overrides
* @param node - Base AST node to modify
* @param overrideProps - Properties to override
* @param visitorKeys - Optional visitor keys for parent pointer management
* @returns New node with overrides or original if unchanged
*/
static nodeWith<T extends ESNode>(
node: T,
overrideProps: Partial<T>,
visitorKeys?: VisitorKeysType
): T;
/**
* Transform AST tree with callback (instance method)
* @param rootNode - Root AST node to transform
* @param options - Transformation configuration
* @returns Transformed node or null if removed
*/
transform(rootNode: ESNode, options: TransformOptions): ESNode | null;
}
interface TransformOptions {
/** Callback invoked for each node to perform transformation */
transform: TransformCallback;
/** Custom visitor keys for traversal (optional) */
visitorKeys?: VisitorKeysType;
}
/**
* Transform callback function
* @param node - Current AST node being visited
* @returns Modified node, original node, or null to remove
*/
type TransformCallback = (node: ESNode) => ESNode | null;Usage Examples:
import { SimpleTransform } from "hermes-parser";
const ast = parse("const x = 1; const y = 2;");
// Remove all const declarations
const transformed = SimpleTransform.transform(ast, {
transform(node) {
if (node.type === "VariableDeclaration" && node.kind === "const") {
return null; // Remove this node
}
return node; // Keep unchanged
}
});
// Transform literals to double their value
const doubled = SimpleTransform.transform(ast, {
transform(node) {
if (node.type === "Literal" && typeof node.value === "number") {
return {
...node,
value: node.value * 2,
raw: String(node.value * 2)
};
}
return node;
}
});
// Use transformProgram for program-specific transforms
const program = SimpleTransform.transformProgram(ast, {
transform(node) {
// Add "use strict" directive at the beginning
if (node.type === "Program") {
return {
...node,
body: [
{
type: "ExpressionStatement",
expression: {
type: "Literal",
value: "use strict",
raw: '"use strict"'
}
},
...node.body
]
};
}
return node;
}
});Helper functions for creating and modifying AST nodes with proper parent pointer management.
/**
* Create new node with property overrides, maintaining referential equality when possible
* @param node - Base AST node
* @param overrideProps - Properties to override
* @param visitorKeys - Optional visitor keys for parent management
* @returns New node with overrides or original if unchanged
*/
function nodeWith<T extends ESNode>(
node: T,
overrideProps: Partial<T>,
visitorKeys?: VisitorKeysType
): T;
/**
* Shallow clone an AST node with correct parent pointers
* @param node - AST node to clone
* @param visitorKeys - Optional visitor keys for parent management
* @returns Shallow clone of the node
*/
function shallowCloneNode<T extends ESNode>(
node: T,
visitorKeys?: VisitorKeysType
): T;
/**
* Deep clone an AST node and entire subtree
* @param node - AST node to clone
* @param visitorKeys - Optional visitor keys for parent management
* @returns Deep clone of node and all children
*/
function deepCloneNode<T extends ESNode>(
node: T,
visitorKeys?: VisitorKeysType
): T;Node Modification Examples:
import { SimpleTransform } from "hermes-parser";
// Efficient node modification with nodeWith
const updatedNode = SimpleTransform.nodeWith(identifierNode, {
name: "newName"
});
// Only creates new object if properties actually changed
const sameNode = SimpleTransform.nodeWith(identifierNode, {
name: identifierNode.name // No change, returns same reference
});
// Manual node modification in transform
SimpleTransform.transform(ast, {
transform(node) {
if (node.type === "Identifier" && node.name === "oldName") {
return SimpleTransform.nodeWith(node, { name: "newName" });
}
return node;
}
});Low-level utilities for directly manipulating AST nodes and their relationships.
/**
* Replace a node with new node in its parent
* @param originalNode - Node to replace
* @param originalNodeParent - Parent containing the node
* @param nodeToReplaceWith - New node to insert
* @param visitorKeys - Optional visitor keys
*/
function replaceNodeOnParent(
originalNode: ESNode,
originalNodeParent: ESNode,
nodeToReplaceWith: ESNode,
visitorKeys?: VisitorKeysType
): void;
/**
* Remove a node from its parent
* @param originalNode - Node to remove
* @param originalNodeParent - Parent containing the node
* @param visitorKeys - Optional visitor keys
*/
function removeNodeOnParent(
originalNode: ESNode,
originalNodeParent: ESNode,
visitorKeys?: VisitorKeysType
): void;
/**
* Set parent pointers on direct children of a node
* @param node - Parent node
* @param visitorKeys - Optional visitor keys
*/
function setParentPointersInDirectChildren(
node: ESNode,
visitorKeys?: VisitorKeysType
): void;
/**
* Update all parent pointers in an entire subtree
* @param node - Root node of subtree
* @param visitorKeys - Optional visitor keys
*/
function updateAllParentPointers(
node: ESNode,
visitorKeys?: VisitorKeysType
): void;Utilities for manipulating arrays within AST nodes during transformations.
/**
* Check if two arrays are equal by reference and content
* @param a1 - First array
* @param a2 - Second array
* @returns True if arrays are equal
*/
function arrayIsEqual(a1: ReadonlyArray<unknown>, a2: ReadonlyArray<unknown>): boolean;
/**
* Insert elements at a specific index in array
* @param array - Source array
* @param index - Index to insert at
* @param elements - Elements to insert
* @returns New array with elements inserted
*/
function insertInArray<T>(
array: ReadonlyArray<T>,
index: number,
elements: ReadonlyArray<T>
): T[];
/**
* Remove element at specific index from array
* @param array - Source array
* @param index - Index to remove
* @returns New array with element removed
*/
function removeFromArray<T>(array: ReadonlyArray<T>, index: number): T[];
/**
* Replace element at index with new elements
* @param array - Source array
* @param index - Index to replace
* @param elements - New elements to insert
* @returns New array with replacement
*/
function replaceInArray<T>(
array: ReadonlyArray<T>,
index: number,
elements: ReadonlyArray<T>
): T[];Array Manipulation Examples:
import { insertInArray, removeFromArray, replaceInArray } from "hermes-parser";
const statements = [stmt1, stmt2, stmt3];
// Insert new statements
const withInserted = insertInArray(statements, 1, [newStmt1, newStmt2]);
// Result: [stmt1, newStmt1, newStmt2, stmt2, stmt3]
// Remove statement
const withRemoved = removeFromArray(statements, 1);
// Result: [stmt1, stmt3]
// Replace statement
const withReplaced = replaceInArray(statements, 1, [replacementStmt]);
// Result: [stmt1, replacementStmt, stmt3]Ready-to-use transformation functions for common AST modifications.
/**
* Collection of pre-built AST transformation functions
*/
const Transforms: {
/** Transform experimental match syntax */
transformMatchSyntax: (program: Program, options: ParserOptions) => Program;
/** Strip experimental component syntax */
stripComponentSyntax: (program: Program, options: ParserOptions) => Program;
/** Strip Flow types for Babel compatibility */
stripFlowTypesForBabel: (program: Program, options: ParserOptions) => Program;
/** Strip Flow types for ESTree output */
stripFlowTypes: (program: Program, options: ParserOptions) => Program;
};Pre-built Transform Examples:
import { Transforms, parse } from "hermes-parser";
const flowCode = "function add(x: number, y: number): number { return x + y; }";
const ast = parse(flowCode, { flow: "all" });
// Strip Flow types for plain JavaScript
const cleanAst = Transforms.stripFlowTypes(ast, { flow: "all" });
// Chain multiple transforms
const processedAst = [
Transforms.transformMatchSyntax,
Transforms.stripComponentSyntax,
Transforms.stripFlowTypesForBabel
].reduce((ast, transform) => transform(ast, { flow: "all", babel: true }), ast);Common patterns for AST transformation workflows.
Conditional Node Replacement:
SimpleTransform.transform(ast, {
transform(node) {
// Replace console.log with custom logger
if (node.type === "CallExpression" &&
node.callee.type === "MemberExpression" &&
node.callee.object.name === "console" &&
node.callee.property.name === "log") {
return {
...node,
callee: {
type: "Identifier",
name: "customLogger"
}
};
}
return node;
}
});Node Removal with Conditions:
SimpleTransform.transform(ast, {
transform(node) {
// Remove all debugger statements
if (node.type === "DebuggerStatement") {
return null;
}
// Remove empty statements
if (node.type === "EmptyStatement") {
return null;
}
return node;
}
});Complex Node Restructuring:
SimpleTransform.transform(ast, {
transform(node) {
// Convert arrow functions to regular functions
if (node.type === "ArrowFunctionExpression") {
return {
type: "FunctionExpression",
id: null,
params: node.params,
body: node.body.type === "BlockStatement"
? node.body
: {
type: "BlockStatement",
body: [{
type: "ReturnStatement",
argument: node.body
}]
},
generator: false,
async: node.async
};
}
return node;
}
});