feat: begin autogenerating web-tree-sitter.d.ts

This commit is contained in:
Amaan Qureshi 2025-01-19 23:06:02 -05:00
parent be7716dfa7
commit 10e6ecf162
14 changed files with 1082 additions and 343 deletions

View file

@ -2,7 +2,7 @@ import createModule, { type MainModule } from '../lib/tree-sitter';
export let Module: MainModule | null = null;
export async function initializeBinding(moduleOptions: EmscriptenModule): Promise<MainModule> {
export async function initializeBinding(moduleOptions?: EmscriptenModule): Promise<MainModule> {
if (!Module) {
Module = await createModule(moduleOptions);
}

View file

@ -21,11 +21,6 @@ export interface Edit {
newEndIndex: number;
}
export interface ParserOptions {
includedRanges?: Range[];
progressCallback?: (progress: { currentOffset: number }) => boolean;
}
export const SIZE_OF_SHORT = 2;
export const SIZE_OF_INT = 4;
export const SIZE_OF_CURSOR = 4 * SIZE_OF_INT;
@ -35,7 +30,7 @@ export const SIZE_OF_RANGE = 2 * SIZE_OF_INT + 2 * SIZE_OF_POINT;
export const ZERO_POINT: Point = { row: 0, column: 0 };
// Types for callbacks
export type ParseCallback = (index: number, position: Point) => string | null;
export type ParseCallback = (index: number, position: Point) => string | undefined;
export type ProgressCallback = (progress: { currentOffset: number }) => boolean;
export type LogCallback = (message: string, isLex: boolean) => void;

View file

@ -11,9 +11,12 @@ const QUERY_WORD_REGEX = /[\w-]+/g;
const LANGUAGE_FUNCTION_REGEX = /^tree_sitter_\w+$/;
export class Language {
private [0]: number; // Internal handle for WASM
public types: string[];
public fields: (string | null)[];
/** @internal */
private [0] = 0; // Internal handle for WASM
types: string[];
fields: (string | null)[];
constructor(internal: Internal, address: number) {
assertInternal(internal);
@ -449,7 +452,8 @@ export class Language {
if (input instanceof Uint8Array) {
bytes = Promise.resolve(input);
} else {
if (globalThis.process.versions.node) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (globalThis.process?.versions.node) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-require-imports
const fs: typeof import('fs/promises') = require('fs/promises');
bytes = fs.readFile(input);
@ -469,7 +473,7 @@ export class Language {
const mod = await C.loadWebAssemblyModule(await bytes, { loadAsync: true });
const symbolNames = Object.keys(mod);
const functionName = symbolNames.find((key) => LANGUAGE_FUNCTION_REGEX.test(key) &&
const functionName = symbolNames.find((key) => LANGUAGE_FUNCTION_REGEX.test(key) &&
!key.includes('external_scanner_'));
if (!functionName) {
console.log(`Couldn't find language function in WASM file. Symbols:\n${JSON.stringify(symbolNames, null, 2)}`);

View file

@ -2,7 +2,10 @@ import { C, Internal, assertInternal } from './constants';
import { Language } from './language';
export class LookaheadIterator implements Iterable<string> {
private [0]: number; // Internal handle for WASM
/** @internal */
private [0] = 0; // Internal handle for WASM
/** @internal */
private language: Language;
constructor(internal: Internal, address: number, language: Language) {

View file

@ -5,8 +5,13 @@ import { marshalNode, marshalPoint, unmarshalNode, unmarshalPoint } from './mars
import { TRANSFER_BUFFER } from './parser';
export class Node {
private [0]: number; // Internal handle for WASM
/** @internal */
private [0] = 0; // Internal handle for WASM
/** @internal */
private _children?: (Node | null)[];
/** @internal */
private _namedChildren?: (Node | null)[];
id!: number;

View file

@ -1,16 +1,17 @@
import { C, INTERNAL, Point, Range, SIZE_OF_INT, SIZE_OF_RANGE, setModule } from './constants';
import { C, INTERNAL, LogCallback, ParseCallback, Range, SIZE_OF_INT, SIZE_OF_RANGE, setModule } from './constants';
import { Language } from './language';
import { marshalRange, unmarshalRange } from './marshal';
import { checkModule, initializeBinding } from './bindings';
import { Tree } from './tree';
interface ParseOptions {
export interface ParseOptions {
includedRanges?: Range[];
progressCallback?: (percent: number) => void;
progressCallback?: (state: ParseState) => void;
}
type ParseCallback = ((index: number, position: Point) => string) | string;
type LogCallback = ((message: string, type: number, row: number, column: number) => void) | null;
export interface ParseState {
currentOffset: number;
}
// Global variable for transferring data across the FFI boundary
export let TRANSFER_BUFFER: number;
@ -18,21 +19,23 @@ export let TRANSFER_BUFFER: number;
let VERSION: number;
let MIN_COMPATIBLE_VERSION: number;
// declare let currentParseCallback: ((index: number, position: Point) => string) | null;
// // eslint-disable-next-line @typescript-eslint/no-unused-vars
// declare let currentLogCallback: LogCallback;
// // eslint-disable-next-line @typescript-eslint/no-unused-vars
// declare let currentProgressCallback: ((percent: number) => void) | null;
export class Parser {
protected [0] = 0;
protected [1] = 0;
protected language: Language | null = null;
protected logCallback: LogCallback = null;
static Language: typeof Language;
/** @internal */
private [0] = 0; // Internal handle for WASM
// This must always be called before creating a Parser.
static async init(moduleOptions: EmscriptenModule) {
/** @internal */
private [1] = 0; // Internal handle for WASM
/** @internal */
private language: Language | null = null;
/** @internal */
private logCallback: LogCallback | null = null;
/**
* This must always be called before creating a Parser.
*/
static async init(moduleOptions?: EmscriptenModule) {
setModule(await initializeBinding(moduleOptions));
TRANSFER_BUFFER = C._ts_init();
VERSION = C.getValue(TRANSFER_BUFFER, 'i32');
@ -87,7 +90,7 @@ export class Parser {
}
parse(
callback: ParseCallback,
callback: string | ParseCallback,
oldTree?: Tree | null,
options: ParseOptions = {}
): Tree {
@ -181,7 +184,7 @@ export class Parser {
C._ts_parser_set_timeout_micros(this[0], 0, timeout);
}
setLogger(callback: LogCallback): this {
setLogger(callback: LogCallback | boolean | null): this {
if (!callback) {
this.logCallback = null;
} else if (typeof callback !== 'function') {
@ -192,7 +195,7 @@ export class Parser {
return this;
}
getLogger(): LogCallback {
getLogger(): LogCallback | null {
return this.logCallback;
}
}

View file

@ -3,9 +3,7 @@ import { Node } from './node';
import { marshalNode, unmarshalCaptures } from './marshal';
import { TRANSFER_BUFFER } from './parser';
// let currentQueryProgressCallback: ((percent: number) => void) | null = null;
interface QueryOptions {
export interface QueryOptions {
startPosition?: Point;
endPosition?: Point;
startIndex?: number;
@ -13,7 +11,11 @@ interface QueryOptions {
matchLimit?: number;
maxStartDepth?: number;
timeoutMicros?: number;
progressCallback?: (percent: number) => void;
progressCallback?: (state: QueryState) => void;
}
export interface QueryState {
currentOffset: number;
}
export type Properties = Record<string, string | null>;
@ -23,7 +25,7 @@ export interface Predicate {
operands: PredicateStep[];
}
export interface Capture {
export interface QueryCapture {
name: string;
node: Node;
setProperties?: Properties;
@ -43,7 +45,7 @@ export type CaptureQuantifier = typeof CaptureQuantifier[keyof typeof CaptureQua
export interface QueryMatch {
pattern: number;
captures: Capture[];
captures: QueryCapture[];
setProperties?: Properties;
assertedProperties?: Properties;
refutedProperties?: Properties;
@ -53,11 +55,16 @@ export type PredicateStep =
| { type: 'string'; value: string }
| { type: 'capture'; value?: string, name: string };
export type TextPredicate = (captures: Capture[]) => boolean;
export type TextPredicate = (captures: QueryCapture[]) => boolean;
export class Query {
private [0]: number; // Internal handle for WASM
/** @internal */
private [0] = 0; // Internal handle for WASM
/** @internal */
private exceededMatchLimit: boolean;
/** @internal */
private textPredicates: TextPredicate[][];
readonly captureNames: string[];
@ -159,7 +166,7 @@ export class Query {
const captureCount = C.getValue(address, 'i32');
address += SIZE_OF_INT;
const captures = new Array<Capture>(captureCount);
const captures = new Array<QueryCapture>(captureCount);
address = unmarshalCaptures(this, node.tree, address, captures);
if (this.textPredicates[pattern].every((p) => p(captures))) {
@ -183,7 +190,7 @@ export class Query {
captures(
node: Node,
options: QueryOptions = {}
): Capture[] {
): QueryCapture[] {
const startPosition = options.startPosition ?? ZERO_POINT;
const endPosition = options.endPosition ?? ZERO_POINT;
const startIndex = options.startIndex ?? 0;
@ -232,10 +239,10 @@ export class Query {
const count = C.getValue(TRANSFER_BUFFER, 'i32');
const startAddress = C.getValue(TRANSFER_BUFFER + SIZE_OF_INT, 'i32');
const didExceedMatchLimit = C.getValue(TRANSFER_BUFFER + 2 * SIZE_OF_INT, 'i32');
const result: Capture[] = [];
const result: QueryCapture[] = [];
this.exceededMatchLimit = Boolean(didExceedMatchLimit);
const captures: Capture[] = [];
const captures: QueryCapture[] = [];
let address = startAddress;
for (let i = 0; i < count; i++) {
const pattern = C.getValue(address, 'i32');

View file

@ -27,7 +27,8 @@ export function getText(tree: Tree, startIndex: number, endIndex: number, startP
}
export class Tree {
private [0]: number; // Internal handle for WASM
/** @internal */
private [0] = 0; // Internal handle for WASM
textCallback: ParseCallback;
language: Language;

View file

@ -5,15 +5,19 @@ import { TRANSFER_BUFFER } from './parser';
import { getText, Tree } from './tree';
export class TreeCursor {
// @ts-expect-error Internal handle for WASM
private [0]: number;
// @ts-expect-error Internal handle for WASM
private [1]: number;
// @ts-expect-error Internal handle for WASM
private [2]: number;
// @ts-expect-error Internal handle for WASM
private [3]: number;
/** @internal */
private [0] = 0; // Internal handle for WASM
/** @internal */
private [1] = 0; // Internal handle for WASM
/** @internal */
private [2] = 0; // Internal handle for WASM
/** @internal */
private [3] = 0; // Internal handle for WASM
/** @internal */
private tree: Tree;
constructor(internal: Internal, tree: Tree) {
@ -109,10 +113,10 @@ export class TreeCursor {
return C._ts_tree_cursor_end_index_wasm(this.tree[0]);
}
get currentNode(): Node | null {
get currentNode(): Node {
marshalTreeCursor(this);
C._ts_tree_cursor_current_node_wasm(this.tree[0]);
return unmarshalNode(this.tree);
return unmarshalNode(this.tree)!;
}
get currentFieldId(): number {