@singapore-editor/tree-sitter 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +32 -0
  2. package/dist/assets/__vite-browser-external-CMrW8369.js +9 -0
  3. package/dist/assets/__vite-browser-external-CMrW8369.js.map +1 -0
  4. package/dist/assets/treeSitter.worker-D1ozCaGZ.js +5698 -0
  5. package/dist/assets/treeSitter.worker-D1ozCaGZ.js.map +1 -0
  6. package/dist/index.d.ts +34 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +143 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/session.d.ts +89 -0
  11. package/dist/session.d.ts.map +1 -0
  12. package/dist/session.js +437 -0
  13. package/dist/session.js.map +1 -0
  14. package/dist/structuralSelection.d.ts +37 -0
  15. package/dist/structuralSelection.d.ts.map +1 -0
  16. package/dist/structuralSelection.js +139 -0
  17. package/dist/structuralSelection.js.map +1 -0
  18. package/dist/treeSitter/markdown.d.ts +12 -0
  19. package/dist/treeSitter/markdown.d.ts.map +1 -0
  20. package/dist/treeSitter/registry.d.ts +56 -0
  21. package/dist/treeSitter/registry.d.ts.map +1 -0
  22. package/dist/treeSitter/registry.js +144 -0
  23. package/dist/treeSitter/registry.js.map +1 -0
  24. package/dist/treeSitter/source.d.ts +42 -0
  25. package/dist/treeSitter/source.d.ts.map +1 -0
  26. package/dist/treeSitter/source.js +175 -0
  27. package/dist/treeSitter/source.js.map +1 -0
  28. package/dist/treeSitter/sourceChunkRetention.d.ts +30 -0
  29. package/dist/treeSitter/sourceChunkRetention.d.ts.map +1 -0
  30. package/dist/treeSitter/sourceChunkRetention.js +76 -0
  31. package/dist/treeSitter/sourceChunkRetention.js.map +1 -0
  32. package/dist/treeSitter/treeSitter.worker.d.ts +64 -0
  33. package/dist/treeSitter/treeSitter.worker.d.ts.map +1 -0
  34. package/dist/treeSitter/types.d.ts +198 -0
  35. package/dist/treeSitter/types.d.ts.map +1 -0
  36. package/dist/treeSitter/workerClient.d.ts +133 -0
  37. package/dist/treeSitter/workerClient.d.ts.map +1 -0
  38. package/dist/treeSitter/workerClient.js +420 -0
  39. package/dist/treeSitter/workerClient.js.map +1 -0
  40. package/package.json +50 -0
@@ -0,0 +1,420 @@
1
+ import { TreeSitterSourceChunkRetention } from "./sourceChunkRetention.js";
2
+ //#region src/treeSitter/workerClient.ts
3
+ var supportsWorkers = () => typeof Worker !== "undefined";
4
+ var supportsSharedCancellation = () => typeof SharedArrayBuffer !== "undefined";
5
+ var canUseTreeSitterWorker = () => supportsWorkers();
6
+ var TreeSitterWorkerClient = class {
7
+ worker = null;
8
+ disposeTask = null;
9
+ nextRequestId = 1;
10
+ nextGeneration = 1;
11
+ workerGeneration = 0;
12
+ lifecycle = "idle";
13
+ lastError = null;
14
+ initPromise = null;
15
+ pendingRequests = /* @__PURE__ */ new Map();
16
+ clientTasks = /* @__PURE__ */ new Set();
17
+ runtimeTasks = /* @__PURE__ */ new Map();
18
+ sourceChunkRetention = new TreeSitterSourceChunkRetention();
19
+ registeredLanguages = /* @__PURE__ */ new Map();
20
+ warmedLanguages = /* @__PURE__ */ new Set();
21
+ inspect() {
22
+ return {
23
+ lifecycle: this.lifecycle,
24
+ pendingRequests: this.pendingRequests.size,
25
+ workerGeneration: this.workerGeneration,
26
+ cache: {
27
+ registeredLanguages: this.registeredLanguages.size,
28
+ sourceChunks: this.sourceChunkRetention.inspect()
29
+ },
30
+ lastError: this.lastError?.message ?? null
31
+ };
32
+ }
33
+ registerLanguages(languages) {
34
+ return this.trackClientTask(this.finishRegisterLanguages(languages));
35
+ }
36
+ async finishRegisterLanguages(languages) {
37
+ const nextLanguages = this.unregisteredLanguages(languages);
38
+ if (nextLanguages.length === 0) return;
39
+ if (!await this.ensureWorkerReady()) return;
40
+ await this.postRequest({
41
+ type: "registerLanguages",
42
+ languages: nextLanguages
43
+ });
44
+ for (const language of nextLanguages) {
45
+ this.registeredLanguages.set(language.id, language);
46
+ this.warmedLanguages.delete(language.id);
47
+ }
48
+ }
49
+ warmLanguages(languages) {
50
+ return this.trackClientTask(this.finishWarmLanguages(languages));
51
+ }
52
+ async finishWarmLanguages(languages) {
53
+ if (!await this.ensureWorkerReady()) return;
54
+ await this.finishRegisterLanguages(languages);
55
+ const languageIds = [...new Set(languages.map((language) => language.id))].filter((languageId) => !this.warmedLanguages.has(languageId));
56
+ if (languageIds.length === 0) return;
57
+ for (const languageId of languageIds) this.warmedLanguages.add(languageId);
58
+ await this.postRequest({
59
+ type: "warmLanguages",
60
+ languageIds
61
+ });
62
+ }
63
+ parse(payload) {
64
+ return this.trackRuntimeTask(payload.runtimeSessionId, this.finishParse(payload));
65
+ }
66
+ async finishParse(payload) {
67
+ if (!await this.ensureWorkerReady()) return void 0;
68
+ const source = this.createSourceDescriptor(payload.runtimeSessionId, payload.snapshot);
69
+ const request = {
70
+ type: "parse",
71
+ documentId: payload.documentId,
72
+ runtimeSessionId: payload.runtimeSessionId,
73
+ snapshotVersion: payload.snapshotVersion,
74
+ languageId: payload.languageId,
75
+ includeHighlights: payload.includeHighlights ?? true,
76
+ includeCaptures: payload.includeCaptures,
77
+ resultMode: payload.resultMode,
78
+ source
79
+ };
80
+ const result = await this.postDocumentRequest(request);
81
+ if (isTreeSitterParseResult(result)) return result;
82
+ if (isTreeSitterParseAckResult(result)) return result;
83
+ }
84
+ edit(payload) {
85
+ return this.trackRuntimeTask(payload.runtimeSessionId, this.finishEdit(payload));
86
+ }
87
+ async finishEdit(payload) {
88
+ if (!await this.ensureWorkerReady()) return void 0;
89
+ const source = this.createSourceDescriptor(payload.runtimeSessionId, payload.snapshot);
90
+ const result = await this.postDocumentRequest({
91
+ type: "edit",
92
+ documentId: payload.documentId,
93
+ runtimeSessionId: payload.runtimeSessionId,
94
+ previousSnapshotVersion: payload.previousSnapshotVersion,
95
+ snapshotVersion: payload.snapshotVersion,
96
+ languageId: payload.languageId,
97
+ includeHighlights: payload.includeHighlights,
98
+ includeCaptures: payload.includeCaptures,
99
+ resultMode: payload.resultMode,
100
+ source,
101
+ edits: payload.edits,
102
+ inputEdits: payload.inputEdits
103
+ });
104
+ if (isTreeSitterParseResult(result)) return result;
105
+ if (isTreeSitterParseAckResult(result)) return result;
106
+ }
107
+ queryRange(payload) {
108
+ return this.trackRuntimeTask(payload.runtimeSessionId, this.finishQueryRange(payload));
109
+ }
110
+ async finishQueryRange(payload) {
111
+ if (!await this.ensureWorkerReady()) return void 0;
112
+ const result = await this.postRangeRequest({
113
+ type: "queryRange",
114
+ documentId: payload.documentId,
115
+ runtimeSessionId: payload.runtimeSessionId,
116
+ snapshotVersion: payload.snapshotVersion,
117
+ languageId: payload.languageId,
118
+ includeHighlights: payload.includeHighlights ?? true,
119
+ includeCaptures: payload.includeCaptures,
120
+ range: payload.range
121
+ });
122
+ return isTreeSitterRangeResult(result) ? result : void 0;
123
+ }
124
+ select(payload) {
125
+ return this.trackRuntimeTask(payload.runtimeSessionId, this.finishSelect(payload));
126
+ }
127
+ async finishSelect(payload) {
128
+ if (!await this.ensureWorkerReady()) return void 0;
129
+ const result = await this.postRequest({
130
+ type: "selection",
131
+ ...payload
132
+ });
133
+ return isTreeSitterSelectionResult(result) ? result : void 0;
134
+ }
135
+ disposeDocument(runtimeSessionId) {
136
+ this.cancelRuntimeRequests(runtimeSessionId);
137
+ this.sourceChunkRetention.invalidateDocument(runtimeSessionId);
138
+ const precedingTasks = [...this.runtimeTasks.get(runtimeSessionId) ?? []];
139
+ const disposal = Promise.allSettled(precedingTasks).then(async () => {
140
+ this.sourceChunkRetention.invalidateDocument(runtimeSessionId);
141
+ if (!this.worker) return;
142
+ await this.postRequest({
143
+ type: "disposeDocument",
144
+ runtimeSessionId
145
+ }, false);
146
+ });
147
+ this.trackRuntimeTask(runtimeSessionId, disposal).catch(() => void 0);
148
+ }
149
+ async awaitRuntimeSessionIdle(runtimeSessionId) {
150
+ await this.awaitRuntimeTasks(runtimeSessionId);
151
+ if (!this.worker) return Promise.resolve();
152
+ await this.postRequest({
153
+ type: "runtimeBarrier",
154
+ runtimeSessionId
155
+ }, false);
156
+ }
157
+ async awaitIdleFence() {
158
+ await this.awaitClientTasks();
159
+ if (!this.worker) return Promise.resolve();
160
+ await this.postRequest({ type: "idleFence" }, false);
161
+ }
162
+ dispose() {
163
+ if (this.disposeTask) return this.disposeTask;
164
+ this.lifecycle = "disposing";
165
+ this.disposeTask = this.finishDispose();
166
+ return this.disposeTask;
167
+ }
168
+ async finishDispose() {
169
+ const handle = this.worker;
170
+ if (!handle) {
171
+ this.clearRetainedState("disposed");
172
+ return;
173
+ }
174
+ try {
175
+ await this.postRequest({ type: "dispose" }, false);
176
+ } finally {
177
+ handle.terminate();
178
+ if (this.worker === handle) this.worker = null;
179
+ this.clearRetainedState("disposed");
180
+ this.rejectPendingRequests(/* @__PURE__ */ new Error("Tree-sitter worker disposed"));
181
+ }
182
+ }
183
+ getWorker() {
184
+ if (this.lifecycle === "disposing" || this.lifecycle === "disposed") return null;
185
+ if (!supportsWorkers()) return null;
186
+ if (this.worker) return this.worker;
187
+ const handle = new Worker(new URL("../assets/treeSitter.worker-D1ozCaGZ.js", import.meta.url), { type: "module" });
188
+ handle.onmessage = (event) => this.handleWorkerMessage(event);
189
+ handle.onerror = (event) => this.handleWorkerError(handle, event);
190
+ this.worker = handle;
191
+ this.workerGeneration += 1;
192
+ this.lifecycle = "initializing";
193
+ this.lastError = null;
194
+ return handle;
195
+ }
196
+ async ensureWorkerReady() {
197
+ const handle = this.getWorker();
198
+ if (!handle) return null;
199
+ if (!this.initPromise) this.initPromise = this.postRequest({ type: "init" }).then(() => {
200
+ if (this.worker === handle) this.lifecycle = "ready";
201
+ });
202
+ await this.initPromise;
203
+ if (this.lifecycle === "disposing" || this.lifecycle === "disposed") return null;
204
+ if (this.worker !== handle) return null;
205
+ return handle;
206
+ }
207
+ postRequest(payload, createIfMissing = true) {
208
+ const handle = createIfMissing ? this.getWorker() : this.worker;
209
+ if (!handle) return Promise.resolve(void 0);
210
+ const id = this.nextRequestId;
211
+ this.nextRequestId += 1;
212
+ const request = {
213
+ id,
214
+ payload
215
+ };
216
+ markEditorWorkerRequest("tree-sitter", payload.type, runtimeSessionIdForPayload(payload));
217
+ return new Promise((resolve, reject) => {
218
+ this.pendingRequests.set(id, {
219
+ runtimeSessionId: runtimeSessionIdForPayload(payload),
220
+ cancellationFlag: cancellationFlagForPayload(payload),
221
+ payload,
222
+ sourceRequest: this.sourceRequestForPayload(payload),
223
+ resolve,
224
+ reject
225
+ });
226
+ try {
227
+ handle.postMessage(request);
228
+ } catch (error) {
229
+ this.pendingRequests.delete(id);
230
+ reject(workerRequestError(error));
231
+ }
232
+ });
233
+ }
234
+ postDocumentRequest(payload) {
235
+ return this.postRequest(this.withCancellation(this.cancelPreviousDocumentRequests(payload.runtimeSessionId), payload));
236
+ }
237
+ postRangeRequest(payload) {
238
+ return this.postRequest(this.withCancellation(this.cancelPreviousRangeRequests(payload.runtimeSessionId), payload));
239
+ }
240
+ cancelPreviousDocumentRequests(runtimeSessionId) {
241
+ const cancellationFlag = this.createCancellationFlag();
242
+ for (const pending of this.pendingRequests.values()) {
243
+ if (pending.runtimeSessionId !== runtimeSessionId) continue;
244
+ if (pending.cancellationFlag) Atomics.store(pending.cancellationFlag, 0, 1);
245
+ }
246
+ return cancellationFlag;
247
+ }
248
+ cancelPreviousRangeRequests(runtimeSessionId) {
249
+ const cancellationFlag = this.createCancellationFlag();
250
+ for (const pending of this.pendingRequests.values()) {
251
+ if (pending.runtimeSessionId !== runtimeSessionId) continue;
252
+ if (pending.payload.type !== "queryRange") continue;
253
+ if (pending.cancellationFlag) Atomics.store(pending.cancellationFlag, 0, 1);
254
+ }
255
+ return cancellationFlag;
256
+ }
257
+ cancelRuntimeRequests(runtimeSessionId) {
258
+ for (const pending of this.pendingRequests.values()) {
259
+ if (pending.runtimeSessionId !== runtimeSessionId) continue;
260
+ if (pending.cancellationFlag) Atomics.store(pending.cancellationFlag, 0, 1);
261
+ }
262
+ }
263
+ createCancellationFlag() {
264
+ if (!supportsSharedCancellation()) return null;
265
+ return new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));
266
+ }
267
+ withCancellation(cancellationFlag, payload) {
268
+ const generation = this.nextGeneration;
269
+ this.nextGeneration += 1;
270
+ if (!cancellationFlag) return {
271
+ ...payload,
272
+ generation
273
+ };
274
+ return {
275
+ ...payload,
276
+ generation,
277
+ cancellationBuffer: cancellationFlag.buffer
278
+ };
279
+ }
280
+ handleWorkerMessage(event) {
281
+ const response = event.data;
282
+ const pending = this.pendingRequests.get(response.id);
283
+ if (!pending) return;
284
+ this.pendingRequests.delete(response.id);
285
+ if (response.ok) {
286
+ this.sourceChunkRetention.markRequestSent(pending.sourceRequest);
287
+ pending.resolve(response.result);
288
+ return;
289
+ }
290
+ if (pending.runtimeSessionId && shouldInvalidateDocumentSourceState(response.error)) this.sourceChunkRetention.invalidateDocument(pending.runtimeSessionId);
291
+ pending.reject(new Error(response.error));
292
+ }
293
+ handleWorkerError(failedWorker, event) {
294
+ if (failedWorker !== this.worker) return;
295
+ const error = new Error(event.message || "Tree-sitter worker failed");
296
+ failedWorker.terminate();
297
+ this.worker = null;
298
+ this.lifecycle = "crashed";
299
+ this.lastError = error;
300
+ this.rejectPendingRequests(error);
301
+ this.clearRetainedState("crashed");
302
+ }
303
+ rejectPendingRequests(error) {
304
+ for (const request of this.pendingRequests.values()) request.reject(error);
305
+ this.pendingRequests.clear();
306
+ }
307
+ shouldRegisterLanguageWithWorker(language) {
308
+ return !sameLanguageRegistration(this.registeredLanguages.get(language.id), language);
309
+ }
310
+ unregisteredLanguages(languages) {
311
+ const nextLanguages = [];
312
+ const nextById = /* @__PURE__ */ new Map();
313
+ for (const language of languages) {
314
+ if (!this.shouldRegisterLanguageWithWorker(language)) continue;
315
+ if (sameLanguageRegistration(nextById.get(language.id), language)) continue;
316
+ nextById.set(language.id, language);
317
+ nextLanguages.push(language);
318
+ }
319
+ return nextLanguages;
320
+ }
321
+ createSourceDescriptor(documentId, snapshot) {
322
+ return this.sourceChunkRetention.createDescriptor(documentId, snapshot);
323
+ }
324
+ sourceRequestForPayload(payload) {
325
+ if (!("source" in payload)) return null;
326
+ return this.sourceChunkRetention.createRequest(payload.runtimeSessionId, payload.source);
327
+ }
328
+ trackClientTask(task) {
329
+ this.clientTasks.add(task);
330
+ task.finally(() => this.clientTasks.delete(task)).catch(() => void 0);
331
+ return task;
332
+ }
333
+ trackRuntimeTask(runtimeSessionId, task) {
334
+ const tasks = this.runtimeTasks.get(runtimeSessionId) ?? /* @__PURE__ */ new Set();
335
+ tasks.add(task);
336
+ this.runtimeTasks.set(runtimeSessionId, tasks);
337
+ this.trackClientTask(task);
338
+ task.finally(() => {
339
+ tasks.delete(task);
340
+ if (tasks.size === 0) this.runtimeTasks.delete(runtimeSessionId);
341
+ }).catch(() => void 0);
342
+ return task;
343
+ }
344
+ async awaitClientTasks() {
345
+ while (this.clientTasks.size > 0) await Promise.allSettled(this.clientTasks);
346
+ }
347
+ async awaitRuntimeTasks(runtimeSessionId) {
348
+ while (this.runtimeTasks.has(runtimeSessionId)) {
349
+ const tasks = this.runtimeTasks.get(runtimeSessionId);
350
+ if (!tasks) return;
351
+ await Promise.allSettled(tasks);
352
+ }
353
+ }
354
+ clearRetainedState(lifecycle) {
355
+ this.lifecycle = lifecycle;
356
+ this.initPromise = null;
357
+ this.registeredLanguages.clear();
358
+ this.warmedLanguages.clear();
359
+ this.sourceChunkRetention.clear();
360
+ }
361
+ };
362
+ var createTreeSitterWorkerBackend = () => new TreeSitterWorkerClient();
363
+ var languageSignatures = /* @__PURE__ */ new WeakMap();
364
+ function sameLanguageRegistration(registered, language) {
365
+ if (!registered) return false;
366
+ if (registered === language) return true;
367
+ if (registered.wasmUrl !== language.wasmUrl) return false;
368
+ return languageDescriptorSignature(registered) === languageDescriptorSignature(language);
369
+ }
370
+ function languageDescriptorSignature(language) {
371
+ const cached = languageSignatures.get(language);
372
+ if (cached !== void 0) return cached;
373
+ const signature = JSON.stringify({
374
+ aliases: sortedItems(language.aliases),
375
+ extensions: sortedItems(language.extensions),
376
+ foldQuerySource: language.foldQuerySource,
377
+ highlightQuerySource: language.highlightQuerySource,
378
+ id: language.id,
379
+ injectionQuerySource: language.injectionQuerySource
380
+ });
381
+ languageSignatures.set(language, signature);
382
+ return signature;
383
+ }
384
+ function sortedItems(items) {
385
+ return items.toSorted();
386
+ }
387
+ var runtimeSessionIdForPayload = (payload) => {
388
+ if ("runtimeSessionId" in payload) return payload.runtimeSessionId;
389
+ return null;
390
+ };
391
+ var cancellationFlagForPayload = (payload) => {
392
+ if (!("cancellationBuffer" in payload)) return null;
393
+ if (!payload.cancellationBuffer) return null;
394
+ return new Int32Array(payload.cancellationBuffer);
395
+ };
396
+ var shouldInvalidateDocumentSourceState = (error) => {
397
+ if (error.includes("Tree-sitter source chunk")) return true;
398
+ if (error.includes("Tree-sitter resolve source failed")) return true;
399
+ return error.includes("Tree-sitter cache miss");
400
+ };
401
+ var workerRequestError = (error) => {
402
+ if (error instanceof Error) return error;
403
+ return new Error(String(error));
404
+ };
405
+ function markEditorWorkerRequest(family, type, runtimeSessionId) {
406
+ if (!globalThis.__editorPerfTrace) return;
407
+ globalThis.performance?.mark("editor.worker.request", { detail: {
408
+ family,
409
+ runtimeSessionId,
410
+ type
411
+ } });
412
+ }
413
+ var isTreeSitterParseResult = (result) => Boolean(result && "captures" in result && "folds" in result);
414
+ var isTreeSitterParseAckResult = (result) => Boolean(result && "status" in result && result.status === "parsed");
415
+ var isTreeSitterRangeResult = (result) => Boolean(result && "range" in result && "tokens" in result);
416
+ var isTreeSitterSelectionResult = (result) => Boolean(result && "status" in result && "ranges" in result);
417
+ //#endregion
418
+ export { TreeSitterWorkerClient, canUseTreeSitterWorker, createTreeSitterWorkerBackend };
419
+
420
+ //# sourceMappingURL=workerClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workerClient.js","names":["import.meta.ROLLDOWN_FILE_URL_48ysLV0565Jl7xxYwgqBwg","traceGlobal"],"sources":["../../src/treeSitter/workerClient.ts"],"sourcesContent":["import type { TreeSitterLanguageDescriptor } from './registry'\nimport {\n TreeSitterSourceChunkRetention,\n type TreeSitterSourceChunkRequest,\n type TreeSitterSourceChunkRetentionSnapshot,\n} from './sourceChunkRetention'\nimport type {\n TreeSitterEditRequest,\n TreeSitterLanguageId,\n TreeSitterParseAckResult,\n TreeSitterParseRequest,\n TreeSitterParseResult,\n TreeSitterRangeRequest,\n TreeSitterRangeResult,\n TreeSitterSelectionRequest,\n TreeSitterSelectionResult,\n TreeSitterSyntaxRange,\n TreeSitterWorkerRequest,\n TreeSitterWorkerRequestPayload,\n TreeSitterWorkerResponse,\n TreeSitterWorkerResult,\n} from './types'\nimport type { PieceTableSnapshot } from '@singapore-editor/core/document'\n\ntype PendingRequest = {\n readonly runtimeSessionId: string | null\n readonly cancellationFlag: Int32Array | null\n readonly payload: TreeSitterWorkerRequestPayload\n readonly sourceRequest: TreeSitterSourceChunkRequest | null\n readonly resolve: (result: TreeSitterWorkerResult) => void\n readonly reject: (error: Error) => void\n}\n\ntype TreeSitterParseDocumentRequest = Omit<\n TreeSitterParseRequest,\n 'generation' | 'cancellationBuffer'\n>\ntype TreeSitterEditDocumentRequest = Omit<\n TreeSitterEditRequest,\n 'generation' | 'cancellationBuffer'\n>\ntype TreeSitterRangeDocumentRequest = Omit<\n TreeSitterRangeRequest,\n 'generation' | 'cancellationBuffer'\n>\n\nexport type TreeSitterParsePayload = {\n readonly documentId: string\n readonly runtimeSessionId: string\n readonly snapshotVersion: number\n readonly languageId: TreeSitterLanguageId\n readonly includeHighlights?: boolean\n readonly includeCaptures?: boolean\n readonly resultMode?: 'full'\n readonly snapshot: PieceTableSnapshot\n}\nexport type TreeSitterParseOnlyPayload = Omit<TreeSitterParsePayload, 'resultMode'> & {\n readonly resultMode: 'parseOnly'\n}\nexport type TreeSitterBackendParsePayload = TreeSitterParsePayload | TreeSitterParseOnlyPayload\n\nexport type TreeSitterEditPayload = {\n readonly documentId: string\n readonly runtimeSessionId: string\n readonly previousSnapshotVersion: number\n readonly snapshotVersion: number\n readonly languageId: TreeSitterLanguageId\n readonly includeHighlights: boolean\n readonly includeCaptures?: boolean\n readonly resultMode?: 'full'\n readonly snapshot: PieceTableSnapshot\n readonly edits: readonly TreeSitterEditRequest['edits'][number][]\n readonly inputEdits: readonly TreeSitterEditRequest['inputEdits'][number][]\n}\nexport type TreeSitterEditOnlyPayload = Omit<TreeSitterEditPayload, 'resultMode'> & {\n readonly resultMode: 'parseOnly'\n}\nexport type TreeSitterBackendEditPayload = TreeSitterEditPayload | TreeSitterEditOnlyPayload\nexport type TreeSitterRangePayload = {\n readonly documentId: string\n readonly runtimeSessionId: string\n readonly snapshotVersion: number\n readonly languageId: TreeSitterLanguageId\n readonly includeHighlights?: boolean\n readonly includeCaptures?: boolean\n readonly range: TreeSitterSyntaxRange\n}\nexport type TreeSitterSelectionPayload = Omit<TreeSitterSelectionRequest, 'type'>\n\nexport type TreeSitterWorkerLifecycleState =\n | 'idle'\n | 'initializing'\n | 'ready'\n | 'disposing'\n | 'disposed'\n | 'crashed'\n\nexport type TreeSitterWorkerCacheSnapshot = {\n readonly registeredLanguages: number\n readonly sourceChunks: TreeSitterSourceChunkRetentionSnapshot\n}\n\nexport type TreeSitterWorkerOwnerSnapshot = {\n readonly lifecycle: TreeSitterWorkerLifecycleState\n readonly pendingRequests: number\n readonly workerGeneration: number\n readonly cache: TreeSitterWorkerCacheSnapshot\n readonly lastError: string | null\n}\n\nexport type TreeSitterBackend = {\n registerLanguages(languages: readonly TreeSitterLanguageDescriptor[]): Promise<void>\n /** Starts the worker, then registers and compiles `languages` ahead of their first document. */\n warmLanguages?(languages: readonly TreeSitterLanguageDescriptor[]): Promise<void>\n parse(\n payload: TreeSitterBackendParsePayload,\n ): Promise<TreeSitterParseResult | TreeSitterParseAckResult | undefined>\n edit(\n payload: TreeSitterBackendEditPayload,\n ): Promise<TreeSitterParseResult | TreeSitterParseAckResult | undefined>\n queryRange?(payload: TreeSitterRangePayload): Promise<TreeSitterRangeResult | undefined>\n select(payload: TreeSitterSelectionPayload): Promise<TreeSitterSelectionResult | undefined>\n disposeDocument(runtimeSessionId: string): void\n awaitRuntimeSessionIdle?(runtimeSessionId: string): Promise<void>\n awaitIdleFence?(): Promise<void>\n dispose?(): Promise<void>\n}\n\nconst supportsWorkers = (): boolean => typeof Worker !== 'undefined'\nconst supportsSharedCancellation = (): boolean => typeof SharedArrayBuffer !== 'undefined'\n\nexport const canUseTreeSitterWorker = (): boolean => supportsWorkers()\n\nexport class TreeSitterWorkerClient implements TreeSitterBackend {\n private worker: Worker | null = null\n private disposeTask: Promise<void> | null = null\n private nextRequestId = 1\n private nextGeneration = 1\n private workerGeneration = 0\n private lifecycle: TreeSitterWorkerLifecycleState = 'idle'\n private lastError: Error | null = null\n private initPromise: Promise<void> | null = null\n private readonly pendingRequests = new Map<number, PendingRequest>()\n private readonly clientTasks = new Set<Promise<unknown>>()\n private readonly runtimeTasks = new Map<string, Set<Promise<unknown>>>()\n private readonly sourceChunkRetention = new TreeSitterSourceChunkRetention()\n private readonly registeredLanguages = new Map<\n TreeSitterLanguageId,\n TreeSitterLanguageDescriptor\n >()\n private readonly warmedLanguages = new Set<TreeSitterLanguageId>()\n\n public inspect(): TreeSitterWorkerOwnerSnapshot {\n return {\n lifecycle: this.lifecycle,\n pendingRequests: this.pendingRequests.size,\n workerGeneration: this.workerGeneration,\n cache: {\n registeredLanguages: this.registeredLanguages.size,\n sourceChunks: this.sourceChunkRetention.inspect(),\n },\n lastError: this.lastError?.message ?? null,\n }\n }\n\n public registerLanguages(languages: readonly TreeSitterLanguageDescriptor[]): Promise<void> {\n return this.trackClientTask(this.finishRegisterLanguages(languages))\n }\n\n private async finishRegisterLanguages(\n languages: readonly TreeSitterLanguageDescriptor[],\n ): Promise<void> {\n const nextLanguages = this.unregisteredLanguages(languages)\n if (nextLanguages.length === 0) return\n\n const handle = await this.ensureWorkerReady()\n if (!handle) return\n\n await this.postRequest({ type: 'registerLanguages', languages: nextLanguages })\n for (const language of nextLanguages) {\n this.registeredLanguages.set(language.id, language)\n // A changed registration drops the worker's compiled runtime for that id.\n this.warmedLanguages.delete(language.id)\n }\n }\n\n public warmLanguages(languages: readonly TreeSitterLanguageDescriptor[]): Promise<void> {\n return this.trackClientTask(this.finishWarmLanguages(languages))\n }\n\n private async finishWarmLanguages(\n languages: readonly TreeSitterLanguageDescriptor[],\n ): Promise<void> {\n const handle = await this.ensureWorkerReady()\n if (!handle) return\n\n await this.finishRegisterLanguages(languages)\n const languageIds = [...new Set(languages.map((language) => language.id))].filter(\n (languageId) => !this.warmedLanguages.has(languageId),\n )\n if (languageIds.length === 0) return\n\n for (const languageId of languageIds) this.warmedLanguages.add(languageId)\n await this.postRequest({ type: 'warmLanguages', languageIds })\n }\n\n public parse(\n payload: TreeSitterParseOnlyPayload,\n ): Promise<TreeSitterParseResult | TreeSitterParseAckResult | undefined>\n public parse(payload: TreeSitterParsePayload): Promise<TreeSitterParseResult | undefined>\n public parse(\n payload: TreeSitterBackendParsePayload,\n ): Promise<TreeSitterParseResult | TreeSitterParseAckResult | undefined>\n public parse(\n payload: TreeSitterBackendParsePayload,\n ): Promise<TreeSitterParseResult | TreeSitterParseAckResult | undefined> {\n return this.trackRuntimeTask(payload.runtimeSessionId, this.finishParse(payload))\n }\n\n private async finishParse(\n payload: TreeSitterBackendParsePayload,\n ): Promise<TreeSitterParseResult | TreeSitterParseAckResult | undefined> {\n const handle = await this.ensureWorkerReady()\n if (!handle) return undefined\n const source = this.createSourceDescriptor(payload.runtimeSessionId, payload.snapshot)\n const request: TreeSitterParseDocumentRequest = {\n type: 'parse',\n documentId: payload.documentId,\n runtimeSessionId: payload.runtimeSessionId,\n snapshotVersion: payload.snapshotVersion,\n languageId: payload.languageId,\n includeHighlights: payload.includeHighlights ?? true,\n includeCaptures: payload.includeCaptures,\n resultMode: payload.resultMode,\n source,\n }\n const result = await this.postDocumentRequest(request)\n if (isTreeSitterParseResult(result)) return result\n if (isTreeSitterParseAckResult(result)) return result\n return undefined\n }\n\n public edit(\n payload: TreeSitterEditOnlyPayload,\n ): Promise<TreeSitterParseResult | TreeSitterParseAckResult | undefined>\n public edit(payload: TreeSitterEditPayload): Promise<TreeSitterParseResult | undefined>\n public edit(\n payload: TreeSitterBackendEditPayload,\n ): Promise<TreeSitterParseResult | TreeSitterParseAckResult | undefined>\n public edit(\n payload: TreeSitterBackendEditPayload,\n ): Promise<TreeSitterParseResult | TreeSitterParseAckResult | undefined> {\n return this.trackRuntimeTask(payload.runtimeSessionId, this.finishEdit(payload))\n }\n\n private async finishEdit(\n payload: TreeSitterBackendEditPayload,\n ): Promise<TreeSitterParseResult | TreeSitterParseAckResult | undefined> {\n const handle = await this.ensureWorkerReady()\n if (!handle) return undefined\n const source = this.createSourceDescriptor(payload.runtimeSessionId, payload.snapshot)\n const result = await this.postDocumentRequest({\n type: 'edit',\n documentId: payload.documentId,\n runtimeSessionId: payload.runtimeSessionId,\n previousSnapshotVersion: payload.previousSnapshotVersion,\n snapshotVersion: payload.snapshotVersion,\n languageId: payload.languageId,\n includeHighlights: payload.includeHighlights,\n includeCaptures: payload.includeCaptures,\n resultMode: payload.resultMode,\n source,\n edits: payload.edits,\n inputEdits: payload.inputEdits,\n })\n if (isTreeSitterParseResult(result)) return result\n if (isTreeSitterParseAckResult(result)) return result\n return undefined\n }\n\n public queryRange(payload: TreeSitterRangePayload): Promise<TreeSitterRangeResult | undefined> {\n return this.trackRuntimeTask(payload.runtimeSessionId, this.finishQueryRange(payload))\n }\n\n private async finishQueryRange(\n payload: TreeSitterRangePayload,\n ): Promise<TreeSitterRangeResult | undefined> {\n const handle = await this.ensureWorkerReady()\n if (!handle) return undefined\n const result = await this.postRangeRequest({\n type: 'queryRange',\n documentId: payload.documentId,\n runtimeSessionId: payload.runtimeSessionId,\n snapshotVersion: payload.snapshotVersion,\n languageId: payload.languageId,\n includeHighlights: payload.includeHighlights ?? true,\n includeCaptures: payload.includeCaptures,\n range: payload.range,\n })\n return isTreeSitterRangeResult(result) ? result : undefined\n }\n\n public select(\n payload: TreeSitterSelectionPayload,\n ): Promise<TreeSitterSelectionResult | undefined> {\n return this.trackRuntimeTask(payload.runtimeSessionId, this.finishSelect(payload))\n }\n\n private async finishSelect(\n payload: TreeSitterSelectionPayload,\n ): Promise<TreeSitterSelectionResult | undefined> {\n const handle = await this.ensureWorkerReady()\n if (!handle) return undefined\n const result = await this.postRequest({ type: 'selection', ...payload })\n return isTreeSitterSelectionResult(result) ? result : undefined\n }\n\n public disposeDocument(runtimeSessionId: string): void {\n this.cancelRuntimeRequests(runtimeSessionId)\n this.sourceChunkRetention.invalidateDocument(runtimeSessionId)\n const precedingTasks = [...(this.runtimeTasks.get(runtimeSessionId) ?? [])]\n const disposal = Promise.allSettled(precedingTasks).then(async () => {\n this.sourceChunkRetention.invalidateDocument(runtimeSessionId)\n if (!this.worker) return\n\n await this.postRequest({ type: 'disposeDocument', runtimeSessionId }, false)\n })\n void this.trackRuntimeTask(runtimeSessionId, disposal).catch(() => undefined)\n }\n\n public async awaitRuntimeSessionIdle(runtimeSessionId: string): Promise<void> {\n await this.awaitRuntimeTasks(runtimeSessionId)\n if (!this.worker) return Promise.resolve()\n\n await this.postRequest({ type: 'runtimeBarrier', runtimeSessionId }, false)\n }\n\n public async awaitIdleFence(): Promise<void> {\n await this.awaitClientTasks()\n if (!this.worker) return Promise.resolve()\n\n await this.postRequest({ type: 'idleFence' }, false)\n }\n\n public dispose(): Promise<void> {\n if (this.disposeTask) return this.disposeTask\n\n this.lifecycle = 'disposing'\n this.disposeTask = this.finishDispose()\n return this.disposeTask\n }\n\n private async finishDispose(): Promise<void> {\n const handle = this.worker\n if (!handle) {\n this.clearRetainedState('disposed')\n return\n }\n try {\n await this.postRequest({ type: 'dispose' }, false)\n } finally {\n handle.terminate()\n if (this.worker === handle) this.worker = null\n this.clearRetainedState('disposed')\n this.rejectPendingRequests(new Error('Tree-sitter worker disposed'))\n }\n }\n\n private getWorker(): Worker | null {\n if (this.lifecycle === 'disposing' || this.lifecycle === 'disposed') return null\n if (!supportsWorkers()) return null\n if (this.worker) return this.worker\n\n const handle = new Worker(new URL('./treeSitter.worker.ts', import.meta.url), {\n type: 'module',\n })\n handle.onmessage = (event) => this.handleWorkerMessage(event)\n handle.onerror = (event) => this.handleWorkerError(handle, event)\n this.worker = handle\n this.workerGeneration += 1\n this.lifecycle = 'initializing'\n this.lastError = null\n return handle\n }\n\n private async ensureWorkerReady(): Promise<Worker | null> {\n const handle = this.getWorker()\n if (!handle) return null\n\n if (!this.initPromise) {\n this.initPromise = this.postRequest({ type: 'init' }).then(() => {\n if (this.worker === handle) this.lifecycle = 'ready'\n })\n }\n\n await this.initPromise\n if (this.lifecycle === 'disposing' || this.lifecycle === 'disposed') return null\n if (this.worker !== handle) return null\n return handle\n }\n\n private postRequest(\n payload: TreeSitterWorkerRequestPayload,\n createIfMissing = true,\n ): Promise<TreeSitterWorkerResult> {\n const handle = createIfMissing ? this.getWorker() : this.worker\n if (!handle) return Promise.resolve(undefined)\n\n const id = this.nextRequestId\n this.nextRequestId += 1\n const request: TreeSitterWorkerRequest = { id, payload }\n markEditorWorkerRequest('tree-sitter', payload.type, runtimeSessionIdForPayload(payload))\n\n return new Promise((resolve, reject) => {\n this.pendingRequests.set(id, {\n runtimeSessionId: runtimeSessionIdForPayload(payload),\n cancellationFlag: cancellationFlagForPayload(payload),\n payload,\n sourceRequest: this.sourceRequestForPayload(payload),\n resolve,\n reject,\n })\n try {\n handle.postMessage(request)\n } catch (error) {\n this.pendingRequests.delete(id)\n reject(workerRequestError(error))\n }\n })\n }\n\n private postDocumentRequest(\n payload: TreeSitterParseDocumentRequest | TreeSitterEditDocumentRequest,\n ): Promise<TreeSitterWorkerResult> {\n return this.postRequest(\n this.withCancellation(this.cancelPreviousDocumentRequests(payload.runtimeSessionId), payload),\n )\n }\n\n private postRangeRequest(\n payload: TreeSitterRangeDocumentRequest,\n ): Promise<TreeSitterWorkerResult> {\n return this.postRequest(\n this.withCancellation(this.cancelPreviousRangeRequests(payload.runtimeSessionId), payload),\n )\n }\n\n private cancelPreviousDocumentRequests(runtimeSessionId: string): Int32Array | null {\n const cancellationFlag = this.createCancellationFlag()\n for (const pending of this.pendingRequests.values()) {\n if (pending.runtimeSessionId !== runtimeSessionId) continue\n if (pending.cancellationFlag) Atomics.store(pending.cancellationFlag, 0, 1)\n }\n\n return cancellationFlag\n }\n\n private cancelPreviousRangeRequests(runtimeSessionId: string): Int32Array | null {\n const cancellationFlag = this.createCancellationFlag()\n for (const pending of this.pendingRequests.values()) {\n if (pending.runtimeSessionId !== runtimeSessionId) continue\n if (pending.payload.type !== 'queryRange') continue\n if (pending.cancellationFlag) Atomics.store(pending.cancellationFlag, 0, 1)\n }\n\n return cancellationFlag\n }\n\n private cancelRuntimeRequests(runtimeSessionId: string): void {\n for (const pending of this.pendingRequests.values()) {\n if (pending.runtimeSessionId !== runtimeSessionId) continue\n if (pending.cancellationFlag) Atomics.store(pending.cancellationFlag, 0, 1)\n }\n }\n\n private createCancellationFlag(): Int32Array | null {\n if (!supportsSharedCancellation()) return null\n return new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT))\n }\n\n private withCancellation<\n TPayload extends\n | TreeSitterParseDocumentRequest\n | TreeSitterEditDocumentRequest\n | TreeSitterRangeDocumentRequest,\n >(\n cancellationFlag: Int32Array | null,\n payload: TPayload,\n ): TPayload & { readonly generation: number; readonly cancellationBuffer?: SharedArrayBuffer } {\n const generation = this.nextGeneration\n this.nextGeneration += 1\n if (!cancellationFlag) return { ...payload, generation }\n return {\n ...payload,\n generation,\n cancellationBuffer: cancellationFlag.buffer as SharedArrayBuffer,\n }\n }\n\n private handleWorkerMessage(event: MessageEvent<TreeSitterWorkerResponse>): void {\n const response = event.data\n const pending = this.pendingRequests.get(response.id)\n if (!pending) return\n\n this.pendingRequests.delete(response.id)\n if (response.ok) {\n this.sourceChunkRetention.markRequestSent(pending.sourceRequest)\n pending.resolve(response.result)\n return\n }\n\n if (pending.runtimeSessionId && shouldInvalidateDocumentSourceState(response.error)) {\n this.sourceChunkRetention.invalidateDocument(pending.runtimeSessionId)\n }\n pending.reject(new Error(response.error))\n }\n\n private handleWorkerError(failedWorker: Worker, event: ErrorEvent): void {\n if (failedWorker !== this.worker) return\n\n const error = new Error(event.message || 'Tree-sitter worker failed')\n failedWorker.terminate()\n this.worker = null\n this.lifecycle = 'crashed'\n this.lastError = error\n this.rejectPendingRequests(error)\n this.clearRetainedState('crashed')\n }\n\n private rejectPendingRequests(error: Error): void {\n for (const request of this.pendingRequests.values()) request.reject(error)\n this.pendingRequests.clear()\n }\n\n private shouldRegisterLanguageWithWorker(language: TreeSitterLanguageDescriptor): boolean {\n return !sameLanguageRegistration(this.registeredLanguages.get(language.id), language)\n }\n\n private unregisteredLanguages(\n languages: readonly TreeSitterLanguageDescriptor[],\n ): readonly TreeSitterLanguageDescriptor[] {\n const nextLanguages: TreeSitterLanguageDescriptor[] = []\n const nextById = new Map<TreeSitterLanguageId, TreeSitterLanguageDescriptor>()\n\n for (const language of languages) {\n if (!this.shouldRegisterLanguageWithWorker(language)) continue\n if (sameLanguageRegistration(nextById.get(language.id), language)) continue\n\n nextById.set(language.id, language)\n nextLanguages.push(language)\n }\n\n return nextLanguages\n }\n\n private createSourceDescriptor(documentId: string, snapshot: PieceTableSnapshot) {\n return this.sourceChunkRetention.createDescriptor(documentId, snapshot)\n }\n\n private sourceRequestForPayload(\n payload: TreeSitterWorkerRequestPayload,\n ): TreeSitterSourceChunkRequest | null {\n if (!('source' in payload)) return null\n return this.sourceChunkRetention.createRequest(payload.runtimeSessionId, payload.source)\n }\n\n private trackClientTask<T>(task: Promise<T>): Promise<T> {\n this.clientTasks.add(task)\n void task.finally(() => this.clientTasks.delete(task)).catch(() => undefined)\n return task\n }\n\n private trackRuntimeTask<T>(runtimeSessionId: string, task: Promise<T>): Promise<T> {\n const tasks = this.runtimeTasks.get(runtimeSessionId) ?? new Set<Promise<unknown>>()\n tasks.add(task)\n this.runtimeTasks.set(runtimeSessionId, tasks)\n this.trackClientTask(task)\n void task\n .finally(() => {\n tasks.delete(task)\n if (tasks.size === 0) this.runtimeTasks.delete(runtimeSessionId)\n })\n .catch(() => undefined)\n return task\n }\n\n private async awaitClientTasks(): Promise<void> {\n while (this.clientTasks.size > 0) {\n await Promise.allSettled(this.clientTasks)\n }\n }\n\n private async awaitRuntimeTasks(runtimeSessionId: string): Promise<void> {\n while (this.runtimeTasks.has(runtimeSessionId)) {\n const tasks = this.runtimeTasks.get(runtimeSessionId)\n if (!tasks) return\n\n await Promise.allSettled(tasks)\n }\n }\n\n private clearRetainedState(lifecycle: TreeSitterWorkerLifecycleState): void {\n this.lifecycle = lifecycle\n this.initPromise = null\n this.registeredLanguages.clear()\n this.warmedLanguages.clear()\n this.sourceChunkRetention.clear()\n }\n}\n\nexport const createTreeSitterWorkerBackend = (): TreeSitterBackend => new TreeSitterWorkerClient()\n\n// `wasmUrl` can be the grammar as a multi-megabyte data URL: it is compared by value, never\n// serialised, and each descriptor's signature is computed once.\nconst languageSignatures = new WeakMap<TreeSitterLanguageDescriptor, string>()\n\nfunction sameLanguageRegistration(\n registered: TreeSitterLanguageDescriptor | undefined,\n language: TreeSitterLanguageDescriptor,\n): boolean {\n if (!registered) return false\n if (registered === language) return true\n if (registered.wasmUrl !== language.wasmUrl) return false\n return languageDescriptorSignature(registered) === languageDescriptorSignature(language)\n}\n\nfunction languageDescriptorSignature(language: TreeSitterLanguageDescriptor): string {\n const cached = languageSignatures.get(language)\n if (cached !== undefined) return cached\n\n const signature = JSON.stringify({\n aliases: sortedItems(language.aliases),\n extensions: sortedItems(language.extensions),\n foldQuerySource: language.foldQuerySource,\n highlightQuerySource: language.highlightQuerySource,\n id: language.id,\n injectionQuerySource: language.injectionQuerySource,\n })\n languageSignatures.set(language, signature)\n return signature\n}\n\nfunction sortedItems(items: readonly string[]): readonly string[] {\n return items.toSorted()\n}\n\nconst runtimeSessionIdForPayload = (payload: TreeSitterWorkerRequestPayload): string | null => {\n if ('runtimeSessionId' in payload) return payload.runtimeSessionId\n return null\n}\n\nconst cancellationFlagForPayload = (payload: TreeSitterWorkerRequestPayload): Int32Array | null => {\n if (!('cancellationBuffer' in payload)) return null\n if (!payload.cancellationBuffer) return null\n return new Int32Array(payload.cancellationBuffer)\n}\n\nconst shouldInvalidateDocumentSourceState = (error: string): boolean => {\n if (error.includes('Tree-sitter source chunk')) return true\n if (error.includes('Tree-sitter resolve source failed')) return true\n return error.includes('Tree-sitter cache miss')\n}\n\nconst workerRequestError = (error: unknown): Error => {\n if (error instanceof Error) return error\n return new Error(String(error))\n}\n\nfunction markEditorWorkerRequest(\n family: string,\n type: string,\n runtimeSessionId: string | null,\n): void {\n const traceGlobal = globalThis as typeof globalThis & { readonly __editorPerfTrace?: unknown }\n if (!traceGlobal.__editorPerfTrace) return\n\n globalThis.performance?.mark('editor.worker.request', {\n detail: { family, runtimeSessionId, type },\n })\n}\n\nconst isTreeSitterParseResult = (result: TreeSitterWorkerResult): result is TreeSitterParseResult =>\n Boolean(result && 'captures' in result && 'folds' in result)\n\nconst isTreeSitterParseAckResult = (\n result: TreeSitterWorkerResult,\n): result is TreeSitterParseAckResult =>\n Boolean(result && 'status' in result && result.status === 'parsed')\n\nconst isTreeSitterRangeResult = (result: TreeSitterWorkerResult): result is TreeSitterRangeResult =>\n Boolean(result && 'range' in result && 'tokens' in result)\n\nconst isTreeSitterSelectionResult = (\n result: TreeSitterWorkerResult,\n): result is TreeSitterSelectionResult =>\n Boolean(result && 'status' in result && 'ranges' in result)\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@singapore-editor/tree-sitter",
3
+ "version": "0.1.1",
4
+ "files": [
5
+ "README.md",
6
+ "dist"
7
+ ],
8
+ "type": "module",
9
+ "sideEffects": false,
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js",
14
+ "default": "./dist/index.js"
15
+ }
16
+ },
17
+ "publishConfig": {
18
+ "access": "public",
19
+ "registry": "https://registry.npmjs.org/"
20
+ },
21
+ "scripts": {
22
+ "build": "bun ../../scripts/build-package.ts",
23
+ "bench:syntax": "bun bench/treeSitter-syntax.ts",
24
+ "test": "vitest run --exclude '**/*.browser.test.ts' && bun run test:browser",
25
+ "test:browser": "vitest run --browser.enabled --browser.headless test/treeSitter-workerClient.browser.test.ts test/native-coverage.browser.test.ts test/markdown.browser.test.ts",
26
+ "typecheck": "tsgo --noEmit",
27
+ "lint": "oxlint .",
28
+ "format": "oxfmt --write .",
29
+ "format:check": "oxfmt --check ."
30
+ },
31
+ "dependencies": {
32
+ "@singapore-editor/core": "0.1.2",
33
+ "tree-sitter-md": "0.1.0",
34
+ "web-tree-sitter": "github:ShaulLavo/tree-sitter-x#e2985e0"
35
+ },
36
+ "devDependencies": {
37
+ "@playwright/test": "^1.63.0",
38
+ "@types/node": "^26.6.3",
39
+ "@typescript/native-preview": "7.0.0-dev.20260707.2",
40
+ "@vitest/browser-playwright": "^5.0.2",
41
+ "happy-dom": "^20.14.5",
42
+ "oxfmt": "0.70.0",
43
+ "oxlint": "1.85.0",
44
+ "typescript": "~6.0.3",
45
+ "vitest": "^5.0.2"
46
+ },
47
+ "peerDependencies": {
48
+ "@singapore-editor/core": "0.1.2"
49
+ }
50
+ }