JavaScript parser written in OCaml that produces ESTree AST with optional Flow type annotations support
npx @tessl/cli install tessl/npm-flow-parser@0.280.0Flow Parser is a JavaScript parser written in OCaml and compiled to JavaScript. It produces an Abstract Syntax Tree (AST) that conforms to the ESTree specification and mostly matches what esprima produces. The parser serves as the core parsing engine for Flow (Facebook's static type checker for JavaScript) but can be used independently to parse JavaScript code with optional Flow type annotations.
npm install flow-parserNode.js (CommonJS):
const parser = require('flow-parser');Browser:
<script src="flow_parser.js"></script>
<script>
// The global 'flow' object is available
const ast = flow.parse('code', {});
</script>const parser = require('flow-parser');
// Parse JavaScript with Flow types enabled (default)
const ast = parser.parse('let x: number = 42;', { types: true });
// Parse plain JavaScript without type annotations
const ast2 = parser.parse('let x = 42;', { types: false });
// Parse with all comments and tokens included
const astWithTokens = parser.parse('/* comment */ let x = 1 + 1;', {
types: true,
comments: true,
tokens: true
});
console.log(ast.type); // "Program"
console.log(ast.errors); // Array of parse errors (if any)The primary API for parsing JavaScript source code with comprehensive configuration options.
/**
* Parse JavaScript source code and return an ESTree-compliant AST
* @param content - JavaScript source code to parse
* @param options - Optional configuration object controlling parser behavior
* @returns ESTree AST object with additional Flow-specific properties
*/
function parse(content: string, options?: ParseOptions): AST;
interface ParseOptions {
// Basic parsing options
types?: boolean; // Enable Flow type parsing (default: true)
use_strict?: boolean; // Treat as strict mode (default: false)
comments?: boolean; // Attach comments to AST nodes (default: true)
all_comments?: boolean; // Include all comments list (default: true)
tokens?: boolean; // Include parsed tokens (default: false)
// Language feature options
enums?: boolean; // Enable Flow enums (default: false)
pattern_matching?: boolean; // Enable Flow match expressions/statements (default: false)
components?: boolean; // Enable Flow component syntax (default: false)
assert_operator?: boolean; // Enable assert operator (default: false)
esproposal_decorators?: boolean; // Enable decorators (default: false)
}
interface AST {
type: "Program";
body: any[]; // Array of ESTree Statement nodes
comments?: Comment[]; // All comments when all_comments is true
tokens?: Token[]; // All tokens when tokens is true
errors: ParseError[]; // Parse errors encountered
sourceType: "script" | "module";
// Additional ESTree properties...
}
interface ParseError {
message: string;
loc: SourceLocation;
// Error-specific properties
}
interface Comment {
type: "Block" | "Line";
value: string;
loc: SourceLocation;
}
interface Token {
type: string;
value: string;
loc: SourceLocation;
}
interface SourceLocation {
start: Position;
end: Position;
}
interface Position {
line: number; // 1-based
column: number; // 0-based
}Usage Examples:
const parser = require('flow-parser');
// Basic parsing with type support
const ast = parser.parse(`
type User = {
name: string,
age: number
};
function greet(user: User): string {
return \`Hello \${user.name}!\`;
}
`, { types: true });
// Parse with comprehensive output
const detailedAst = parser.parse(`
// This is a comment
const items = [1, 2, 3];
const doubled = items.map(x => x * 2);
`, {
types: false,
comments: true,
all_comments: true,
tokens: true
});
// Access parse results
console.log('AST type:', detailedAst.type);
console.log('Parse errors:', detailedAst.errors.length);
console.log('Comments found:', detailedAst.comments?.length || 0);
console.log('Tokens found:', detailedAst.tokens?.length || 0);
// Handle parse errors
const invalidCode = parser.parse('let x = ;', { types: false });
if (invalidCode.errors.length > 0) {
invalidCode.errors.forEach(error => {
console.log(`Parse error at line ${error.loc.start.line}: ${error.message}`);
});
}Flow-specific Language Features:
// Enable Flow enums
const enumAst = parser.parse(`
enum Status {
PENDING,
COMPLETE,
FAILED
}
`, { enums: true });
// Enable Flow match expressions
const matchAst = parser.parse(`
const result = match (value) {
1 => "one",
2 => "two",
_ => "other"
};
`, { pattern_matching: true });
// Enable Flow components
const componentAst = parser.parse(`
component Button(text: string) {
return <button>{text}</button>;
}
`, { components: true });
// Enable decorators
const decoratorAst = parser.parse(`
class MyClass {
@observable value = 0;
}
`, { esproposal_decorators: true });The parser is designed to be fault-tolerant and will attempt to parse as much of the input as possible:
const parser = require('flow-parser');
// Parse code with syntax errors
const ast = parser.parse(`
let valid = 'this works';
let invalid = ; // syntax error
let alsoValid = 'this also works';
`, { types: false });
// The AST is still returned with partial results
console.log('AST generated:', ast.type === 'Program');
console.log('Errors found:', ast.errors.length);
// Examine errors
ast.errors.forEach((error, index) => {
console.log(`Error ${index + 1}:`);
console.log(` Message: ${error.message}`);
console.log(` Location: Line ${error.loc.start.line}, Column ${error.loc.start.column}`);
});The parser works in both Node.js and browser environments:
<!DOCTYPE html>
<html>
<head>
<script src="node_modules/flow-parser/flow_parser.js"></script>
</head>
<body>
<script>
// Use the global 'flow' object
const ast = flow.parse('const x = 42;', { types: false });
console.log('Parsed successfully:', ast.type === 'Program');
// All the same options are available
const typedAst = flow.parse('const x: number = 42;', {
types: true,
comments: true
});
</script>
</body>
</html>tokens: true) increases memory usage and parsing time// Optimal performance configuration for large files
const ast = parser.parse(largeCodebase, {
types: true, // Keep if you need Flow types
comments: false, // Disable if comments aren't needed
all_comments: false,
tokens: false // Disable unless specifically needed
});