feat(web): add missing API functions

Co-authored-by: Will Lillis <will.lillis24@gmail.com>
This commit is contained in:
Amaan Qureshi 2025-01-05 22:06:33 -05:00
parent dcdd6ce2d2
commit 45fa028201
11 changed files with 436 additions and 35 deletions

View file

@ -121,6 +121,14 @@ extern void tree_sitter_log_callback(
const char *message
);
extern bool tree_sitter_progress_callback(
uint32_t current_offset
);
extern bool tree_sitter_query_progress_callback(
uint32_t current_offset
);
static const char *call_parse_callback(
void *payload,
uint32_t byte,
@ -150,6 +158,18 @@ static void call_log_callback(
tree_sitter_log_callback(log_type == TSLogTypeLex, message);
}
static bool progress_callback(
TSParseState *state
) {
return tree_sitter_progress_callback(state->current_byte_offset);
}
static bool query_progress_callback(
TSQueryCursorState *state
) {
return tree_sitter_query_progress_callback(state->current_byte_offset);
}
void ts_parser_new_wasm() {
TSParser *parser = ts_parser_new();
char *input_buffer = calloc(INPUT_BUFFER_SIZE, sizeof(char));
@ -172,7 +192,8 @@ TSTree *ts_parser_parse_wasm(
TSInput input = {
input_buffer,
call_parse_callback,
TSInputEncodingUTF16LE
TSInputEncodingUTF16LE,
NULL,
};
if (range_count) {
for (unsigned i = 0; i < range_count; i++) {
@ -183,7 +204,10 @@ TSTree *ts_parser_parse_wasm(
} else {
ts_parser_set_included_ranges(self, NULL, 0);
}
return ts_parser_parse(self, old_tree, input);
TSParseOptions options = {.payload = NULL, .progress_callback = progress_callback};
return ts_parser_parse_with_options(self, old_tree, input, options);
}
void ts_parser_included_ranges_wasm(TSParser *self) {
@ -278,6 +302,12 @@ void ts_tree_cursor_new_wasm(const TSTree *tree) {
marshal_cursor(&cursor);
}
void ts_tree_cursor_copy_wasm(const TSTree *tree) {
TSTreeCursor cursor = unmarshal_cursor(TRANSFER_BUFFER, tree);
TSTreeCursor copy = ts_tree_cursor_copy(&cursor);
marshal_cursor(&copy);
}
void ts_tree_cursor_delete_wasm(const TSTree *tree) {
TSTreeCursor cursor = unmarshal_cursor(TRANSFER_BUFFER, tree);
ts_tree_cursor_delete(&cursor);
@ -447,6 +477,11 @@ const char *ts_node_field_name_for_child_wasm(const TSTree *tree, uint32_t index
return ts_node_field_name_for_child(node, index);
}
const char *ts_node_field_name_for_named_child_wasm(const TSTree *tree, uint32_t index) {
TSNode node = unmarshal_node(tree);
return ts_node_field_name_for_named_child(node, index);
}
void ts_node_children_by_field_id_wasm(const TSTree *tree, uint32_t field_id) {
TSNode node = unmarshal_node(tree);
TSTreeCursor cursor = ts_tree_cursor_new(node);
@ -826,7 +861,10 @@ void ts_query_matches_wasm(
ts_query_cursor_set_match_limit(scratch_query_cursor, match_limit);
ts_query_cursor_set_max_start_depth(scratch_query_cursor, max_start_depth);
ts_query_cursor_set_timeout_micros(scratch_query_cursor, timeout_micros);
ts_query_cursor_exec(scratch_query_cursor, self, node);
TSQueryCursorOptions options = {.payload = NULL, .progress_callback = query_progress_callback};
ts_query_cursor_exec_with_options(scratch_query_cursor, self, node, &options);
uint32_t index = 0;
uint32_t match_count = 0;

View file

@ -24,6 +24,10 @@ let MIN_COMPATIBLE_VERSION;
let TRANSFER_BUFFER;
let currentParseCallback;
// eslint-disable-next-line no-unused-vars
let currentProgressCallback;
// eslint-disable-next-line no-unused-vars
let currentQueryProgressCallback;
// eslint-disable-next-line no-unused-vars
let currentLogCallback;
// eslint-disable-next-line no-unused-vars
@ -82,6 +86,12 @@ class ParserImpl {
throw new Error('Argument must be a string or a function');
}
if (options?.progressCallback) {
currentProgressCallback = options.progressCallback;
} else {
currentProgressCallback = null;
}
if (this.logCallback) {
currentLogCallback = this.logCallback;
C._ts_parser_enable_logger_wasm(this[0], 1);
@ -113,12 +123,14 @@ class ParserImpl {
if (!treeAddress) {
currentParseCallback = null;
currentLogCallback = null;
currentProgressCallback = null;
throw new Error('Parsing failed');
}
const result = new Tree(INTERNAL, treeAddress, this.language, currentParseCallback);
currentParseCallback = null;
currentLogCallback = null;
currentProgressCallback = null;
return result;
}
@ -326,7 +338,7 @@ class Node {
}
equals(other) {
return this.id === other.id;
return this.tree === other.tree && this.id === other.id;
}
child(index) {
@ -364,6 +376,20 @@ class Node {
return result;
}
fieldNameForNamedChild(index) {
marshalNode(this);
const address = C._ts_node_field_name_for_named_child_wasm(
this.tree[0],
index,
);
if (!address) {
return null;
}
const result = AsciiToString(address);
// must not free, the string memory is owned by the language
return result;
}
childrenForFieldName(fieldName) {
const fieldId = this.tree.language.fields.indexOf(fieldName);
if (fieldId !== -1 && fieldId !== 0) return this.childrenForFieldId(fieldId);
@ -610,6 +636,35 @@ class Node {
return new TreeCursor(INTERNAL, this.tree);
}
edit(edit) {
if (this.startIndex >= edit.oldEndIndex) {
this.startIndex = edit.newEndIndex + (this.startIndex - edit.oldEndIndex);
let subbedPointRow;
let subbedPointColumn;
if (this.startPosition.row > edit.oldEndPosition.row) {
subbedPointRow = this.startPosition.row - edit.oldEndPosition.row;
subbedPointColumn = this.startPosition.column;
} else {
subbedPointRow = 0;
if (this.startPosition.column >= edit.oldEndPosition.column) {
subbedPointColumn =
this.startPosition.column - edit.oldEndPosition.column;
}
}
if (subbedPointRow > 0) {
this.startPosition.row += subbedPointRow;
this.startPosition.column = subbedPointColumn;
} else {
this.startPosition.column += subbedPointColumn;
}
} else if (this.startIndex > edit.startIndex) {
this.startIndex = edit.newEndIndex;
this.startPosition.row = edit.newEndPosition.row;
this.startPosition.column = edit.newEndPosition.column;
}
}
toString() {
marshalNode(this);
const address = C._ts_node_to_string_wasm(this.tree[0]);
@ -626,6 +681,13 @@ class TreeCursor {
unmarshalTreeCursor(this);
}
copy() {
const copy = new TreeCursor(INTERNAL, this.tree);
C._ts_tree_cursor_copy_wasm(this.tree[0]);
unmarshalTreeCursor(copy);
return copy;
}
delete() {
marshalTreeCursor(this);
C._ts_tree_cursor_delete_wasm(this.tree[0]);
@ -808,6 +870,10 @@ class Language {
}
}
get name() {
return UTF8ToString(C._ts_language_name(this[0]));
}
get version() {
return C._ts_language_version(this[0]);
}
@ -951,6 +1017,7 @@ class Language {
const captureCount = C._ts_query_capture_count(address);
const patternCount = C._ts_query_pattern_count(address);
const captureNames = new Array(captureCount);
const captureQuantifiers = new Array(patternCount);
const stringValues = new Array(stringCount);
for (let i = 0; i < captureCount; i++) {
@ -963,6 +1030,15 @@ class Language {
captureNames[i] = UTF8ToString(nameAddress, nameLength);
}
for (let i = 0; i < patternCount; i++) {
const captureQuantifiersArray = new Array(captureCount);
for (let j = 0; j < captureCount; j++) {
const quantifier = C._ts_query_capture_quantifier_for_id(address, i, j);
captureQuantifiersArray[j] = quantifier;
}
captureQuantifiers[i] = captureQuantifiersArray;
}
for (let i = 0; i < stringCount; i++) {
const valueAddress = C._ts_query_string_value_for_id(
address,
@ -1185,6 +1261,7 @@ class Language {
INTERNAL,
address,
captureNames,
captureQuantifiers,
textPredicates,
predicates,
Object.freeze(setProperties),
@ -1281,12 +1358,14 @@ class LookaheadIterable {
class Query {
constructor(
internal, address, captureNames, textPredicates, predicates,
internal, address,
captureNames, captureQuantifiers, textPredicates, predicates,
setProperties, assertedProperties, refutedProperties,
) {
assertInternal(internal);
this[0] = address;
this.captureNames = captureNames;
this.captureQuantifiers = captureQuantifiers;
this.textPredicates = textPredicates;
this.predicates = predicates;
this.setProperties = setProperties;
@ -1310,6 +1389,7 @@ class Query {
matchLimit = 0xFFFFFFFF,
maxStartDepth = 0xFFFFFFFF,
timeoutMicros = 0,
progressCallback,
} = {},
) {
if (typeof matchLimit !== 'number') {
@ -1323,6 +1403,10 @@ class Query {
throw new Error('`startPosition` cannot be greater than `endPosition`');
}
if (progressCallback) {
currentQueryProgressCallback = progressCallback;
}
marshalNode(node);
C._ts_query_matches_wasm(
@ -1369,6 +1453,7 @@ class Query {
result.length = filteredCount;
C._free(startAddress);
currentQueryProgressCallback = null;
return result;
}
@ -1382,6 +1467,7 @@ class Query {
matchLimit = 0xFFFFFFFF,
maxStartDepth = 0xFFFFFFFF,
timeoutMicros = 0,
progressCallback,
} = {},
) {
if (typeof matchLimit !== 'number') {
@ -1395,6 +1481,10 @@ class Query {
throw new Error('`startPosition` cannot be greater than `endPosition`');
}
if (progressCallback) {
currentQueryProgressCallback = progressCallback;
}
marshalNode(node);
C._ts_query_captures_wasm(
@ -1443,6 +1533,7 @@ class Query {
}
C._free(startAddress);
currentQueryProgressCallback = null;
return result;
}
@ -1458,9 +1549,54 @@ class Query {
C._free(captureNameAddress);
}
disablePattern(patternIndex) {
if (patternIndex >= this.predicates.length) {
throw new Error(
`Pattern index is ${patternIndex} but the pattern count is ${this.predicates.length}`,
);
}
C._ts_query_disable_pattern(this[0], patternIndex);
}
didExceedMatchLimit() {
return this.exceededMatchLimit;
}
startIndexForPattern(patternIndex) {
if (patternIndex >= this.predicates.length) {
throw new Error(
`Pattern index is ${patternIndex} but the pattern count is ${this.predicates.length}`,
);
}
return C._ts_query_start_byte_for_pattern(this[0], patternIndex);
}
endIndexForPattern(patternIndex) {
if (patternIndex >= this.predicates.length) {
throw new Error(
`Pattern index is ${patternIndex} but the pattern count is ${this.predicates.length}`,
);
}
return C._ts_query_end_byte_for_pattern(this[0], patternIndex);
}
isPatternNonLocal(patternIndex) {
return C._ts_query_is_pattern_non_local(this[0], patternIndex) === 1;
}
isPatternRooted(patternIndex) {
return C._ts_query_is_pattern_rooted(this[0], patternIndex) === 1;
}
isPatternGuaranteedAtStep(patternIndex, stepIndex) {
return (
C._ts_query_is_pattern_guaranteed_at_step(
this[0],
patternIndex,
stepIndex,
) === 1
);
}
}
function getText(tree, startIndex, endIndex) {

View file

@ -10,9 +10,11 @@
"ts_language_symbol_for_name",
"ts_language_symbol_name",
"ts_language_symbol_type",
"ts_language_name",
"ts_language_version",
"ts_language_next_state",
"ts_node_field_name_for_child_wasm",
"ts_node_field_name_for_named_child_wasm",
"ts_node_children_by_field_id_wasm",
"ts_node_first_child_for_byte_wasm",
"ts_node_first_named_child_for_byte_wasm",
@ -68,8 +70,15 @@
"ts_query_pattern_count",
"ts_query_predicates_for_pattern",
"ts_query_disable_capture",
"ts_query_start_byte_for_pattern",
"ts_query_end_byte_for_pattern",
"ts_query_string_count",
"ts_query_string_value_for_id",
"ts_query_disable_pattern",
"ts_query_capture_quantifier_for_id",
"ts_query_is_pattern_non_local",
"ts_query_is_pattern_rooted",
"ts_query_is_pattern_guaranteed_at_step",
"ts_tree_copy",
"ts_tree_cursor_current_field_id_wasm",
"ts_tree_cursor_current_depth_wasm",
@ -96,6 +105,7 @@
"ts_tree_cursor_reset_to_wasm",
"ts_tree_cursor_start_index_wasm",
"ts_tree_cursor_start_position_wasm",
"ts_tree_cursor_copy_wasm",
"ts_tree_delete",
"ts_tree_included_ranges_wasm",
"ts_tree_edit_wasm",

View file

@ -22,4 +22,18 @@ mergeInto(LibraryManager.library, {
currentLogCallback(message, isLexMessage !== 0);
}
},
tree_sitter_progress_callback(currentOffset) {
if (currentProgressCallback) {
return currentProgressCallback({currentOffset});
}
return false;
},
tree_sitter_query_progress_callback(currentOffset) {
if (currentQueryProgressCallback) {
return currentQueryProgressCallback({currentOffset});
}
return false;
},
});

View file

@ -7,6 +7,7 @@ function languageURL(name) {
module.exports = Parser.init().then(async () => ({
Parser,
languageURL,
C: await Parser.Language.load(languageURL('c')),
EmbeddedTemplate: await Parser.Language.load(languageURL('embedded-template')),
HTML: await Parser.Language.load(languageURL('html')),
JavaScript: await Parser.Language.load(languageURL('javascript')),

View file

@ -4,6 +4,13 @@ let JavaScript;
describe('Language', () => {
before(async () => ({JavaScript, Rust} = await require('./helper')));
describe('.name, .version', () => {
it('returns the name and version of the language', () => {
assert.equal('javascript', JavaScript.name);
assert.equal(15, JavaScript.version);
});
});
describe('.fieldIdForName, .fieldNameForId', () => {
it('converts between the string and integer representations of fields', () => {
const nameId = JavaScript.fieldIdForName('name');

View file

@ -1,5 +1,5 @@
const {assert} = require('chai');
let Parser; let JavaScript; let JSON; let EmbeddedTemplate; let Python;
let Parser; let C; let JavaScript; let JSON; let EmbeddedTemplate; let Python;
const JSON_EXAMPLE = `
@ -35,7 +35,7 @@ describe('Node', () => {
let parser; let tree;
before(async () =>
({Parser, EmbeddedTemplate, JavaScript, JSON, Python} = await require('./helper')),
({Parser, C, EmbeddedTemplate, JavaScript, JSON, Python} = await require('./helper')),
);
beforeEach(() => {
@ -620,17 +620,57 @@ describe('Node', () => {
describe('.fieldNameForChild(index)', () => {
it('returns the field of a child or null', () => {
tree = parser.parse('let a = 5');
parser.setLanguage(C);
tree = parser.parse('int w = x + /* y is special! */ y;');
const noField = tree.rootNode.fieldNameForChild(0);
const name = tree.rootNode.firstChild.children[1].fieldNameForChild(0);
const value = tree.rootNode.firstChild.children[1].fieldNameForChild(2);
const overflow = tree.rootNode.firstChild.children[1].fieldNameForChild(3);
const translationUnitNode = tree.rootNode;
const declarationNode = translationUnitNode.firstChild;
const binaryExpressionNode = declarationNode
.childForFieldName('declarator')
.childForFieldName('value');
assert.equal(noField, null);
assert.equal(name, 'name');
assert.equal(value, 'value');
assert.equal(overflow, null);
// -------------------
// left: (identifier) 0
// operator: "+" _ <--- (not a named child)
// (comment) 1 <--- (is an extra)
// right: (identifier) 2
// -------------------
assert.equal(binaryExpressionNode.fieldNameForChild(0), 'left');
assert.equal(binaryExpressionNode.fieldNameForChild(1), 'operator');
// The comment should not have a field name, as it's just an extra
assert.equal(binaryExpressionNode.fieldNameForChild(2), null);
assert.equal(binaryExpressionNode.fieldNameForChild(3), 'right');
// Negative test - Not a valid child index
assert.equal(binaryExpressionNode.fieldNameForChild(4), null);
});
});
describe('.fieldNameForNamedChild(index)', () => {
it('returns the field of a named child or null', () => {
parser.setLanguage(C);
tree = parser.parse('int w = x + /* y is special! */ y;');
const translationUnitNode = tree.rootNode;
const declarationNode = translationUnitNode.firstNamedChild;
const binaryExpressionNode = declarationNode
.childForFieldName('declarator')
.childForFieldName('value');
// -------------------
// left: (identifier) 0
// operator: "+" _ <--- (not a named child)
// (comment) 1 <--- (is an extra)
// right: (identifier) 2
// -------------------
assert.equal(binaryExpressionNode.fieldNameForNamedChild(0), 'left');
// The comment should not have a field name, as it's just an extra
assert.equal(binaryExpressionNode.fieldNameForNamedChild(1), null);
// The operator is not a named child, so the named child at index 2 is the right child
assert.equal(binaryExpressionNode.fieldNameForNamedChild(2), 'right');
// Negative test - Not a valid child index
assert.equal(binaryExpressionNode.fieldNameForNamedChild(3), null);
});
});
});

View file

@ -1,11 +1,11 @@
const {assert} = require('chai');
let Parser; let JavaScript; let HTML; let languageURL;
let Parser; let JavaScript; let HTML; let languageURL; let JSON;
describe('Parser', () => {
let parser;
before(async () =>
({Parser, JavaScript, HTML, languageURL} = await require('./helper')),
({Parser, JavaScript, HTML, JSON, languageURL} = await require('./helper')),
);
beforeEach(() => {
@ -388,5 +388,26 @@ describe('Parser', () => {
'(program (expression_statement (call_expression function: (identifier) arguments: (arguments))) (expression_statement (identifier)))',
);
});
it('parses with a timeout', () => {
parser.setLanguage(JSON);
const startTime = performance.now();
assert.throws(() => {
parser.parse(
(offset, _) => offset === 0 ? '[' : ',0',
null,
{
progressCallback: (_) => {
if (performance.now() - startTime > 1) {
return true;
}
return false;
},
},
);
},
);
}).timeout(5000);
});
});

View file

@ -455,13 +455,112 @@ describe('Query', () => {
describe('Set a timeout', () =>
it('returns less than the expected matches', () => {
tree = parser.parse('function foo() while (true) { } }\n'.repeat(1000));
query = JavaScript.query('(function_declaration name: (identifier) @function)');
const matches = query.matches(tree.rootNode, { timeoutMicros: 1000 });
query = JavaScript.query(
'(function_declaration name: (identifier) @function)',
);
const matches = query.matches(tree.rootNode, {timeoutMicros: 1000});
assert.isBelow(matches.length, 1000);
const matches2 = query.matches(tree.rootNode, { timeoutMicros: 0 });
const matches2 = query.matches(tree.rootNode, {timeoutMicros: 0});
assert.equal(matches2.length, 1000);
})
);
}));
describe('Start and end indices for patterns', () => {
it('Returns the start and end indices for a pattern', () => {
const patterns1 = `
"+" @operator
"-" @operator
"*" @operator
"=" @operator
"=>" @operator
`.trim();
const patterns2 = `
(identifier) @a
(string) @b
`.trim();
const patterns3 = `
((identifier) @b (#match? @b i))
(function_declaration name: (identifier) @c)
(method_definition name: (property_identifier) @d)
`.trim();
const source = patterns1 + patterns2 + patterns3;
const query = JavaScript.query(source);
assert.equal(query.startIndexForPattern(0), 0);
assert.equal(query.endIndexForPattern(0), '"+" @operator\n'.length);
assert.equal(query.startIndexForPattern(5), patterns1.length);
assert.equal(
query.endIndexForPattern(5),
patterns1.length + '(identifier) @a\n'.length,
);
assert.equal(
query.startIndexForPattern(7),
patterns1.length + patterns2.length,
);
assert.equal(
query.endIndexForPattern(7),
patterns1.length +
patterns2.length +
'((identifier) @b (#match? @b i))\n'.length,
);
});
});
describe('Disable pattern', () => {
it('Disables patterns in the query', () => {
const query = JavaScript.query(`
(function_declaration name: (identifier) @name)
(function_declaration body: (statement_block) @body)
(class_declaration name: (identifier) @name)
(class_declaration body: (class_body) @body)
`);
// disable the patterns that match names
query.disablePattern(0);
query.disablePattern(2);
const source = 'class A { constructor() {} } function b() { return 1; }';
tree = parser.parse(source);
const matches = query.matches(tree.rootNode);
assert.deepEqual(formatMatches(matches), [
{
pattern: 3,
captures: [{name: 'body', text: '{ constructor() {} }'}],
},
{pattern: 1, captures: [{name: 'body', text: '{ return 1; }'}]},
]);
});
});
describe('Executes with a timeout', () => {
it('Returns less than the expected matches', () => {
tree = parser.parse('function foo() while (true) { } }\n'.repeat(1000));
query = JavaScript.query(
'(function_declaration) @function',
);
const startTime = performance.now();
const matches = query.matches(
tree.rootNode,
{
progressCallback: (_) => {
if (performance.now() - startTime > 1) {
return true;
}
return false;
},
},
);
assert.isBelow(matches.length, 1000);
const matches2 = query.matches(tree.rootNode);
assert.equal(matches2.length, 1000);
});
});
});
function formatMatches(matches) {

View file

@ -363,7 +363,7 @@ describe('Tree', () => {
);
const tree2 = tree.copy();
([input, edit] = spliceInput(input, 3, 0, '123'));
[input, edit] = spliceInput(input, 3, 0, '123');
assert.equal(input, 'abc123 + cde');
tree.edit(edit);

View file

@ -1,4 +1,4 @@
declare module 'web-tree-sitter' {
declare module "web-tree-sitter" {
class Parser {
/**
*
@ -6,7 +6,11 @@ declare module 'web-tree-sitter' {
*/
static init(moduleOptions?: object): Promise<void>;
delete(): void;
parse(input: string | Parser.Input, oldTree?: Parser.Tree, options?: Parser.Options): Parser.Tree;
parse(
input: string | Parser.Input,
oldTree?: Parser.Tree,
options?: Parser.Options,
): Parser.Tree;
getIncludedRanges(): Parser.Range[];
getTimeoutMicros(): number;
setTimeoutMicros(timeout: number): void;
@ -20,6 +24,11 @@ declare module 'web-tree-sitter' {
namespace Parser {
export type Options = {
includedRanges?: Range[];
progressCallback?: (state: Parser.State) => boolean;
};
export type State = {
currentOffset: number;
};
export type Point = {
@ -28,10 +37,10 @@ declare module 'web-tree-sitter' {
};
export type Range = {
startIndex: number,
endIndex: number,
startPosition: Point,
endPosition: Point
startIndex: number;
endIndex: number;
startPosition: Point;
endPosition: Point;
};
export type Edit = {
@ -46,7 +55,7 @@ declare module 'web-tree-sitter' {
export type Logger = (
message: string,
params: { [param: string]: string },
type: "parse" | "lex"
type: "parse" | "lex",
) => void;
export interface Input {
@ -105,10 +114,20 @@ declare module 'web-tree-sitter' {
namedDescendantForIndex(index: number): SyntaxNode;
namedDescendantForIndex(startIndex: number, endIndex: number): SyntaxNode;
descendantForPosition(position: Point): SyntaxNode;
descendantForPosition(startPosition: Point, endPosition: Point): SyntaxNode;
descendantForPosition(
startPosition: Point,
endPosition: Point,
): SyntaxNode;
namedDescendantForPosition(position: Point): SyntaxNode;
namedDescendantForPosition(startPosition: Point, endPosition: Point): SyntaxNode;
descendantsOfType(types: String | Array<String>, startPosition?: Point, endPosition?: Point): Array<SyntaxNode>;
namedDescendantForPosition(
startPosition: Point,
endPosition: Point,
): SyntaxNode;
descendantsOfType(
types: String | Array<String>,
startPosition?: Point,
endPosition?: Point,
): Array<SyntaxNode>;
walk(): TreeCursor;
}
@ -131,6 +150,7 @@ declare module 'web-tree-sitter' {
readonly currentDepth: number;
readonly currentDescendantIndex: number;
copy(): TreeCursor;
reset(node: SyntaxNode): void;
resetTo(cursor: TreeCursor): void;
delete(): void;
@ -171,6 +191,10 @@ declare module 'web-tree-sitter' {
captures: QueryCapture[];
}
export type QueryState = {
currentOffset: number;
};
export type QueryOptions = {
startPosition?: Point;
endPosition?: Point;
@ -179,6 +203,7 @@ declare module 'web-tree-sitter' {
matchLimit?: number;
maxStartDepth?: number;
timeoutMicros?: number;
progressCallback: (state: QueryState) => boolean;
};
export interface PredicateResult {
@ -186,8 +211,17 @@ declare module 'web-tree-sitter' {
operands: { name: string; type: string }[];
}
export enum CaptureQuantifier {
Zero = 0,
ZeroOrOne = 1,
ZeroOrMore = 2,
One = 3,
OneOrMore = 4,
}
export class Query {
captureNames: string[];
captureQuantifiers: CaptureQuantifier[];
readonly predicates: { [name: string]: Function }[];
readonly setProperties: any[];
readonly assertedProperties: any[];
@ -204,6 +238,7 @@ declare module 'web-tree-sitter' {
isPatternRooted(patternIndex: number): boolean;
isPatternNonLocal(patternIndex: number): boolean;
startIndexForPattern(patternIndex: number): number;
endIndexForPattern(patternIndex: number): number;
didExceedMatchLimit(): boolean;
}
@ -238,5 +273,5 @@ declare module 'web-tree-sitter' {
}
}
export = Parser
export = Parser;
}