High-performance JavaScript/TypeScript parser for Synth - universal AST for JS tooling
npm install @sylphx/synth-jsHigh-performance JavaScript/TypeScript parser for Synth. Powered by Acorn, converting ESTree AST into Synth's language-agnostic universal AST.
- JavaScript & TypeScript: Full ES2024+ support with TypeScript parsing
- Language-Agnostic AST: Uses Synth's universal BaseNode interface
- Powered by Acorn: Battle-tested parsing engine with excellent performance
- Plugin System: Compatible with Synth's transform and visitor plugins
- Async Support: Both sync and async parsing with automatic async plugin detection
- TypeScript: Fully typed with comprehensive type utilities
``bash`
bun install @sylphx/synth-js
`typescript
import { parse } from '@sylphx/synth-js'
const tree = parse('const x = 42; function hello() { return x; }')
`
`typescript
import { parse } from '@sylphx/synth-js'
const tree = parse(
'const x: number = 42; function greet(name: string): void {}',
{ typescript: true }
)
`
`typescript
import { JSParser } from '@sylphx/synth-js'
const parser = new JSParser()
const tree = parser.parse('export function add(a, b) { return a + b; }')
// Access the tree
console.log(tree.nodes)
`
`typescript
import {
parse,
isFunctionDeclaration,
isVariableDeclaration,
getFunctionName,
getVariableKind,
findImports,
findExports,
} from '@sylphx/synth-js'
const code =
import { useState } from 'react';
export function Counter() {
const [count, setCount] = useState(0);
return count;
}
const tree = parse(code)
// Find imports and exports
const imports = findImports(tree) // All import declarations
const exports = findExports(tree) // All export declarations
// Find functions
const func = tree.nodes.find(isFunctionDeclaration)
console.log(getFunctionName(func)) // "Counter"
// Find variables
const varDecl = tree.nodes.find(isVariableDeclaration)
console.log(getVariableKind(varDecl)) // "const"
`
`typescript
import { parse } from '@sylphx/synth-js'
import { createTransformPlugin } from '@sylphx/synth'
// Create a plugin that logs all function names
const logFunctionsPlugin = createTransformPlugin(
{ name: 'log-functions', version: '1.0.0' },
(tree) => {
tree.nodes.forEach(node => {
if (node.type === 'FunctionDeclaration') {
console.log('Function:', node.data?.id)
}
})
return tree
}
)
const tree = parse('function foo() {} function bar() {}', {
plugins: [logFunctionsPlugin],
})
`
`typescript
import { parseAsync } from '@sylphx/synth-js'
import { createTransformPlugin } from '@sylphx/synth'
const asyncPlugin = createTransformPlugin(
{ name: 'async-transform', version: '1.0.0' },
async (tree) => {
// Async transformation
await somethingAsync()
return tree
}
)
const tree = await parseAsync('const x = 42;', {
plugins: [asyncPlugin],
})
`
`typescript
import { JSParser } from '@sylphx/synth-js'
import { createTransformPlugin } from '@sylphx/synth'
const parser = new JSParser()
// Register plugins
parser
.use(plugin1)
.use(plugin2)
.use(plugin3)
// Plugins apply to all parse() calls
const tree = parser.parse('const x = 42;')
`
- parse(code, options?): Parse JavaScript/TypeScript synchronouslyparseAsync(code, options?)
- : Parse JavaScript/TypeScript asynchronouslycreateParser()
- : Create a new parser instance
`typescript
interface JSParseOptions {
/* ECMAScript version (default: 'latest') /
ecmaVersion?: acorn.ecmaVersion
/* Source type: 'script' or 'module' (default: 'module') /
sourceType?: 'script' | 'module'
/* Enable TypeScript parsing (default: false) /
typescript?: boolean
/* Build query index for fast lookups /
buildIndex?: boolean
/* Plugins to apply during parsing /
plugins?: Plugin[]
/* Allow return outside functions /
allowReturnOutsideFunction?: boolean
/* Allow await at top level /
allowAwaitOutsideFunction?: boolean
/* Allow hash bang (#!) at start /
allowHashBang?: boolean
}
`
- isProgramNode(node): Check if node is root programisIdentifier(node)
- : Check if node is an identifierisLiteral(node)
- : Check if node is a literal valueisFunctionDeclaration(node)
- : Check if node is a function declarationisClassDeclaration(node)
- : Check if node is a class declarationisVariableDeclaration(node)
- : Check if node is a variable declarationisImportDeclaration(node)
- : Check if node is an import statementisExportDeclaration(node)
- : Check if node is an export statementisStatement(node)
- : Check if node is any statementisExpression(node)
- : Check if node is any expressionisCallExpression(node)
- : Check if node is a function callisMemberExpression(node)
- : Check if node is a member accessisArrowFunction(node)
- : Check if node is an arrow functionisFunctionExpression(node)
- : Check if node is a function expression
- getIdentifierName(node): Get identifier namegetLiteralValue(node)
- : Get literal valuegetLiteralRaw(node)
- : Get literal raw sourcegetVariableKind(node)
- : Get variable kind ('var' | 'let' | 'const')getFunctionName(node)
- : Get function nameisAsync(node)
- : Check if function is asyncisGenerator(node)
- : Check if function is a generatorgetOperator(node)
- : Get operator for binary/unary expressionsgetSourceType(node)
- : Get program source type
- findImports(tree): Find all import declarationsfindExports(tree)
- : Find all export declarationsfindFunctions(tree)
- : Find all function declarationsfindClasses(tree)
- : Find all class declarationsfindIdentifiersByName(tree, name)
- : Find all identifiers with given name
All nodes follow Synth's language-agnostic BaseNode interface:
`typescript`
interface BaseNode {
id: number
type: string // ESTree node type: 'FunctionDeclaration', 'VariableDeclaration', etc.
parent: number | null
children: number[]
span?: {
start: { offset: number; line: number; column: number }
end: { offset: number; line: number; column: number }
}
data?: Record
}
JavaScript-specific data is stored in the data field:
`typescript
// Function declaration
{
id: 5,
type: 'FunctionDeclaration',
parent: 0,
children: [6, 7], // Parameters and body
data: {
id: 'myFunction', // Function name
async: false,
generator: false,
expression: false
}
}
// Variable declaration
{
id: 2,
type: 'VariableDeclaration',
parent: 0,
children: [3], // Declarators
data: {
kind: 'const' // 'var', 'let', or 'const'
}
}
`
- ES2024+: All modern JavaScript syntax
- Modules: import/export statements
- Classes: class declarations, extends, methods
- Functions: declarations, expressions, arrow functions
- Async/Await: async functions and await expressions
- Generators: function* and yield
- Destructuring: object and array destructuring
- Spread/Rest: ...spread and ...rest operators
- Template Literals: string ${interpolation}
- Optional Chaining: obj?.prop
- Nullish Coalescing: value ?? default
Enable TypeScript parsing with the typescript option:
`typescript
import { parse } from '@sylphx/synth-js'
const tree = parse(
interface User {
name: string;
age: number;
}
function greet(user: User): void {
console.log(\Hello, \${user.name}\);
}, { typescript: true })`
Supported TypeScript features:
- Type annotations
- Interfaces
- Type aliases
- Enums
- Generics
- Decorators
- Namespaces
Built on Acorn, one of the fastest JavaScript parsers:
- Fast parsing: Character-based parsing with minimal overhead
- Efficient tree building: Arena-based storage for cache locality
- Low memory usage: Optimized for large codebases
`typescript
import { parse, findImports, getIdentifierName } from '@sylphx/synth-js'
const code =
import React from 'react';
import { useState, useEffect } from 'react';
import './styles.css';
const tree = parse(code)
const imports = findImports(tree)
console.log(Found ${imports.length} imports)`
`typescript
import { parse, findFunctions, getFunctionName } from '@sylphx/synth-js'
const code =
function foo() {}
function bar() {}
const baz = () => {};
const tree = parse(code)
const functions = findFunctions(tree)
functions.forEach(func => {
console.log('Function:', getFunctionName(func))
})
`
`typescript
import { parse } from '@sylphx/synth-js'
import { createTransformPlugin } from '@sylphx/synth'
// Rename all functions to have 'fn_' prefix
const renamePlugin = createTransformPlugin(
{ name: 'rename-functions', version: '1.0.0' },
(tree) => {
tree.nodes.forEach(node => {
if (node.type === 'FunctionDeclaration' && node.data?.id) {
node.data.id = fn_${node.data.id}
}
})
return tree
}
)
const tree = parse('function hello() {}', {
plugins: [renamePlugin],
})
``
MIT
---