feat(web): document the API
This commit is contained in:
parent
a4b20c1c56
commit
09cb4c5729
17 changed files with 1155 additions and 198 deletions
|
|
@ -4,21 +4,85 @@ import { marshalRange, unmarshalRange } from './marshal';
|
|||
import { checkModule, initializeBinding } from './bindings';
|
||||
import { Tree } from './tree';
|
||||
|
||||
/**
|
||||
* Options for parsing
|
||||
*
|
||||
* The `includedRanges` property is an array of {@link Range} objects that
|
||||
* represent the ranges of text that the parser should include when parsing.
|
||||
*
|
||||
* The `progressCallback` property is a function that is called periodically
|
||||
* during parsing to check whether parsing should be cancelled.
|
||||
*
|
||||
* See {@link Parser#parse} for more information.
|
||||
*/
|
||||
export interface ParseOptions {
|
||||
/**
|
||||
* An array of {@link Range} objects that
|
||||
* represent the ranges of text that the parser should include when parsing.
|
||||
*
|
||||
* This sets the ranges of text that the parser should include when parsing.
|
||||
* By default, the parser will always include entire documents. This
|
||||
* function allows you to parse only a *portion* of a document but
|
||||
* still return a syntax tree whose ranges match up with the document
|
||||
* as a whole. You can also pass multiple disjoint ranges.
|
||||
* If `ranges` is empty, then the entire document will be parsed.
|
||||
* Otherwise, the given ranges must be ordered from earliest to latest
|
||||
* in the document, and they must not overlap. That is, the following
|
||||
* must hold for all `i` < `length - 1`:
|
||||
* ```text
|
||||
* ranges[i].end_byte <= ranges[i + 1].start_byte
|
||||
* ```
|
||||
*/
|
||||
includedRanges?: Range[];
|
||||
|
||||
/**
|
||||
* A function that is called periodically during parsing to check
|
||||
* whether parsing should be cancelled. If the progress callback returns
|
||||
* `false`, then parsing will be cancelled. You can also use this to instrument
|
||||
* parsing and check where the parser is at in the document. The progress callback
|
||||
* takes a single argument, which is a {@link ParseState} representing the current
|
||||
* state of the parser.
|
||||
*/
|
||||
progressCallback?: (state: ParseState) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* A stateful object that is passed into the progress callback {@link ParseOptions#progressCallback}
|
||||
* to provide the current state of the parser.
|
||||
*/
|
||||
export interface ParseState {
|
||||
/** The byte offset in the document that the parser is at. */
|
||||
currentOffset: number;
|
||||
}
|
||||
|
||||
// Global variable for transferring data across the FFI boundary
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* Global variable for transferring data across the FFI boundary
|
||||
*/
|
||||
export let TRANSFER_BUFFER: number;
|
||||
|
||||
let VERSION: number;
|
||||
let MIN_COMPATIBLE_VERSION: number;
|
||||
/**
|
||||
* The latest ABI version that is supported by the current version of the
|
||||
* library.
|
||||
*
|
||||
* When Languages are generated by the Tree-sitter CLI, they are
|
||||
* assigned an ABI version number that corresponds to the current CLI version.
|
||||
* The Tree-sitter library is generally backwards-compatible with languages
|
||||
* generated using older CLI versions, but is not forwards-compatible.
|
||||
*/
|
||||
export let LANGUAGE_VERSION: number;
|
||||
|
||||
/**
|
||||
* The earliest ABI version that is supported by the current version of the
|
||||
* library.
|
||||
*/
|
||||
export let MIN_COMPATIBLE_VERSION: number;
|
||||
|
||||
/**
|
||||
* A stateful object that is used to produce a {@link Tree} based on some
|
||||
* source code.
|
||||
*/
|
||||
export class Parser {
|
||||
/** @internal */
|
||||
private [0] = 0; // Internal handle for WASM
|
||||
|
|
@ -26,26 +90,33 @@ export class Parser {
|
|||
/** @internal */
|
||||
private [1] = 0; // Internal handle for WASM
|
||||
|
||||
/** @internal */
|
||||
private language: Language | null = null;
|
||||
|
||||
/** @internal */
|
||||
private logCallback: LogCallback | null = null;
|
||||
|
||||
/** The parser's current language. */
|
||||
language: Language | null = null;
|
||||
|
||||
/**
|
||||
* This must always be called before creating a Parser.
|
||||
*
|
||||
* You can optionally pass in options to configure the WASM module, the most common
|
||||
* one being `locateFile` to help the module find the `.wasm` file.
|
||||
*/
|
||||
static async init(moduleOptions?: EmscriptenModule) {
|
||||
setModule(await initializeBinding(moduleOptions));
|
||||
TRANSFER_BUFFER = C._ts_init();
|
||||
VERSION = C.getValue(TRANSFER_BUFFER, 'i32');
|
||||
LANGUAGE_VERSION = C.getValue(TRANSFER_BUFFER, 'i32');
|
||||
MIN_COMPATIBLE_VERSION = C.getValue(TRANSFER_BUFFER + SIZE_OF_INT, 'i32');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new parser.
|
||||
*/
|
||||
constructor() {
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
initialize() {
|
||||
if (!checkModule()) {
|
||||
throw new Error("cannot construct a Parser before calling `init()`");
|
||||
|
|
@ -55,6 +126,7 @@ export class Parser {
|
|||
this[1] = C.getValue(TRANSFER_BUFFER + SIZE_OF_INT, 'i32');
|
||||
}
|
||||
|
||||
/** Delete the parser, freeing its resources. */
|
||||
delete() {
|
||||
C._ts_parser_delete(this[0]);
|
||||
C._free(this[1]);
|
||||
|
|
@ -62,6 +134,15 @@ export class Parser {
|
|||
this[1] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the language that the parser should use for parsing.
|
||||
*
|
||||
* If the language was not successfully assigned, an error will be thrown.
|
||||
* This happens if the language was generated with an incompatible
|
||||
* version of the Tree-sitter CLI. Check the language's version using
|
||||
* {@link Language#version} and compare it to this library's
|
||||
* {@link LANGUAGE_VERSION} and {@link MIN_COMPATIBLE_VERSION} constants.
|
||||
*/
|
||||
setLanguage(language: Language | null): this {
|
||||
let address: number;
|
||||
if (!language) {
|
||||
|
|
@ -70,10 +151,10 @@ export class Parser {
|
|||
} else if (language.constructor === Language) {
|
||||
address = language[0];
|
||||
const version = C._ts_language_version(address);
|
||||
if (version < MIN_COMPATIBLE_VERSION || VERSION < version) {
|
||||
if (version < MIN_COMPATIBLE_VERSION || LANGUAGE_VERSION < version) {
|
||||
throw new Error(
|
||||
`Incompatible language version ${version}. ` +
|
||||
`Compatibility range ${MIN_COMPATIBLE_VERSION} through ${VERSION}.`
|
||||
`Compatibility range ${MIN_COMPATIBLE_VERSION} through ${LANGUAGE_VERSION}.`
|
||||
);
|
||||
}
|
||||
this.language = language;
|
||||
|
|
@ -85,15 +166,27 @@ export class Parser {
|
|||
return this;
|
||||
}
|
||||
|
||||
getLanguage(): Language | null {
|
||||
return this.language;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a slice of UTF8 text.
|
||||
*
|
||||
* @param {string | ParseCallback} callback - The UTF8-encoded text to parse or a callback function.
|
||||
*
|
||||
* @param {Tree | null} [oldTree] - A previous syntax tree parsed from the same document. If the text of the
|
||||
* document has changed since `oldTree` was created, then you must edit `oldTree` to match
|
||||
* the new text using {@link Tree#edit}.
|
||||
*
|
||||
* @param {ParseOptions} [options] - Options for parsing the text.
|
||||
* This can be used to set the included ranges, or a progress callback.
|
||||
*
|
||||
* @returns {Tree | null} A {@link Tree} if parsing succeeded, or `null` if:
|
||||
* - The parser has not yet had a language assigned with {@link Parser#setLanguage}.
|
||||
* - The progress callback returned true.
|
||||
*/
|
||||
parse(
|
||||
callback: string | ParseCallback,
|
||||
oldTree?: Tree | null,
|
||||
options: ParseOptions = {}
|
||||
): Tree {
|
||||
options?: ParseOptions,
|
||||
): Tree | null {
|
||||
if (typeof callback === 'string') {
|
||||
C.currentParseCallback = (index: number) => callback.slice(index);
|
||||
} else if (typeof callback === 'function') {
|
||||
|
|
@ -102,7 +195,7 @@ export class Parser {
|
|||
throw new Error('Argument must be a string or a function');
|
||||
}
|
||||
|
||||
if (options.progressCallback) {
|
||||
if (options?.progressCallback) {
|
||||
C.currentProgressCallback = options.progressCallback;
|
||||
} else {
|
||||
C.currentProgressCallback = null;
|
||||
|
|
@ -118,7 +211,7 @@ export class Parser {
|
|||
|
||||
let rangeCount = 0;
|
||||
let rangeAddress = 0;
|
||||
if (options.includedRanges) {
|
||||
if (options?.includedRanges) {
|
||||
rangeCount = options.includedRanges.length;
|
||||
rangeAddress = C._calloc(rangeCount, SIZE_OF_RANGE);
|
||||
let address = rangeAddress;
|
||||
|
|
@ -140,7 +233,7 @@ export class Parser {
|
|||
C.currentParseCallback = null;
|
||||
C.currentLogCallback = null;
|
||||
C.currentProgressCallback = null;
|
||||
throw new Error('Parsing failed');
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!this.language) {
|
||||
|
|
@ -154,10 +247,20 @@ export class Parser {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instruct the parser to start the next parse from the beginning.
|
||||
*
|
||||
* If the parser previously failed because of a timeout, cancellation,
|
||||
* or callback, then by default, it will resume where it left off on the
|
||||
* next call to {@link Parser#parse} or other parsing functions.
|
||||
* If you don't want to resume, and instead intend to use this parser to
|
||||
* parse some other document, you must call `reset` first.
|
||||
*/
|
||||
reset(): void {
|
||||
C._ts_parser_reset(this[0]);
|
||||
}
|
||||
|
||||
/** Get the ranges of text that the parser will include when parsing. */
|
||||
getIncludedRanges(): Range[] {
|
||||
C._ts_parser_included_ranges_wasm(this[0]);
|
||||
const count = C.getValue(TRANSFER_BUFFER, 'i32');
|
||||
|
|
@ -176,14 +279,31 @@ export class Parser {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since version 0.25.0, prefer passing a progress callback to {@link Parser#parse}
|
||||
*
|
||||
* Get the duration in microseconds that parsing is allowed to take.
|
||||
*
|
||||
* This is set via {@link Parser#setTimeoutMicros}.
|
||||
*/
|
||||
getTimeoutMicros(): number {
|
||||
return C._ts_parser_timeout_micros(this[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since version 0.25.0, prefer passing a progress callback to {@link Parser#parse}
|
||||
*
|
||||
* Set the maximum duration in microseconds that parsing should be allowed
|
||||
* to take before halting.
|
||||
*
|
||||
* If parsing takes longer than this, it will halt early, returning `null`.
|
||||
* See {@link Parser#parse} for more information.
|
||||
*/
|
||||
setTimeoutMicros(timeout: number): void {
|
||||
C._ts_parser_set_timeout_micros(this[0], 0, timeout);
|
||||
}
|
||||
|
||||
/** Set the logging callback that a parser should use during parsing. */
|
||||
setLogger(callback: LogCallback | boolean | null): this {
|
||||
if (!callback) {
|
||||
this.logCallback = null;
|
||||
|
|
@ -195,6 +315,7 @@ export class Parser {
|
|||
return this;
|
||||
}
|
||||
|
||||
/** Get the parser's current logger. */
|
||||
getLogger(): LogCallback | null {
|
||||
return this.logCallback;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue