Top Related Projects
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
Find and fix problems in your JavaScript code.
🐠 Babel is a compiler for writing next generation JavaScript.
Prettier is an opinionated code formatter.
:sparkles: Monorepo for all the tooling which enables ESLint to support TypeScript
JSHint is a tool that helps to detect errors and potential problems in your JavaScript code
Quick Overview
TSQuery is a TypeScript library that allows you to query TypeScript ASTs (Abstract Syntax Trees) using a CSS selector-like syntax. It provides a powerful and intuitive way to search and manipulate TypeScript code programmatically, making it useful for static analysis, code transformation, and other AST-based operations.
Pros
- Intuitive CSS-like syntax for querying TypeScript ASTs
- Supports a wide range of selectors and combinators
- Integrates well with TypeScript's compiler API
- Actively maintained and regularly updated
Cons
- Learning curve for users unfamiliar with AST manipulation
- Limited documentation and examples for advanced use cases
- Performance may degrade with very large codebases
- Requires understanding of TypeScript's AST structure
Code Examples
- Basic selector usage:
import { tsquery } from '@phenomnomnominal/tsquery';
const code = `
function greet(name: string) {
console.log(\`Hello, \${name}!\`);
}
`;
const ast = tsquery.ast(code);
const functions = tsquery(ast, 'FunctionDeclaration');
console.log(functions.length); // Output: 1
- Finding specific identifiers:
import { tsquery } from '@phenomnomnominal/tsquery';
const code = `
const x = 1;
let y = 2;
var z = 3;
`;
const ast = tsquery.ast(code);
const constVariables = tsquery(ast, 'VariableDeclaration[kind="const"]');
console.log(constVariables.length); // Output: 1
- Combining selectors:
import { tsquery } from '@phenomnomnominal/tsquery';
const code = `
class MyClass {
private myMethod() {
return 42;
}
}
`;
const ast = tsquery.ast(code);
const privateMethods = tsquery(ast, 'ClassDeclaration MethodDeclaration[modifiers.0.kind="PrivateKeyword"]');
console.log(privateMethods.length); // Output: 1
Getting Started
To use TSQuery in your project, follow these steps:
-
Install the package:
npm install @phenomnomnominal/tsquery
-
Import and use in your TypeScript code:
import { tsquery } from '@phenomnomnominal/tsquery'; const code = `/* Your TypeScript code here */`; const ast = tsquery.ast(code); const results = tsquery(ast, 'YourSelector');
-
Run your TypeScript code with
ts-node
or compile and run withtsc
andnode
.
Competitor Comparisons
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
Pros of TypeScript
- Comprehensive language implementation with full compiler and tooling support
- Extensive documentation and large community backing
- Regular updates and active development by Microsoft
Cons of TypeScript
- Large codebase, which can be overwhelming for contributors
- Slower to implement new features due to rigorous testing and compatibility requirements
- More complex setup for local development and testing
Code Comparison
TypeScript (compiler core):
function createProgram(
rootNames: readonly string[],
options: CompilerOptions,
host?: CompilerHost,
oldProgram?: Program,
configFileParsingDiagnostics?: readonly Diagnostic[]
): Program {
// ... implementation
}
TSQuery:
export function tsquery(
ast: ts.Node,
query: string,
opts: TSQueryOptions = {}
): TSQueryNode[] {
// ... implementation
}
Key Differences
- TypeScript is a full language implementation, while TSQuery is a utility for querying TypeScript ASTs
- TypeScript's codebase is much larger and more complex
- TSQuery focuses on a specific use case, making it more lightweight and easier to contribute to
- TypeScript provides a complete development environment, whereas TSQuery is a tool to be used within TypeScript projects
Find and fix problems in your JavaScript code.
Pros of ESLint
- Broader language support: Covers JavaScript, TypeScript, and various frameworks
- Extensive rule set: Offers a wide range of customizable linting rules
- Large ecosystem: Numerous plugins and configurations available
Cons of ESLint
- Steeper learning curve: More complex setup and configuration process
- Performance: Can be slower on large projects due to its comprehensive nature
Code Comparison
ESLint configuration example:
{
"extends": "eslint:recommended",
"rules": {
"semi": ["error", "always"],
"quotes": ["error", "double"]
}
}
TSQuery usage example:
import { tsquery } from '@phenomnomnominal/tsquery';
const ast = tsquery.ast(`const x = 1;`);
const result = tsquery(ast, 'VariableDeclaration');
Key Differences
- ESLint is a full-featured linter, while TSQuery is a query tool for TypeScript ASTs
- ESLint focuses on enforcing coding standards, while TSQuery is designed for AST analysis and manipulation
- ESLint has a more extensive configuration system, whereas TSQuery offers a simpler, more focused API
Use Cases
- ESLint: Ideal for enforcing coding standards and catching potential errors in JavaScript and TypeScript projects
- TSQuery: Better suited for specific TypeScript AST querying tasks, such as code analysis tools or custom transformations
🐠 Babel is a compiler for writing next generation JavaScript.
Pros of babel
- Broader scope: Babel is a comprehensive JavaScript compiler with extensive transformation capabilities
- Larger community and ecosystem: More plugins, integrations, and third-party support
- Supports multiple languages and syntaxes beyond TypeScript
Cons of babel
- Heavier and more complex: Requires more configuration and setup
- Not TypeScript-specific: May lack some TypeScript-focused features and optimizations
- Steeper learning curve for TypeScript-only projects
Code comparison
tsquery:
import { tsquery } from '@phenomnomnominal/tsquery';
const ast = tsquery.ast(`const x: number = 5;`);
const result = tsquery(ast, 'VariableDeclaration');
babel:
const babel = require('@babel/core');
const code = `const x: number = 5;`;
const result = babel.transform(code, {
presets: ['@babel/preset-typescript']
});
Summary
tsquery is a lightweight, TypeScript-specific AST querying tool, while babel is a more comprehensive JavaScript compiler with broader language support. tsquery offers simplicity and focus for TypeScript projects, whereas babel provides greater flexibility and transformation capabilities across multiple languages and syntaxes.
Prettier is an opinionated code formatter.
Pros of Prettier
- Widely adopted and supported by the community
- Opinionated formatting with minimal configuration needed
- Supports multiple languages beyond TypeScript
Cons of Prettier
- Less granular control over specific formatting rules
- May not handle complex TypeScript-specific syntax as effectively
Code Comparison
TSQuery:
import { tsquery } from 'tsquery';
const ast = tsquery.ast(`
const x = 1;
const y = 2;
`);
const result = tsquery(ast, 'VariableDeclaration');
Prettier:
const prettier = require("prettier");
const code = `
const x = 1;
const y = 2;
`;
const formattedCode = prettier.format(code, { parser: "typescript" });
Key Differences
- TSQuery focuses on querying and manipulating TypeScript ASTs
- Prettier is primarily for code formatting across multiple languages
- TSQuery provides more fine-grained control for TypeScript-specific operations
- Prettier aims for consistent, opinionated formatting with minimal configuration
Use Cases
- Use TSQuery for advanced TypeScript static analysis and transformations
- Choose Prettier for standardized code formatting across projects and teams
:sparkles: Monorepo for all the tooling which enables ESLint to support TypeScript
Pros of typescript-eslint
- More comprehensive and actively maintained ESLint integration for TypeScript
- Provides a wider range of rules and plugins specifically designed for TypeScript
- Offers a unified parser for both JavaScript and TypeScript
Cons of typescript-eslint
- More complex setup and configuration compared to tsquery
- Larger package size and potential performance overhead
- Steeper learning curve for customizing rules and plugins
Code Comparison
tsquery:
import { tsquery } from '@phenomnomnominal/tsquery';
const ast = tsquery.ast(`const x: number = 5;`);
const result = tsquery(ast, 'VariableDeclaration');
typescript-eslint:
module.exports = {
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
extends: ['plugin:@typescript-eslint/recommended'],
rules: {
'@typescript-eslint/explicit-function-return-type': 'error',
},
};
typescript-eslint provides a more comprehensive linting solution with extensive rule configurations, while tsquery focuses on querying TypeScript ASTs. typescript-eslint is better suited for large-scale projects requiring strict code quality enforcement, whereas tsquery is more lightweight and useful for specific AST analysis tasks.
JSHint is a tool that helps to detect errors and potential problems in your JavaScript code
Pros of JSHint
- Broader language support: Analyzes JavaScript, while TSQuery focuses on TypeScript
- More established project with a larger community and longer history
- Offers a wider range of linting rules and configuration options
Cons of JSHint
- Less focused on modern JavaScript/TypeScript features
- Slower performance compared to TSQuery's targeted approach
- More complex setup and configuration process
Code Comparison
TSQuery:
import { tsquery } from '@phenomnomnominal/tsquery';
const ast = tsquery.ast(`const x: number = 5;`);
const result = tsquery(ast, 'VariableDeclaration');
JSHint:
const JSHINT = require('jshint').JSHINT;
const code = 'const x = 5;';
JSHINT(code);
const errors = JSHINT.errors;
Key Differences
- TSQuery is specifically designed for querying TypeScript ASTs, while JSHint is a more general-purpose JavaScript linter
- TSQuery uses a CSS-like selector syntax for querying, whereas JSHint relies on predefined linting rules
- JSHint provides a broader set of linting capabilities, while TSQuery offers more precise control over TypeScript-specific structures
Use Cases
- Choose TSQuery for TypeScript-specific static analysis and AST querying
- Opt for JSHint for general JavaScript linting and code quality checks in larger, established projects
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
TSQuery
TSQuery is a port of the ESQuery API for TypeScript! TSQuery allows you to query a TypeScript AST for patterns of syntax using a CSS style selector system.
Demos:
ESQuery demo - note that the demo requires JavaScript code, not TypeScript TSQuery demo by Uri Shaked
Installation
npm install @phenomnomnominal/tsquery --save-dev
Examples
Say we want to select all instances of an identifier with name "Animal", e.g. the identifier in the class
declaration, and the identifier in the extends
declaration.
We would do something like the following:
import { ast, query } from '@phenomnomnominal/tsquery';
const typescript = `
class Animal {
constructor(public name: string) { }
move(distanceInMeters: number = 0) {
console.log(\`\${this.name} moved \${distanceInMeters}m.\`);
}
}
class Snake extends Animal {
constructor(name: string) { super(name); }
move(distanceInMeters = 5) {
console.log("Slithering...");
super.move(distanceInMeters);
}
}
`;
const ast = ast(typescript);
const nodes = query(ast, 'Identifier[name="Animal"]');
console.log(nodes.length); // 2
Selectors
The following selectors are supported:
- AST node type:
ForStatement
(see common node types) - wildcard:
*
- attribute existence:
[attr]
- attribute value:
[attr="foo"]
or[attr=123]
- attribute regex:
[attr=/foo.*/]
- attribute conditions:
[attr!="foo"]
,[attr>2]
,[attr<3]
,[attr>=2]
, or[attr<=3]
- nested attribute:
[attr.level2="foo"]
- field:
FunctionDeclaration > Identifier.id
- First or last child:
:first-child
or:last-child
- nth-child (no ax+b support):
:nth-child(2)
- nth-last-child (no ax+b support):
:nth-last-child(1)
- descendant:
ancestor descendant
- child:
parent > child
- following sibling:
node ~ sibling
- adjacent sibling:
node + adjacent
- negation:
:not(ForStatement)
- matches-any:
:matches([attr] > :first-child, :last-child)
- has:
IfStatement:has([name="foo"])
- class of AST node:
:statement
,:expression
,:declaration
,:function
, or:pattern
Common AST node types
Identifier
- any identifier (name of a function, class, variable, etc)IfStatement
,ForStatement
,WhileStatement
,DoStatement
- control flowFunctionDeclaration
,ClassDeclaration
,ArrowFunction
- declarationsVariableStatement
- var, const, let.ImportDeclaration
- anyimport
statementStringLiteral
- any stringTrueKeyword
,FalseKeyword
,NullKeyword
,AnyKeyword
- various keywordsCallExpression
- function callNumericLiteral
- any numeric constantNoSubstitutionTemplateLiteral
,TemplateExpression
- template strings and expressions
API:
ast
:
Parse a string of code into an Abstract Syntax Tree which can then be queried with TSQuery Selectors.
import { ast } from '@phenomnomnominal/tsquery';
const sourceFile = ast('const x = 1;');
includes
:
Check for Nodes
within a given string
of code or AST Node
matching a Selector
.
import { includes } from '@phenomnomnominal/tsquery';
const hasIdentifier = includes('const x = 1;', 'Identifier');
map
:
Transform AST Nodes
within a given Node
matching a Selector
. Can be used to do Node
-based replacement or removal of parts of the input AST.
import { factory } from 'typescript';
import { map } from '@phenomnomnominal/tsquery';
const tree = ast('const x = 1;')
const updatedTree = map(tree, 'Identifier', () => factory.createIdentifier('y'));
match
:
Find AST Nodes
within a given AST Node
matching a Selector
.
import { ast, match } from '@phenomnomnominal/tsquery';
const tree = ast('const x = 1;')
const [xNode] = match(tree, 'Identifier');
parse
:
Parse a string
into an ESQuery Selector
.
import { parse } from '@phenomnomnominal/tsquery';
const selector = parse(':matches([attr] > :first-child, :last-child)');
print
:
Print a given Node
or SourceFile
to a string, using the default TypeScript printer.
import { print } from '@phenomnomnominal/tsquery';
import { factory } from 'typescript';
// create synthetic node:
const node = factory.createArrowFunction(
// ...
);
const code = print(node);
project
:
Get all the SourceFiles
included in a the TypeScript project described by a given config file.
import { project } from '@phenomnomnominal/tsquery';
const files = project('./tsconfig.json');
files
:
Get all the file paths included ina the TypeScript project described by a given config file.
import { files } from '@phenomnomnominal/tsquery';
const filePaths = files('./tsconfig.json');
match
:
Find AST Nodes
within a given string
of code or AST Node
matching a Selector
.
import {query } from '@phenomnomnominal/tsquery';
const [xNode] = query('const x = 1;', 'Identifier');
replace
:
Transform AST Nodes
within a given Node
matching a Selector
. Can be used to do string-based replacement or removal of parts of the input AST. The updated code will be printed with the TypeScript Printer
, so you may need to run your own formatter on any output code.
import { replace } from '@phenomnomnominal/tsquery';
const updatedCode = replace('const x = 1;', 'Identifier', () => 'y'));
Top Related Projects
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
Find and fix problems in your JavaScript code.
🐠 Babel is a compiler for writing next generation JavaScript.
Prettier is an opinionated code formatter.
:sparkles: Monorepo for all the tooling which enables ESLint to support TypeScript
JSHint is a tool that helps to detect errors and potential problems in your JavaScript code
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot