From 07986471b3f722a4a83ae83749810b484723272f Mon Sep 17 00:00:00 2001 From: ObserverOfTime Date: Sat, 30 Aug 2025 22:42:17 +0300 Subject: [PATCH] feat(xtask): automate edits to emscripten generated d.ts --- crates/xtask/src/build_wasm.rs | 85 ++++++++++++++++++++++-- lib/binding_web/lib/web-tree-sitter.d.ts | 26 +++----- 2 files changed, 89 insertions(+), 22 deletions(-) diff --git a/crates/xtask/src/build_wasm.rs b/crates/xtask/src/build_wasm.rs index 534c87f6..58259b0f 100644 --- a/crates/xtask/src/build_wasm.rs +++ b/crates/xtask/src/build_wasm.rs @@ -9,6 +9,7 @@ use std::{ }; use anyhow::{anyhow, Result}; +use indoc::indoc; use notify::{ event::{AccessKind, AccessMode}, EventKind, RecursiveMode, @@ -159,6 +160,12 @@ pub fn run_wasm(args: &BuildWasm) -> Result<()> { emscripten_flags.extend(["-s", "EXPORT_ES6=1"]); } + macro_rules! binding_file { + ($ext:literal) => { + concat!("lib/binding_web/lib/web-tree-sitter", $ext) + }; + } + #[rustfmt::skip] emscripten_flags.extend([ "-gsource-map=inline", @@ -185,7 +192,7 @@ pub fn run_wasm(args: &BuildWasm) -> Result<()> { "-I", "lib/include", "--js-library", "lib/binding_web/lib/imports.js", "--pre-js", "lib/binding_web/lib/prefix.js", - "-o", if args.cjs { "lib/binding_web/lib/web-tree-sitter.cjs" } else { "lib/binding_web/lib/web-tree-sitter.mjs" }, + "-o", if args.cjs { binding_file!("cjs") } else { binding_file!(".mjs") }, "lib/src/lib.c", "lib/binding_web/lib/tree-sitter.c", ]); @@ -196,20 +203,90 @@ pub fn run_wasm(args: &BuildWasm) -> Result<()> { let command = command.args(&emscripten_flags); if args.watch { - watch_wasm!(|| build_wasm(command)); + watch_wasm!(|| build_wasm(command, args.emit_tsd)); } else { - build_wasm(command)?; + build_wasm(command, args.emit_tsd)?; } Ok(()) } -fn build_wasm(cmd: &mut Command) -> Result<()> { +fn build_wasm(cmd: &mut Command, edit_tsd: bool) -> Result<()> { bail_on_err( &cmd.spawn()?.wait_with_output()?, "Failed to compile the Tree-sitter Wasm library", )?; + if edit_tsd { + let file = "lib/binding_web/lib/web-tree-sitter.d.ts"; + let content = fs::read_to_string(file)? + .replace("Automatically generated", "Automatically @generated") + .replace( + "AsciiToString(ptr: any): string", + "AsciiToString(ptr: number): string", + ) + .replace( + "stringToUTF8(str: any, outPtr: any, maxBytesToWrite: any): any", + "stringToUTF8(str: string, outPtr: number, maxBytesToWrite: number): number", + ) + .replace( + "UTF8ToString(ptr: number, maxBytesToRead?: number | undefined): string", + "UTF8ToString(ptr: number, maxBytesToRead?: number): string", + ) + .replace( + "lengthBytesUTF8(str: any): number", + "lengthBytesUTF8(str: string): number", + ) + .replace( + "stringToUTF16(str: any, outPtr: any, maxBytesToWrite: any): number", + "stringToUTF16(str: string, outPtr: number, maxBytesToWrite: number): number", + ) + .replace( + concat!( + "loadWebAssemblyModule(binary: any, flags: any, libName?: string | ", + "undefined, localScope?: any | undefined, handle?: number | undefined): any" + ), + concat!( + "loadWebAssemblyModule(binary: Uint8Array, flags: Record,", + " libName?: string, localScope?: Record, handle?: number):", + " Promise number>>" + ), + ) + .replace( + "getValue(ptr: number, type?: string): any", + "getValue(ptr: number, type?: string): number", + ) + .replace("HEAPF32: any", "HEAPF32: Float32Array") + .replace("HEAPF64: any", "HEAPF64: Float64Array") + .replace("HEAP_DATA_VIEW: any", "HEAP_DATA_VIEW: DataView") + .replace("HEAP8: any", "HEAP8: Int8Array") + .replace("HEAPU8: any", "HEAPU8: Uint8Array") + .replace("HEAP16: any", "HEAP16: Int16Array") + .replace("HEAPU16: any", "HEAPU16: Uint16Array") + .replace("HEAP32: any", "HEAP32: Int32Array") + .replace("HEAPU32: any", "HEAPU32: Uint32Array") + .replace("HEAP64: any", "HEAP64: BigInt64Array") + .replace("HEAPU64: any", "HEAPU64: BigUint64Array") + .replace("BigInt;", "bigint;") + .replace("BigInt)", "bigint)") + .replace( + "WasmModule & typeof RuntimeExports;", + indoc! {" + WasmModule & typeof RuntimeExports & { + currentParseCallback: ((index: number, position: {row: number, column: number}) => string | undefined) | null; + currentLogCallback: ((message: string, isLex: boolean) => void) | null; + currentProgressCallback: ((state: {currentOffset: number, hasError: boolean}) => void) | null; + currentQueryProgressCallback: ((state: {currentOffset: number}) => void) | null; + }; + "}, + ) + .replace( + "MainModuleFactory (options?: unknown): Promise", + "MainModuleFactory(options?: Partial): Promise", + ); + fs::write(file, content)?; + } + Ok(()) } diff --git a/lib/binding_web/lib/web-tree-sitter.d.ts b/lib/binding_web/lib/web-tree-sitter.d.ts index 2e6261b0..9bb137c6 100644 --- a/lib/binding_web/lib/web-tree-sitter.d.ts +++ b/lib/binding_web/lib/web-tree-sitter.d.ts @@ -1,4 +1,4 @@ -// TypeScript bindings for emscripten-generated code. Automatically generated at compile time (manually edited). +// TypeScript bindings for emscripten-generated code. Automatically @generated at compile time. declare namespace RuntimeExports { function AsciiToString(ptr: number): string; function stringToUTF8(str: string, outPtr: number, maxBytesToWrite: number): number; @@ -25,18 +25,7 @@ declare namespace RuntimeExports { * @param {Object=} localScope * @param {number=} handle */ - function loadWebAssemblyModule( - binary: Uint8Array, - flags: { - allowUndefined?: boolean, - loadAsync?: boolean, - global?: boolean, - nodelete?: boolean, - }, - libName?: string, - localScope?: Record, - handle?: number - ): Promise number>>; + function loadWebAssemblyModule(binary: Uint8Array, flags: Record, libName?: string, localScope?: Record, handle?: number): Promise number>>; /** * @param {number} ptr * @param {string} type @@ -51,7 +40,7 @@ declare namespace RuntimeExports { let HEAPF32: Float32Array; let HEAPF64: Float64Array; let HEAP_DATA_VIEW: DataView; - let HEAP8: Int8Array + let HEAP8: Int8Array; let HEAPU8: Uint8Array; let HEAP16: Int16Array; let HEAPU16: Uint16Array; @@ -211,9 +200,10 @@ interface WasmModule { } export type MainModule = WasmModule & typeof RuntimeExports & { - currentParseCallback: ((index: number, position: {row: number, column: number}) => string | undefined) | null; - currentLogCallback: ((message: string, isLex: boolean) => void) | null; - currentProgressCallback: ((state: {currentOffset: number, hasError: boolean}) => void) | null; - currentQueryProgressCallback: ((state: {currentOffset: number}) => void) | null; + currentParseCallback: ((index: number, position: {row: number, column: number}) => string | undefined) | null; + currentLogCallback: ((message: string, isLex: boolean) => void) | null; + currentProgressCallback: ((state: {currentOffset: number, hasError: boolean}) => void) | null; + currentQueryProgressCallback: ((state: {currentOffset: number}) => void) | null; }; + export default function MainModuleFactory(options?: Partial): Promise;