feat: add and apply eslint config

This commit is contained in:
Amaan Qureshi 2025-01-16 01:10:54 -05:00
parent 2cae67892e
commit 31ceb99603
23 changed files with 1349 additions and 771 deletions

View file

@ -1,4 +1,4 @@
import { CaptureQuantifier } from "./query";
import { CaptureQuantifier } from './query';
export interface Point {
row: number;
@ -48,14 +48,15 @@ export function assertInternal(x: unknown): asserts x is Internal {
if (x !== INTERNAL) throw new Error('Illegal constructor');
}
export function isPoint(point: Point): point is Point {
export function isPoint(point?: Point): point is Point {
return (
!!point &&
typeof (point as Point).row === 'number' &&
typeof (point as Point).column === 'number'
typeof (point).row === 'number' &&
typeof (point).column === 'number'
);
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
export const C: EmscriptenModule & {
// Global
_ts_init(): number;
@ -69,7 +70,6 @@ export const C: EmscriptenModule & {
_ts_parser_new_wasm(): void;
_ts_parser_delete(address: number): void;
_ts_parser_set_language(parserAddress: number, languageAddress: number): void;
_ts_language_version(address: number): number;
_ts_parser_enable_logger_wasm(address: number, enabled: number): void;
_ts_parser_parse_wasm(
address: number,
@ -234,5 +234,5 @@ export const C: EmscriptenModule & {
_ts_lookahead_iterator_reset(address: number, languageAddress: number, stateId: number): boolean;
_ts_lookahead_iterator_next(address: number): boolean;
// @ts-ignore
// @ts-expect-error Module is defined after compilation
} = Module;

View file

@ -4,11 +4,7 @@ import { Node } from './node';
import { TRANSFER_BUFFER } from './parser';
import { CaptureQuantifier, Predicate, PredicateStep, Properties, Query, TextPredicate } from './query';
declare const UTF8ToString: (ptr: number, maxBytesToRead?: number) => string;
declare const lengthBytesUTF8: (str: string) => number;
declare const stringToUTF8: (str: string, outPtr: number, maxBytesToRead: number) => void;
declare const getValue: (ptr: number, type: string) => any;
declare const loadWebAssemblyModule: (bytes: Uint8Array, options: { loadAsync: boolean }) => Promise<any>;
declare const loadWebAssemblyModule: (bytes: Uint8Array, options: { loadAsync: boolean }) => Promise<Record<string, () => number>>;
const PREDICATE_STEP_TYPE_CAPTURE = 1;
const PREDICATE_STEP_TYPE_STRING = 2;
@ -24,13 +20,13 @@ export class Language {
constructor(internal: Internal, address: number) {
assertInternal(internal);
this[0] = address;
this.types = new Array(C._ts_language_symbol_count(this[0]));
this.types = new Array<string>(C._ts_language_symbol_count(this[0]));
for (let i = 0, n = this.types.length; i < n; i++) {
if (C._ts_language_symbol_type(this[0], i) < 2) {
this.types[i] = UTF8ToString(C._ts_language_symbol_name(this[0], i));
}
}
this.fields = new Array(C._ts_language_field_count(this[0]) + 1);
this.fields = new Array<string>(C._ts_language_field_count(this[0]) + 1);
for (let i = 0, n = this.fields.length; i < n; i++) {
const fieldName = C._ts_language_field_name_for_id(this[0], i);
if (fieldName !== 0) {
@ -65,7 +61,7 @@ export class Language {
}
fieldNameForId(fieldId: number): string | null {
return this.fields[fieldId] || null;
return this.fields[fieldId] ?? null;
}
idForNodeType(type: string, named: boolean): number | null {
@ -98,7 +94,7 @@ export class Language {
C._ts_language_supertypes_wasm(this[0]);
const count = getValue(TRANSFER_BUFFER, 'i32');
const buffer = getValue(TRANSFER_BUFFER + SIZE_OF_INT, 'i32');
const result = new Array(count);
const result = new Array<number>(count);
if (count > 0) {
let address = buffer;
@ -115,7 +111,7 @@ export class Language {
C._ts_language_subtypes_wasm(this[0], supertype);
const count = getValue(TRANSFER_BUFFER, 'i32');
const buffer = getValue(TRANSFER_BUFFER + SIZE_OF_INT, 'i32');
const result = new Array(count);
const result = new Array<number>(count);
if (count > 0) {
let address = buffer;
@ -155,7 +151,7 @@ export class Language {
const errorByte = getValue(TRANSFER_BUFFER, 'i32');
const errorIndex = UTF8ToString(sourceAddress, errorByte).length;
const suffix = source.slice(errorIndex, errorIndex + 100).split('\n')[0];
let word = suffix.match(QUERY_WORD_REGEX)?.[0] || '';
let word = suffix.match(QUERY_WORD_REGEX)?.[0] ?? '';
let error: Error;
switch (errorId) {
@ -178,7 +174,9 @@ export class Language {
break;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
(error as any).index = errorIndex;
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
(error as any).length = word.length;
C._free(sourceAddress);
throw error;
@ -188,7 +186,7 @@ export class Language {
const captureCount = C._ts_query_capture_count(address);
const patternCount = C._ts_query_pattern_count(address);
const captureNames = new Array<string>(captureCount);
const captureQuantifiers = new Array<Array<CaptureQuantifier>>(patternCount);
const captureQuantifiers = new Array<CaptureQuantifier[]>(patternCount);
const stringValues = new Array<string>(stringCount);
for (let i = 0; i < captureCount; i++) {
@ -223,8 +221,8 @@ export class Language {
const setProperties = new Array<Properties>(patternCount);
const assertedProperties = new Array<Properties>(patternCount);
const refutedProperties = new Array<Properties>(patternCount);
const predicates = new Array<Array<Predicate>>(patternCount);
const textPredicates = new Array<Array<TextPredicate>>(patternCount);
const predicates = new Array<Predicate[]>(patternCount);
const textPredicates = new Array<TextPredicate[]>(patternCount);
for (let i = 0; i < patternCount; i++) {
const predicatesAddress = C._ts_query_predicates_for_pattern(
@ -255,7 +253,7 @@ export class Language {
throw new Error('Predicates must begin with a literal value');
}
const operator = steps[0].value!;
const operator = steps[0].value;
let isPositive = true;
let matchAll = true;
let captureName: string | undefined;
@ -278,8 +276,8 @@ export class Language {
}
matchAll = !operator.startsWith('any-');
if (steps[2].type === 'capture') {
const captureName1 = steps[1].name!;
const captureName2 = steps[2].name!;
const captureName1 = steps[1].name;
const captureName2 = steps[2].name;
textPredicates[i].push((captures) => {
const nodes1: Node[] = [];
const nodes2: Node[] = [];
@ -366,7 +364,7 @@ export class Language {
);
}
if (!setProperties[i]) setProperties[i] = {};
setProperties[i][steps[1].value!] = steps[2]?.value || null;
setProperties[i][steps[1].value!] = steps[2]?.value ?? null;
break;
}
@ -384,7 +382,7 @@ export class Language {
}
const properties = operator === 'is?' ? assertedProperties : refutedProperties;
if (!properties[i]) properties[i] = {};
properties[i][steps[1].value!] = steps[2]?.value || null;
properties[i][steps[1].value!] = steps[2]?.value ?? null;
break;
}
@ -448,15 +446,14 @@ export class Language {
);
}
static load(input: string | Uint8Array): Promise<Language> {
static async load(input: string | Uint8Array): Promise<Language> {
let bytes: Promise<Uint8Array>;
if (input instanceof Uint8Array) {
bytes = Promise.resolve(input);
} else {
// @ts-ignore
if (globalThis.process?.versions?.node) {
// @ts-ignore
const fs = require('fs/promises');
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);
} else {
bytes = fetch(input)
@ -472,20 +469,15 @@ export class Language {
}
}
return bytes
.then((bytes) => loadWebAssemblyModule(bytes, { loadAsync: true }))
.then((mod) => {
const symbolNames = Object.keys(mod);
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)}`);
throw new Error('Language.load failed: no language function found in WASM file');
}
const languageAddress = mod[functionName]();
return new Language(INTERNAL, languageAddress);
});
const mod = await loadWebAssemblyModule(await bytes, { loadAsync: true });
const symbolNames = Object.keys(mod);
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)}`);
throw new Error('Language.load failed: no language function found in WASM file');
}
const languageAddress = mod[functionName]();
return new Language(INTERNAL, languageAddress);
}
}

View file

@ -37,11 +37,10 @@ export class LookaheadIterator implements Iterable<string> {
}
[Symbol.iterator](): Iterator<string> {
const self = this;
return {
next(): IteratorResult<string> {
if (C._ts_lookahead_iterator_next(self[0])) {
return { done: false, value: self.currentType };
next: (): IteratorResult<string> => {
if (C._ts_lookahead_iterator_next(this[0])) {
return { done: false, value: this.currentType };
}
return { done: true, value: '' };
}

View file

@ -5,7 +5,7 @@ import { Query } from "./query";
import { TreeCursor } from "./tree_cursor";
import { TRANSFER_BUFFER } from "./parser";
export function unmarshalCaptures(query: Query, tree: Tree, address: number, result: Array<{name: string, node: Node}>) {
export function unmarshalCaptures(query: Query, tree: Tree, address: number, result: {name: string, node: Node}[]) {
for (let i = 0, n = result.length; i < n; i++) {
const captureIndex = getValue(address, 'i32');
address += SIZE_OF_INT;

View file

@ -7,7 +7,6 @@ import { TRANSFER_BUFFER } from './parser';
declare const AsciiToString: (ptr: number) => string;
export class Node {
// @ts-ignore
private [0]: number; // Internal handle for WASM
private _children?: (Node | null)[];
private _namedChildren?: (Node | null)[];

View file

@ -3,10 +3,6 @@ import { Language } from './language';
import { marshalRange, unmarshalRange } from './marshal';
import { Tree } from './tree';
declare const getValue: (ptr: number, type: string) => any;
declare const Module: { [key: string]: any };
declare let initPromise: Promise<void>;
interface ParseOptions {
includedRanges?: Range[];
progressCallback?: (percent: number) => void;
@ -21,16 +17,15 @@ export let TRANSFER_BUFFER: number;
let VERSION: number;
let MIN_COMPATIBLE_VERSION: number;
// @ts-ignore
let currentParseCallback: ((index: number, position: Point) => string) | null = null;
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unused-vars
let currentLogCallback: LogCallback = null;
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unused-vars
let currentProgressCallback: ((percent: number) => void) | null = null;
export class ParserImpl {
protected [0]: number = 0;
protected [1]: number = 0;
protected [0] = 0;
protected [1] = 0;
protected language: Language | null = null;
protected logCallback: LogCallback = null;
static Language: typeof Language;
@ -94,7 +89,7 @@ export class ParserImpl {
throw new Error('Argument must be a string or a function');
}
if (options?.progressCallback) {
if (options.progressCallback) {
currentProgressCallback = options.progressCallback;
} else {
currentProgressCallback = null;
@ -110,7 +105,7 @@ export class ParserImpl {
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;
@ -154,7 +149,7 @@ export class ParserImpl {
C._ts_parser_included_ranges_wasm(this[0]);
const count = getValue(TRANSFER_BUFFER, 'i32');
const buffer = getValue(TRANSFER_BUFFER + SIZE_OF_INT, 'i32');
const result: Range[] = new Array(count);
const result = new Array<Range>(count);
if (count > 0) {
let address = buffer;

View file

@ -3,7 +3,7 @@ import { Node } from './node';
import { marshalNode, unmarshalCaptures } from './marshal';
import { TRANSFER_BUFFER } from './parser';
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unused-vars
let currentQueryProgressCallback: ((percent: number) => void) | null = null;
interface QueryOptions {
@ -17,9 +17,7 @@ interface QueryOptions {
progressCallback?: (percent: number) => void;
}
export interface Properties {
[key: string]: string | null;
}
export type Properties = Record<string, string | null>;
export interface Predicate {
operator: string;
@ -56,7 +54,7 @@ export type PredicateStep =
| { type: 'string'; value: string }
| { type: 'capture'; value?: string, name: string };
export type TextPredicate = (captures: Array<Capture>) => boolean;
export type TextPredicate = (captures: Capture[]) => boolean;
export class Query {
private [0]: number; // Internal handle for WASM
@ -64,7 +62,7 @@ export class Query {
private textPredicates: TextPredicate[][];
readonly captureNames: string[];
readonly captureQuantifiers: number[][];
readonly captureQuantifiers: CaptureQuantifier[][];
readonly predicates: Predicate[][];
readonly setProperties: Properties[];
readonly assertedProperties: Properties[];
@ -75,7 +73,7 @@ export class Query {
internal: Internal,
address: number,
captureNames: string[],
captureQuantifiers: number[][],
captureQuantifiers: CaptureQuantifier[][],
textPredicates: TextPredicate[][],
predicates: Predicate[][],
setProperties: Properties[],
@ -103,13 +101,13 @@ export class Query {
node: Node,
options: QueryOptions = {}
): QueryMatch[] {
const startPosition = options.startPosition || ZERO_POINT;
const endPosition = options.endPosition || ZERO_POINT;
const startIndex = options.startIndex || 0;
const endIndex = options.endIndex || 0;
const matchLimit = options.matchLimit || 0xFFFFFFFF;
const maxStartDepth = options.maxStartDepth || 0xFFFFFFFF;
const timeoutMicros = options.timeoutMicros || 0;
const startPosition = options.startPosition ?? ZERO_POINT;
const endPosition = options.endPosition ?? ZERO_POINT;
const startIndex = options.startIndex ?? 0;
const endIndex = options.endIndex ?? 0;
const matchLimit = options.matchLimit ?? 0xFFFFFFFF;
const maxStartDepth = options.maxStartDepth ?? 0xFFFFFFFF;
const timeoutMicros = options.timeoutMicros ?? 0;
const progressCallback = options.progressCallback;
if (typeof matchLimit !== 'number') {
@ -151,7 +149,7 @@ export class Query {
const rawCount = getValue(TRANSFER_BUFFER, 'i32');
const startAddress = getValue(TRANSFER_BUFFER + SIZE_OF_INT, 'i32');
const didExceedMatchLimit = getValue(TRANSFER_BUFFER + 2 * SIZE_OF_INT, 'i32');
const result = new Array(rawCount);
const result = new Array<QueryMatch>(rawCount);
this.exceededMatchLimit = Boolean(didExceedMatchLimit);
let filteredCount = 0;
@ -162,17 +160,17 @@ export class Query {
const captureCount = getValue(address, 'i32');
address += SIZE_OF_INT;
const captures: Capture[] = new Array(captureCount);
const captures = new Array<Capture>(captureCount);
address = unmarshalCaptures(this, node.tree, address, captures);
if (this.textPredicates[pattern].every((p) => p(captures))) {
result[filteredCount] = { pattern, captures };
const setProperties = this.setProperties[pattern];
if (setProperties) result[filteredCount].setProperties = setProperties;
result[filteredCount].setProperties = setProperties;
const assertedProperties = this.assertedProperties[pattern];
if (assertedProperties) result[filteredCount].assertedProperties = assertedProperties;
result[filteredCount].assertedProperties = assertedProperties;
const refutedProperties = this.refutedProperties[pattern];
if (refutedProperties) result[filteredCount].refutedProperties = refutedProperties;
result[filteredCount].refutedProperties = refutedProperties;
filteredCount++;
}
}
@ -187,13 +185,13 @@ export class Query {
node: Node,
options: QueryOptions = {}
): Capture[] {
const startPosition = options.startPosition || ZERO_POINT;
const endPosition = options.endPosition || ZERO_POINT;
const startIndex = options.startIndex || 0;
const endIndex = options.endIndex || 0;
const matchLimit = options.matchLimit || 0xFFFFFFFF;
const maxStartDepth = options.maxStartDepth || 0xFFFFFFFF;
const timeoutMicros = options.timeoutMicros || 0;
const startPosition = options.startPosition ?? ZERO_POINT;
const endPosition = options.endPosition ?? ZERO_POINT;
const startIndex = options.startIndex ?? 0;
const endIndex = options.endIndex ?? 0;
const matchLimit = options.matchLimit ?? 0xFFFFFFFF;
const maxStartDepth = options.maxStartDepth ?? 0xFFFFFFFF;
const timeoutMicros = options.timeoutMicros ?? 0;
const progressCallback = options.progressCallback;
if (typeof matchLimit !== 'number') {
@ -254,11 +252,11 @@ export class Query {
if (this.textPredicates[pattern].every((p) => p(captures))) {
const capture = captures[captureIndex];
const setProperties = this.setProperties[pattern];
if (setProperties) capture.setProperties = setProperties;
capture.setProperties = setProperties;
const assertedProperties = this.assertedProperties[pattern];
if (assertedProperties) capture.assertedProperties = assertedProperties;
capture.assertedProperties = assertedProperties;
const refutedProperties = this.refutedProperties[pattern];
if (refutedProperties) capture.refutedProperties = refutedProperties;
capture.refutedProperties = refutedProperties;
result.push(capture);
}
}

View file

@ -23,7 +23,7 @@ export function getText(tree: Tree, startIndex: number, endIndex: number, startP
result = result.slice(0, length);
}
}
return result || '';
return result ?? '';
}
export class Tree {
@ -83,7 +83,7 @@ export class Tree {
C._ts_tree_get_changed_ranges_wasm(this[0], other[0]);
const count = getValue(TRANSFER_BUFFER, 'i32');
const buffer = getValue(TRANSFER_BUFFER + SIZE_OF_INT, 'i32');
const result = new Array(count);
const result = new Array<Range>(count);
if (count > 0) {
let address = buffer;
@ -100,7 +100,7 @@ export class Tree {
C._ts_tree_included_ranges_wasm(this[0]);
const count = getValue(TRANSFER_BUFFER, 'i32');
const buffer = getValue(TRANSFER_BUFFER + SIZE_OF_INT, 'i32');
const result = new Array(count);
const result = new Array<Range>(count);
if (count > 0) {
let address = buffer;

View file

@ -5,14 +5,14 @@ import { TRANSFER_BUFFER } from './parser';
import { getText, Tree } from './tree';
export class TreeCursor {
// @ts-ignore
private [0]: number; // Internal handle for WASM
// @ts-ignore
private [1]: number; // Internal handle for WASM
// @ts-ignore
private [2]: number; // Internal handle for WASM
// @ts-ignore
private [3]: number; // Internal handle for WASM
// @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;
private tree: Tree;