Skip to content

Commit bee23bb

Browse files
committed
feat: improve wasm support
1 parent 1127905 commit bee23bb

File tree

8 files changed

+159
-204
lines changed

8 files changed

+159
-204
lines changed

packages/shikiji-core/src/bundle-factory.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ export type GetHighlighterFactory<L extends string, T extends string> = (options
99
*
1010
* @param bundledLanguages
1111
* @param bundledThemes
12-
* @param ladWasm
12+
* @param loadWasm
1313
*/
1414
export function createdBundledHighlighter<BundledLangs extends string, BundledThemes extends string>(
1515
bundledLanguages: Record<BundledLangs, LanguageInput>,
1616
bundledThemes: Record<BundledThemes, ThemeInput>,
17-
ladWasm: HighlighterCoreOptions['loadWasm'],
17+
loadWasm: HighlighterCoreOptions['loadWasm'],
1818
): GetHighlighterFactory<BundledLangs, BundledThemes> {
1919
async function getHighlighter(options: BundledHighlighterOptions<BundledLangs, BundledThemes> = {}): Promise<HighlighterGeneric<BundledLangs, BundledThemes>> {
2020
function resolveLang(lang: LanguageInput | BundledLangs | SpecialLanguage): LanguageInput {
@@ -48,7 +48,7 @@ export function createdBundledHighlighter<BundledLangs extends string, BundledTh
4848
...options,
4949
themes: _themes,
5050
langs,
51-
loadWasm: ladWasm,
51+
loadWasm,
5252
})
5353

5454
return {

packages/shikiji-core/src/oniguruma/index.ts

+71-77
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*-------------------------------------------------------- */
44

55
import type { IOnigBinding, IOnigCaptureIndex, IOnigMatch, OnigScanner as IOnigScanner, OnigString as IOnigString, Pointer } from './types'
6-
import OnigasmModuleFactory from './onig'
6+
import createOnigasm from './onig'
77

88
export const enum FindOption {
99
None = 0,
@@ -29,7 +29,7 @@ let onigBinding: IOnigBinding | null = null
2929
let defaultDebugCall = false
3030

3131
function throwLastOnigError(onigBinding: IOnigBinding): void {
32-
throw new Error(onigBinding.UTF8ToString(onigBinding._getLastOnigError()))
32+
throw new Error(onigBinding.UTF8ToString(onigBinding.getLastOnigError()))
3333
}
3434

3535
class UtfString {
@@ -169,7 +169,7 @@ class UtfString {
169169
}
170170

171171
public createString(onigBinding: IOnigBinding): Pointer {
172-
const result = onigBinding._omalloc(this.utf8Length)
172+
const result = onigBinding.omalloc(this.utf8Length)
173173
onigBinding.HEAPU8.set(this.utf8Value, result)
174174
return result
175175
}
@@ -203,7 +203,7 @@ export class OnigString implements IOnigString {
203203

204204
if (this.utf8Length < 10000 && !OnigString._sharedPtrInUse) {
205205
if (!OnigString._sharedPtr)
206-
OnigString._sharedPtr = onigBinding._omalloc(10000)
206+
OnigString._sharedPtr = onigBinding.omalloc(10000)
207207

208208
OnigString._sharedPtrInUse = true
209209
onigBinding.HEAPU8.set(utfString.utf8Value, OnigString._sharedPtr)
@@ -245,7 +245,7 @@ export class OnigString implements IOnigString {
245245
OnigString._sharedPtrInUse = false
246246

247247
else
248-
this._onigBinding._ofree(this.ptr)
248+
this._onigBinding.ofree(this.ptr)
249249
}
250250
}
251251

@@ -264,19 +264,19 @@ export class OnigScanner implements IOnigScanner {
264264
strPtrsArr[i] = utfString.createString(onigBinding)
265265
strLenArr[i] = utfString.utf8Length
266266
}
267-
const strPtrsPtr = onigBinding._omalloc(4 * patterns.length)
267+
const strPtrsPtr = onigBinding.omalloc(4 * patterns.length)
268268
onigBinding.HEAPU32.set(strPtrsArr, strPtrsPtr / 4)
269269

270-
const strLenPtr = onigBinding._omalloc(4 * patterns.length)
270+
const strLenPtr = onigBinding.omalloc(4 * patterns.length)
271271
onigBinding.HEAPU32.set(strLenArr, strLenPtr / 4)
272272

273-
const scannerPtr = onigBinding._createOnigScanner(strPtrsPtr, strLenPtr, patterns.length)
273+
const scannerPtr = onigBinding.createOnigScanner(strPtrsPtr, strLenPtr, patterns.length)
274274

275275
for (let i = 0, len = patterns.length; i < len; i++)
276-
onigBinding._ofree(strPtrsArr[i])
276+
onigBinding.ofree(strPtrsArr[i])
277277

278-
onigBinding._ofree(strLenPtr)
279-
onigBinding._ofree(strPtrsPtr)
278+
onigBinding.ofree(strLenPtr)
279+
onigBinding.ofree(strPtrsPtr)
280280

281281
if (scannerPtr === 0)
282282
throwLastOnigError(onigBinding)
@@ -286,7 +286,7 @@ export class OnigScanner implements IOnigScanner {
286286
}
287287

288288
public dispose(): void {
289-
this._onigBinding._freeOnigScanner(this._ptr)
289+
this._onigBinding.freeOnigScanner(this._ptr)
290290
}
291291

292292
public findNextMatchSync(string: string | OnigString, startPosition: number, options: number): IOnigMatch | null
@@ -317,10 +317,10 @@ export class OnigScanner implements IOnigScanner {
317317
const onigBinding = this._onigBinding
318318
let resultPtr: Pointer
319319
if (debugCall)
320-
resultPtr = onigBinding._findNextOnigScannerMatchDbg(this._ptr, string.id, string.ptr, string.utf8Length, string.convertUtf16OffsetToUtf8(startPosition), options)
320+
resultPtr = onigBinding.findNextOnigScannerMatchDbg(this._ptr, string.id, string.ptr, string.utf8Length, string.convertUtf16OffsetToUtf8(startPosition), options)
321321

322322
else
323-
resultPtr = onigBinding._findNextOnigScannerMatch(this._ptr, string.id, string.ptr, string.utf8Length, string.convertUtf16OffsetToUtf8(startPosition), options)
323+
resultPtr = onigBinding.findNextOnigScannerMatch(this._ptr, string.id, string.ptr, string.utf8Length, string.convertUtf16OffsetToUtf8(startPosition), options)
324324

325325
if (resultPtr === 0) {
326326
// no match
@@ -348,94 +348,88 @@ export class OnigScanner implements IOnigScanner {
348348
}
349349

350350
export interface WebAssemblyInstantiator {
351-
(importObject: Record<string, Record<string, WebAssembly.ImportValue>> | undefined): Promise<WebAssembly.WebAssemblyInstantiatedSource | WebAssembly.Instance>
351+
(importObject: Record<string, Record<string, WebAssembly.ImportValue>> | undefined): Promise<WebAssemblyInstance>
352352
}
353353

354-
interface ICommonOptions {
355-
print?(str: string): void
356-
}
357-
interface IInstantiatorOptions extends ICommonOptions {
354+
export type WebAssemblyInstance = WebAssembly.WebAssemblyInstantiatedSource | WebAssembly.Instance | WebAssembly.Instance['exports']
355+
356+
interface IInstantiatorOptions {
358357
instantiator: WebAssemblyInstantiator
359358
}
360-
interface IDataOptions extends ICommonOptions {
359+
interface IDataOptions {
361360
data: ArrayBufferView | ArrayBuffer | Response
362361
}
363-
export type OnigurumaLoadOptions = IInstantiatorOptions | IDataOptions
364362

365-
async function _loadWasm(loader: WebAssemblyInstantiator, print: ((str: string) => void) | undefined): Promise<void> {
366-
onigBinding = await OnigasmModuleFactory({
367-
print,
368-
instantiateWasm: (importObject) => {
369-
if (typeof performance === 'undefined') {
370-
// performance.now() is not available in this environment, so use Date.now()
371-
const get_now = () => Date.now();
372-
(<any>importObject).env.emscripten_get_now = get_now;
373-
(<any>importObject).wasi_snapshot_preview1.emscripten_get_now = get_now
374-
}
375-
// @ts-expect-error Can be a instantiator, or a instance
376-
return loader(importObject).then(instantiatedSource => instantiatedSource.instance || instantiatedSource)
377-
},
378-
})
379-
}
363+
export type OnigurumaLoadOptions = IInstantiatorOptions | IDataOptions
380364

381-
function isInstantiatorOptionsObject(dataOrOptions: ArrayBufferView | ArrayBuffer | Response | OnigurumaLoadOptions): dataOrOptions is IInstantiatorOptions {
365+
function isInstantiatorOptionsObject(dataOrOptions: any): dataOrOptions is IInstantiatorOptions {
382366
return (typeof (<IInstantiatorOptions>dataOrOptions).instantiator === 'function')
383367
}
384368

385-
function isDataOptionsObject(dataOrOptions: ArrayBufferView | ArrayBuffer | Response | OnigurumaLoadOptions): dataOrOptions is IDataOptions {
369+
function isDataOptionsObject(dataOrOptions: any): dataOrOptions is IDataOptions {
386370
return (typeof (<IDataOptions>dataOrOptions).data !== 'undefined')
387371
}
388372

389-
function isResponse(dataOrOptions: ArrayBufferView | ArrayBuffer | Response | OnigurumaLoadOptions): dataOrOptions is Response {
373+
function isResponse(dataOrOptions: any): dataOrOptions is Response {
390374
return (typeof Response !== 'undefined' && dataOrOptions instanceof Response)
391375
}
392376

393-
let initCalled = false
377+
function isArrayBuffer(data: any): data is ArrayBuffer | ArrayBufferView {
378+
return (typeof ArrayBuffer !== 'undefined' && (data instanceof ArrayBuffer || ArrayBuffer.isView(data)))
379+
// eslint-disable-next-line node/prefer-global/buffer
380+
|| (typeof Buffer !== 'undefined' && Buffer.isBuffer(data))
381+
|| (typeof SharedArrayBuffer !== 'undefined' && data instanceof SharedArrayBuffer)
382+
|| (typeof Uint32Array !== 'undefined' && data instanceof Uint32Array)
383+
}
384+
394385
let initPromise: Promise<void> | null = null
395386

396-
export function loadWasm(loader: WebAssemblyInstantiator): Promise<void>
397-
export function loadWasm(options: OnigurumaLoadOptions): Promise<void>
398-
export function loadWasm(data: ArrayBufferView | ArrayBuffer | Response): Promise<void>
399-
export function loadWasm(dataOrOptions: WebAssemblyInstantiator | ArrayBufferView | ArrayBuffer | Response | OnigurumaLoadOptions): Promise<void> {
400-
if (initCalled) {
401-
// Already initialized
402-
return initPromise!
403-
}
404-
initCalled = true
387+
type Awaitable<T> = T | Promise<T>
405388

406-
let loader: WebAssemblyInstantiator
407-
let print: ((str: string) => void) | undefined
389+
export type LoadWasmOptions =
390+
| OnigurumaLoadOptions
391+
| WebAssemblyInstantiator
392+
| ArrayBufferView | ArrayBuffer | Response
408393

409-
if (typeof dataOrOptions === 'function') {
410-
loader = dataOrOptions
411-
}
412-
else if (isInstantiatorOptionsObject(dataOrOptions)) {
413-
loader = dataOrOptions.instantiator
414-
print = dataOrOptions.print
415-
}
416-
else {
417-
let data: ArrayBufferView | ArrayBuffer | Response
418-
if (isDataOptionsObject(dataOrOptions)) {
419-
data = dataOrOptions.data
420-
print = dataOrOptions.print
421-
}
422-
else {
423-
data = dataOrOptions
424-
}
394+
export async function loadWasm(options: LoadWasmOptions | (() => Awaitable<LoadWasmOptions>)): Promise<void> {
395+
if (initPromise)
396+
return initPromise
425397

426-
if (isResponse(data)) {
427-
if (typeof WebAssembly.instantiateStreaming === 'function')
428-
loader = _makeResponseStreamingLoader(data)
398+
async function _load() {
399+
onigBinding = await createOnigasm(async (info) => {
400+
let instance: LoadWasmOptions | (() => Awaitable<LoadWasmOptions>) | WebAssemblyInstance = options
401+
if (typeof instance === 'function')
402+
instance = await instance(info)
403+
if (typeof instance === 'function')
404+
instance = await instance(info)
429405

430-
else
431-
loader = _makeResponseNonStreamingLoader(data)
432-
}
433-
else {
434-
loader = _makeArrayBufferLoader(data)
435-
}
406+
if (isInstantiatorOptionsObject(instance)) {
407+
instance = await instance.instantiator(info)
408+
}
409+
else {
410+
if (isDataOptionsObject(instance))
411+
instance = instance.data
412+
413+
if (isResponse(instance)) {
414+
if (typeof WebAssembly.instantiateStreaming === 'function')
415+
instance = await _makeResponseStreamingLoader(instance)(info)
416+
else
417+
instance = await _makeResponseNonStreamingLoader(instance)(info)
418+
}
419+
else if (isArrayBuffer(instance)) {
420+
instance = await _makeArrayBufferLoader(instance)(info)
421+
}
422+
}
423+
424+
if ('instance' in instance)
425+
instance = (instance as WebAssembly.WebAssemblyInstantiatedSource).instance
426+
if ('exports' in instance)
427+
instance = (instance as WebAssembly.Instance).exports
428+
return instance
429+
})
436430
}
437431

438-
initPromise = _loadWasm(loader, print)
432+
initPromise = _load()
439433
return initPromise
440434
}
441435

packages/shikiji-core/src/oniguruma/onig.d.ts

-15
This file was deleted.

packages/shikiji-core/src/oniguruma/onig.js

-99
This file was deleted.

0 commit comments

Comments
 (0)