This commit is contained in:
Wilco Kruijer 2026-01-21 04:02:24 +00:00 committed by GitHub
commit 35cc0ef8e4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 63 additions and 6 deletions

View file

@ -260,9 +260,12 @@ fn build_wasm(cmd: &mut Command, edit_tsd: bool) -> Result<()> {
"undefined, localScope?: any | undefined, handle?: number | undefined): any"
),
concat!(
"loadWebAssemblyModule(binary: Uint8Array | WebAssembly.Module, flags: Record<string, boolean>,",
"loadWebAssemblyModule(binary: Uint8Array | WebAssembly.Module, flags: { loadAsync: true } & Record<string, boolean>,",
" libName?: string, localScope?: Record<string, unknown>, handle?: number):",
" Promise<Record<string, () => number>>"
" Promise<Record<string, () => number>>;\n",
" function loadWebAssemblyModule(binary: Uint8Array | WebAssembly.Module, flags: { loadAsync: false } & Record<string, boolean>,",
" libName?: string, localScope?: Record<string, unknown>, handle?: number):",
" Record<string, () => number>"
),
)
.replace(

View file

@ -209,6 +209,18 @@ const Parser = require('web-tree-sitter');
})();
```
### Loading a pre-compiled WebAssembly module
In some environments, such as Cloudflare Workers and Vercel Edge Functions, you can import WebAssembly modules directly.
Modules can be loaded synchronously using the `Language.loadSync` method:
```javascript
import treeSitterJavaScript from 'tree-sitter-javascript.wasm';
// treeSitterJavaScript is of type `WebAssembly.Module`
const JavaScript = Language.loadSync(treeSitterJavaScript);
parser.setLanguage(JavaScript);
```
### Running .wasm in browser
`web-tree-sitter` can run in the browser, but there are some common pitfalls.

View file

@ -23,7 +23,8 @@ declare namespace RuntimeExports {
* @param {Object=} localScope
* @param {number=} handle
*/
function loadWebAssemblyModule(binary: Uint8Array | WebAssembly.Module, flags: Record<string, boolean>, libName?: string, localScope?: Record<string, unknown>, handle?: number): Promise<Record<string, () => number>>;
function loadWebAssemblyModule(binary: Uint8Array | WebAssembly.Module, flags: { loadAsync: true } & Record<string, boolean>, libName?: string, localScope?: Record<string, unknown>, handle?: number): Promise<Record<string, () => number>>;
function loadWebAssemblyModule(binary: Uint8Array | WebAssembly.Module, flags: { loadAsync: false } & Record<string, boolean>, libName?: string, localScope?: Record<string, unknown>, handle?: number): Record<string, () => number>;
/**
* @param {number} ptr
* @param {string} type

View file

@ -265,4 +265,21 @@ export class Language {
const languageAddress = mod[functionName]();
return new Language(INTERNAL, languageAddress);
}
/**
* Load a language synchronously from a pre-compiled WebAssembly module.
* Use this method when you have already compiled the WebAssembly module yourself.
*/
static loadSync(module: WebAssembly.Module): Language {
const mod = C.loadWebAssemblyModule(module, { loadAsync: false });
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.loadSync failed: no language function found in Wasm file');
}
const languageAddress = mod[functionName]();
return new Language(INTERNAL, languageAddress);
}
}

View file

@ -1,13 +1,37 @@
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import helper from './helper';
import type { LookaheadIterator, Language } from '../src';
import helper, { type LanguageName } from './helper';
import { LookaheadIterator, Language } from '../src';
import { Parser } from '../src';
import { readFile } from 'fs/promises';
let JavaScript: Language;
let Rust: Language;
let languageURL: (name: LanguageName) => string;
describe('Language', () => {
beforeAll(async () => ({ JavaScript, Rust } = await helper));
beforeAll(async () => ({ JavaScript, Rust, languageURL } = await helper));
describe('.loadSync', () => {
it('loads a language synchronously from a pre-compiled WebAssembly.Module', async () => {
const wasmPath = languageURL('javascript');
const wasmBytes = await readFile(wasmPath);
const wasmModule = await WebAssembly.compile(wasmBytes);
const lang = Language.loadSync(wasmModule);
expect(lang.name).toBe('javascript');
expect(lang.abiVersion).toBe(15);
// Verify the language actually works by parsing a snippet
const parser = new Parser();
parser.setLanguage(lang);
const tree = parser.parse('const x = 1;');
expect(tree).not.toBeNull();
expect(tree!.rootNode.type).toBe('program');
expect(tree!.rootNode.childCount).toBe(1);
expect(tree!.rootNode.firstChild!.type).toBe('lexical_declaration');
parser.delete();
});
});
describe('.name, .version', () => {
it('returns the name and version of the language', () => {