Flow Types for JavaScript AST
ast-types-flow provides Flow type definitions specifically tailored for JavaScript Abstract Syntax Trees (ASTs), designed to integrate with AST structures produced by parsers compatible with `benjamn/ast-types`. Published as version 0.0.8, the project appears to be abandoned, with its last update several years ago, reflecting the broader shift in the JavaScript ecosystem's preference from Flow to TypeScript for static typing. The library employs a distinctive method, utilizing special comments like `// extends Node` to define type hierarchies, which are then processed by a custom transform into disjoint union types. This approach aims to facilitate robust type refinement for diverse AST nodes, though it often requires duplicating complete type definitions and introducing unique `_Foo: void` fields to satisfy Flow's structural uniqueness requirements for disjoint unions. It was intended for static analysis of ASTs within Flow-typed projects.
Common errors
-
Cannot get `node.id.name` because `node.id` is `null` or `undefined`.
cause Attempting to access a property on an AST node's `id` property, when `id` is defined as nullable (e.g., for anonymous functions or classes without explicit identifiers).fixAdd a null check for the `id` property before attempting to access its `name`: `if (node.id) { return node.id.name; }` -
Property `name` is missing in `Literal` [1].
cause Attempting to access a property (like `name`) that does not exist on a specific AST node type (e.g., `Literal` nodes have a `value` property, not `name`).fixConsult the AST specification for the correct properties available on the specific node type you are working with. For `Literal` nodes, you likely want `node.value`. -
Error: `ast-types-flow` cannot be found or is not a module.
cause Attempting to use `require()` or a non-type `import` for `ast-types-flow`, which is exclusively a type definition package and does not provide runtime JavaScript modules.fixEnsure you are using `import type { ... } from 'ast-types-flow';` for Flow type imports. The package is not meant for runtime consumption.
Warnings
- deprecated The `ast-types-flow` package is largely abandoned (last updated ~8-10 years ago) and targets Flow, a static type checker that has seen significantly reduced adoption in favor of TypeScript. It is not recommended for new projects.
- gotcha The library utilizes a non-standard syntax (comments like `// extends Node`) for defining type hierarchies, requiring a specific transform step to generate the final Flow types. This can complicate tooling integration and understanding.
- gotcha To ensure Flow's disjoint union refinement works correctly, the library generates types with duplicated complete definitions and adds private `_Foo: void` fields. This can lead to verbose type definitions and might be confusing.
- gotcha Flow type definitions for ASTs often expose properties that can be `null` or `undefined` (e.g., `id` on `ClassDeclaration` or `FunctionExpression`) or that simply do not exist on certain node types (e.g., `name` on `Literal`). Direct access without checks will result in Flow errors.
Install
-
npm install ast-types-flow -
yarn add ast-types-flow -
pnpm add ast-types-flow
Imports
- Node
const Node = require('ast-types-flow');import type { Node } from 'ast-types-flow'; - Identifier
import { Identifier } from 'ast-types-flow';import type { Identifier } from 'ast-types-flow'; - ClassDeclaration
const { ClassDeclaration } = require('ast-types-flow');import type { ClassDeclaration } from 'ast-types-flow';
Quickstart
/* @flow */
import type { Node, Identifier, ClassDeclaration, FunctionDeclaration, FunctionExpression, Literal } from 'ast-types-flow';
/**
* Safely extracts the name from various AST node types.
* Handles cases where IDs might be null or properties might not exist.
* @param {Node} node - The AST node to inspect.
* @returns {string} The name of the node or 'Unknown'.
*/
function getName(node: Node): string {
switch (node.type) {
case 'Identifier':
return node.name; // 'Identifier' nodes reliably have a 'name' property.
case 'ClassDeclaration':
// Flow would flag 'node.id' as potentially null. Refinement is needed.
if (node.id) {
return node.id.name;
}
return 'AnonymousClass'; // Handle the nullable case explicitly.
case 'FunctionDeclaration':
// Assuming 'id' is always present for 'FunctionDeclaration' in this context.
return node.id.name;
case 'FunctionExpression':
// 'FunctionExpression' can be anonymous; 'id' might be null.
if (node.id) {
return node.id.name;
} else {
return 'AnonymousFunction';
}
case 'Literal':
// 'Literal' nodes do not have a 'name' property. Flow would error here.
if (typeof node.value === 'string' || typeof node.value === 'number') {
return String(node.value); // Return the literal's value instead.
}
return 'LiteralValue';
default:
return 'UnknownNode';
}
}
// Example usage (not runnable without an actual AST node)
const myIdentifier: Identifier = { type: 'Identifier', name: 'foo' };
const myClassDecl: ClassDeclaration = { type: 'ClassDeclaration', id: { type: 'Identifier', name: 'MyClass' }, body: { type: 'BlockStatement', body: [] } };
const myLiteral: Literal = { type: 'Literal', value: 123, raw: '123' };
console.log(getName(myIdentifier)); // Expected: foo
console.log(getName(myClassDecl)); // Expected: MyClass
console.log(getName(myLiteral)); // Expected: 123