Utility functions for working with TypeScript's Abstract Syntax Tree (AST) and type system
—
Text processing utilities for source code analysis including line range calculation, identifier validation, comment extraction, position-based operations, and various text validation functions for TypeScript constructs.
Utilities for analyzing line structure and line breaks in source files.
/**
* Get line ranges for all lines in a source file
* @param sourceFile - Source file to analyze
* @returns Array of line ranges with position and content length information
*/
function getLineRanges(sourceFile: ts.SourceFile): LineRange[];
/**
* Get the line break style used in a source file
* @param sourceFile - Source file to analyze
* @returns Line break string (e.g., '\n', '\r\n', '\r')
*/
function getLineBreakStyle(sourceFile: ts.SourceFile): string;
/**
* Check if two positions are on the same line
* @param sourceFile - Source file containing the positions
* @param pos1 - First position
* @param pos2 - Second position
* @returns true if both positions are on the same line
*/
function isSameLine(sourceFile: ts.SourceFile, pos1: number, pos2: number): boolean;
/**
* Line range interface with content length information
*/
interface LineRange extends ts.TextRange {
/** Length of actual content on the line (excluding line break) */
contentLength: number;
}Utilities for validating TypeScript identifiers and property names.
/**
* Check if text is a valid TypeScript identifier
* @param text - Text to validate
* @param languageVersion - TypeScript language version (optional)
* @returns true if text is valid identifier
*/
function isValidIdentifier(text: string, languageVersion?: ts.ScriptTarget): boolean;
/**
* Check if text can be used as property access (obj.prop)
* @param text - Text to validate
* @param languageVersion - TypeScript language version (optional)
* @returns true if text is valid for property access
*/
function isValidPropertyAccess(text: string, languageVersion?: ts.ScriptTarget): boolean;
/**
* Check if text is a valid property name
* @param text - Text to validate
* @param languageVersion - TypeScript language version (optional)
* @returns true if text is valid property name
*/
function isValidPropertyName(text: string, languageVersion?: ts.ScriptTarget): boolean;
/**
* Check if text is a valid numeric literal
* @param text - Text to validate
* @param languageVersion - TypeScript language version (optional)
* @returns true if text is valid numeric literal
*/
function isValidNumericLiteral(text: string, languageVersion?: ts.ScriptTarget): boolean;
/**
* Check if text is a valid JSX identifier
* @param text - Text to validate
* @param languageVersion - TypeScript language version (optional)
* @returns true if text is valid JSX identifier
*/
function isValidJsxIdentifier(text: string, languageVersion?: ts.ScriptTarget): boolean;Utilities for working with property names and numeric properties.
/**
* Extract property name from a property name node
* @param propertyName - Property name node
* @returns String representation of property name or undefined if not extractable
*/
function getPropertyName(propertyName: ts.PropertyName): string | undefined;
/**
* Check if property name is numeric
* @param name - Property name to check
* @returns true if name represents a numeric property
*/
function isNumericPropertyName(name: string | ts.__String): boolean;Utilities for analyzing well-known symbol property access.
/**
* Check if expression is a well-known symbol literal (Symbol.iterator, etc.)
* @param node - Expression to check
* @returns true if expression is well-known symbol access
*/
function isWellKnownSymbolLiterally(node: ts.Expression): node is WellKnownSymbolLiteral;
/**
* Get property name information for well-known symbol
* @param node - Well-known symbol literal node
* @returns Property name information
* @deprecated Use getLateBoundPropertyNames instead
*/
function getPropertyNameOfWellKnownSymbol(node: WellKnownSymbolLiteral): PropertyName;
/**
* Interface for well-known symbol literal expressions
*/
interface WellKnownSymbolLiteral extends ts.PropertyAccessExpression {
expression: ts.Identifier & {text: 'Symbol', escapedText: 'symbol'};
}
/**
* Property name information
*/
interface PropertyName {
displayName: string;
symbolName: ts.__String;
}Utilities for analyzing dynamically computed property names.
/**
* Analyze late-bound property names from an expression
* @param node - Expression to analyze
* @param checker - Type checker instance
* @returns Late-bound property names information
*/
function getLateBoundPropertyNames(node: ts.Expression, checker: ts.TypeChecker): LateBoundPropertyNames;
/**
* Get late-bound property names from a property name node
* @param node - Property name node
* @param checker - Type checker instance
* @returns Late-bound property names information
*/
function getLateBoundPropertyNamesOfPropertyName(node: ts.PropertyName, checker: ts.TypeChecker): LateBoundPropertyNames;
/**
* Get single late-bound property name if deterministic
* @param node - Property name node
* @param checker - Type checker instance
* @returns Single property name if deterministic, undefined otherwise
*/
function getSingleLateBoundPropertyNameOfPropertyName(node: ts.PropertyName, checker: ts.TypeChecker): PropertyName | undefined;
/**
* Late-bound property names result
*/
interface LateBoundPropertyNames {
/** Whether all property names are known at compile time */
known: boolean;
/** Array of resolved property names */
names: PropertyName[];
}Utilities for analyzing expressions and their side effects.
/**
* Check if expression has side effects
* @param node - Expression to analyze
* @param options - Side effect analysis options
* @returns true if expression may have side effects
*/
function hasSideEffects(node: ts.Expression, options?: SideEffectOptions): boolean;
/**
* Check if expression value is used (not discarded)
* @param node - Expression to check
* @returns true if expression value is used
*/
function isExpressionValueUsed(node: ts.Expression): boolean;
/**
* Get access kind for a node (read, write, delete)
* @param node - Node to analyze
* @returns Access kind flags
*/
function getAccessKind(node: ts.Node): AccessKind;
/**
* Check if expression is a reassignment target
* @param node - Expression to check
* @returns true if expression is being reassigned
*/
function isReassignmentTarget(node: ts.Expression): boolean;
/**
* Side effect analysis options
*/
enum SideEffectOptions {
None = 0,
TaggedTemplate = 1,
Constructor = 2,
JsxElement = 4
}
/**
* Access kind enumeration
*/
enum AccessKind {
None = 0,
Read = 1,
Write = 2,
Delete = 4,
ReadWrite = Read | Write,
Modification = Write | Delete
}Utilities for analyzing const assertions and readonly contexts.
/**
* Check if assertion expression is a const assertion
* @param node - Assertion expression to check
* @returns true if assertion is 'as const'
*/
function isConstAssertion(node: ts.AssertionExpression): boolean;
/**
* Check if expression is in const context
* @param node - Expression to check
* @returns true if expression is in const assertion context
*/
function isInConstContext(node: ts.Expression): boolean;
/**
* Check if call expression is readonly assignment declaration
* @param node - Call expression to check
* @param checker - Type checker instance
* @returns true if call creates readonly assignment
*/
function isReadonlyAssignmentDeclaration(node: ts.CallExpression, checker: ts.TypeChecker): boolean;
/**
* Check if call expression is bindable Object.defineProperty call
* @param node - Call expression to check
* @returns true if call is bindable defineProperty
*/
function isBindableObjectDefinePropertyCall(node: ts.CallExpression): boolean;Miscellaneous text processing and utility functions.
/**
* Remove parentheses from expression
* @param node - Expression that may be parenthesized
* @returns Unwrapped expression
*/
function unwrapParentheses(node: ts.Expression): ts.Expression;
/**
* Format pseudo big int value as string
* @param v - Pseudo big int value
* @returns Formatted string representation
*/
function formatPseudoBigInt(v: ts.PseudoBigInt): string;
/**
* Check if switch statement has exhaustive case clauses
* @param node - Switch statement to check
* @param checker - Type checker instance
* @returns true if all cases are covered
*/
function hasExhaustiveCaseClauses(node: ts.SwitchStatement, checker: ts.TypeChecker): boolean;
/**
* Get base class expression from class-like declaration
* @param node - Class-like declaration
* @returns Base class expression if present
*/
function getBaseOfClassLikeExpression(node: ts.ClassLikeDeclaration): ts.ExpressionWithTypeArguments | undefined;Utilities for analyzing TypeScript compiler directives.
/**
* Get TypeScript check directive from source text
* @param source - Source text to analyze
* @returns Check directive if found
*/
function getTsCheckDirective(source: string): ts.CheckJsDirective | undefined;
/**
* Get check JS directive from source text (deprecated)
* @param source - Source text to analyze
* @returns Check directive if found
* @deprecated Use getTsCheckDirective instead
*/
function getCheckJsDirective(source: string): ts.CheckJsDirective | undefined;Usage Examples:
import * as ts from "typescript";
import {
getLineRanges,
isValidIdentifier,
getPropertyName,
hasSideEffects,
isConstAssertion,
unwrapParentheses,
SideEffectOptions,
AccessKind
} from "tsutils/util";
// Line analysis example
function analyzeSourceLines(sourceFile: ts.SourceFile) {
const lines = getLineRanges(sourceFile);
const lineBreakStyle = getLineBreakStyle(sourceFile);
console.log(`File has ${lines.length} lines`);
console.log(`Line break style: ${JSON.stringify(lineBreakStyle)}`);
lines.forEach((line, index) => {
console.log(`Line ${index + 1}: ${line.contentLength} characters`);
});
}
// Identifier validation example
function validateIdentifiers(identifiers: string[]) {
identifiers.forEach(id => {
if (isValidIdentifier(id)) {
console.log(`"${id}" is a valid identifier`);
} else {
console.log(`"${id}" is not a valid identifier`);
}
if (isValidPropertyAccess(id)) {
console.log(`"${id}" can be used in property access`);
}
});
}
// Property name analysis
function analyzePropertyAccess(node: ts.PropertyAccessExpression) {
const propertyName = getPropertyName(node.name);
if (propertyName) {
console.log(`Property name: ${propertyName}`);
if (isNumericPropertyName(propertyName)) {
console.log("Property name is numeric");
}
}
}
// Side effect analysis
function analyzeSideEffects(expression: ts.Expression) {
const hasEffects = hasSideEffects(expression, SideEffectOptions.None);
const hasEffectsWithConstructors = hasSideEffects(expression, SideEffectOptions.Constructor);
console.log(`Expression has side effects: ${hasEffects}`);
console.log(`With constructor calls: ${hasEffectsWithConstructors}`);
const isUsed = isExpressionValueUsed(expression);
console.log(`Expression value is used: ${isUsed}`);
}
// Const assertion analysis
function analyzeConstAssertions(node: ts.Node) {
if (ts.isAsExpression(node) || ts.isTypeAssertion(node)) {
if (isConstAssertion(node)) {
console.log("Found const assertion");
}
}
if (ts.isExpression(node) && isInConstContext(node)) {
console.log("Expression is in const context");
}
}
// Expression unwrapping
function analyzeExpression(expr: ts.Expression) {
const unwrapped = unwrapParentheses(expr);
if (unwrapped !== expr) {
console.log("Expression was parenthesized");
}
console.log(`Unwrapped expression: ${ts.SyntaxKind[unwrapped.kind]}`);
}
// Position-based analysis
function checkPositionInLine(sourceFile: ts.SourceFile, pos1: number, pos2: number) {
if (isSameLine(sourceFile, pos1, pos2)) {
console.log("Positions are on the same line");
} else {
console.log("Positions are on different lines");
}
}Install with Tessl CLI
npx tessl i tessl/npm-tsutils