wasm-bindgen-lite 0.2.0 → 0.3.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wasm-bindgen-lite",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "type": "module",
5
5
  "description": "CLI tool to build Rust crates into minimal, SIMD-optimized WASM packages with JS loaders",
6
6
  "repository": {
package/src/cli/config.js CHANGED
@@ -19,6 +19,7 @@ const DEFAULT_CONFIG = {
19
19
  node: true,
20
20
  browser: true,
21
21
  inline: true,
22
+ types: true,
22
23
  },
23
24
  custom: null, // path to custom JS file to include and re-export
24
25
  },
@@ -63,13 +64,14 @@ function readCrateName(crateDir) {
63
64
  }
64
65
 
65
66
  function normalizeEmit(value) {
66
- if (!value) return { node: true, browser: true, inline: true }
67
+ if (!value) return { node: true, browser: true, inline: true, types: true }
67
68
  if (Array.isArray(value)) {
68
69
  const set = new Set(value)
69
70
  return {
70
71
  node: set.has('node'),
71
72
  browser: set.has('browser'),
72
73
  inline: set.has('inline'),
74
+ types: set.has('types') || !set.has('no-types'), // default to true if not specified
73
75
  }
74
76
  }
75
77
  if (typeof value === 'object') {
@@ -77,9 +79,10 @@ function normalizeEmit(value) {
77
79
  node: value.node !== false,
78
80
  browser: value.browser !== false,
79
81
  inline: value.inline !== false,
82
+ types: value.types !== false,
80
83
  }
81
84
  }
82
- return { node: true, browser: true, inline: true }
85
+ return { node: true, browser: true, inline: true, types: true }
83
86
  }
84
87
 
85
88
  function normalizeWasmOpt(input) {
package/src/cli/emit.js CHANGED
@@ -1,4 +1,4 @@
1
- import { readFileSync, writeFileSync, mkdirSync } from 'node:fs'
1
+ import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'
2
2
  import { join } from 'node:path'
3
3
  import { fileURLToPath } from 'node:url'
4
4
 
@@ -112,51 +112,55 @@ export function createCore({ exportsList, autoInit, stream }) {
112
112
  b.line('}')
113
113
  b.blank()
114
114
 
115
- b.line('function scalarSize(type) {')
116
- b.indent(() => {
117
- b.line('switch (type) {')
118
- b.line(' case "f64": return 8;')
119
- b.line(' case "f32":')
120
- b.line(' case "i32":')
121
- b.line(' case "u32": return 4;')
122
- b.line(' case "i16":')
123
- b.line(' case "u16": return 2;')
124
- b.line(' case "i8":')
125
- b.line(' case "u8": return 1;')
126
- b.line(' case "u32_array":')
127
- b.line(' case "i32_array":')
128
- b.line(' case "f32_array": return 1024 * 1024;')
129
- b.line(' default: return 0;')
115
+ const needsDecoders = wrappersIR.some((w) => w.returnType !== 'bytes')
116
+
117
+ if (needsDecoders) {
118
+ b.line('function scalarSize(type) {')
119
+ b.indent(() => {
120
+ b.line('switch (type) {')
121
+ b.line(' case "f64": return 8;')
122
+ b.line(' case "f32":')
123
+ b.line(' case "i32":')
124
+ b.line(' case "u32": return 4;')
125
+ b.line(' case "i16":')
126
+ b.line(' case "u16": return 2;')
127
+ b.line(' case "i8":')
128
+ b.line(' case "u8": return 1;')
129
+ b.line(' case "u32_array":')
130
+ b.line(' case "i32_array":')
131
+ b.line(' case "f32_array": return 1024 * 1024;')
132
+ b.line(' default: return 0;')
133
+ b.line('}')
134
+ })
130
135
  b.line('}')
131
- })
132
- b.line('}')
133
- b.blank()
136
+ b.blank()
134
137
 
135
- b.line('function decodeReturn(view, type) {')
136
- b.indent(() => {
137
- b.line('switch (type) {')
138
- b.line(' case "f32": return view.getFloat32(0, true);')
139
- b.line(' case "f64": return view.getFloat64(0, true);')
140
- b.line(' case "i32": return view.getInt32(0, true);')
141
- b.line(' case "u32": return view.getUint32(0, true);')
142
- b.line(' case "i16": return view.getInt16(0, true);')
143
- b.line(' case "u16": return view.getUint16(0, true);')
144
- b.line(' case "i8": return view.getInt8(0);')
145
- b.line(' case "u8": return view.getUint8(0);')
146
- b.line(
147
- ' case "u32_array": return new Uint32Array(view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength));'
148
- )
149
- b.line(
150
- ' case "i32_array": return new Int32Array(view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength));'
151
- )
152
- b.line(
153
- ' case "f32_array": return new Float32Array(view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength));'
154
- )
155
- b.line(' default: return null;')
138
+ b.line('function decodeReturn(view, type) {')
139
+ b.indent(() => {
140
+ b.line('switch (type) {')
141
+ b.line(' case "f32": return view.getFloat32(0, true);')
142
+ b.line(' case "f64": return view.getFloat64(0, true);')
143
+ b.line(' case "i32": return view.getInt32(0, true);')
144
+ b.line(' case "u32": return view.getUint32(0, true);')
145
+ b.line(' case "i16": return view.getInt16(0, true);')
146
+ b.line(' case "u16": return view.getUint16(0, true);')
147
+ b.line(' case "i8": return view.getInt8(0);')
148
+ b.line(' case "u8": return view.getUint8(0);')
149
+ b.line(
150
+ ' case "u32_array": return new Uint32Array(view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength));'
151
+ )
152
+ b.line(
153
+ ' case "i32_array": return new Int32Array(view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength));'
154
+ )
155
+ b.line(
156
+ ' case "f32_array": return new Float32Array(view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength));'
157
+ )
158
+ b.line(' default: return null;')
159
+ b.line('}')
160
+ })
156
161
  b.line('}')
157
- })
158
- b.line('}')
159
- b.blank()
162
+ b.blank()
163
+ }
160
164
 
161
165
  b.line('function callWasm(abi, input, outLen, reuse) {')
162
166
  b.indent(() => {
@@ -363,6 +367,62 @@ export function createCore({ exportsList, autoInit, stream }) {
363
367
  return b.toString()
364
368
  }
365
369
 
370
+ export function createCoreTypes({ exportsList, autoInit, stream }) {
371
+ const needsEnsure = autoInit === 'lazy'
372
+ const wrappersIR = buildWrapperIR(exportsList)
373
+ const b = code()
374
+
375
+ b.line('export type WasmInput = Uint8Array | ArrayBufferView | ArrayBuffer;')
376
+ b.blank()
377
+
378
+ b.line('export function setInstance(instance: WebAssembly.Instance): void;')
379
+ b.line('export function wasmExports(): WebAssembly.Exports;')
380
+ b.line('export function memoryU8(): Uint8Array;')
381
+ b.line('export function alloc(len: number): number;')
382
+ b.line('export function free(ptr: number, len: number): void;')
383
+ b.blank()
384
+
385
+ wrappersIR.forEach((w) => {
386
+ let tsRetType
387
+ switch (w.returnType) {
388
+ case 'f32':
389
+ case 'f64':
390
+ case 'i32':
391
+ case 'u32':
392
+ case 'i16':
393
+ case 'u16':
394
+ case 'i8':
395
+ case 'u8':
396
+ tsRetType = 'number'
397
+ break
398
+ case 'u32_array':
399
+ tsRetType = 'Uint32Array'
400
+ break
401
+ case 'i32_array':
402
+ tsRetType = 'Int32Array'
403
+ break
404
+ case 'f32_array':
405
+ tsRetType = 'Float32Array'
406
+ break
407
+ case 'bytes':
408
+ default:
409
+ tsRetType = 'Uint8Array'
410
+ }
411
+
412
+ const ret = needsEnsure ? `Promise<${tsRetType}>` : tsRetType
413
+ b.line(`export function ${w.fnName}(input: WasmInput): ${ret};`)
414
+ })
415
+
416
+ if (stream?.enable) {
417
+ b.blank()
418
+ b.line(
419
+ 'export function createTransformStream(fnName?: string): TransformStream<WasmInput, Uint8Array>;'
420
+ )
421
+ }
422
+
423
+ return b.toString()
424
+ }
425
+
366
426
  export function code() {
367
427
  const lines = []
368
428
  let indent = 0
@@ -388,6 +448,12 @@ export function code() {
388
448
  return api
389
449
  }
390
450
 
451
+ export function createLoaderTypes({ exportFrom }) {
452
+ return `export function init(imports?: WebAssembly.Imports): Promise<void>;
453
+ export * from "${exportFrom}";
454
+ `
455
+ }
456
+
391
457
  export function createLoader({ exportFrom, autoInit, getBytesSrc }) {
392
458
  const eager =
393
459
  autoInit === 'eager'
@@ -497,11 +563,13 @@ function writeInlineModules({
497
563
  }
498
564
 
499
565
  export function emitRuntime({
566
+ crateDir,
500
567
  outDir,
501
568
  artifactBaseName,
502
569
  emitNode,
503
570
  emitBrowser,
504
571
  emitInline,
572
+ emitTypes,
505
573
  wasmPaths,
506
574
  exportsList,
507
575
  autoInit,
@@ -512,16 +580,38 @@ export function emitRuntime({
512
580
  mkdirSync(outDir, { recursive: true })
513
581
 
514
582
  if (customJs) {
515
- const customJsContent = readFileSync(join(process.cwd(), customJs), 'utf8')
583
+ const customJsContent = readFileSync(join(crateDir, customJs), 'utf8')
516
584
  writeFileSync(join(outDir, 'custom.js'), customJsContent)
585
+
586
+ if (emitTypes) {
587
+ const customTsPath = customJs.replace(/\.js$/, '.d.ts')
588
+ if (existsSync(join(crateDir, customTsPath))) {
589
+ writeFileSync(
590
+ join(outDir, 'custom.d.ts'),
591
+ readFileSync(join(crateDir, customTsPath), 'utf8')
592
+ )
593
+ }
594
+ }
517
595
  }
518
596
 
519
597
  writeFileSync(
520
598
  join(outDir, 'core.js'),
521
599
  createCore({ exportsList, autoInit, stream })
522
600
  )
601
+ if (emitTypes) {
602
+ writeFileSync(
603
+ join(outDir, 'core.d.ts'),
604
+ createCoreTypes({ exportsList, autoInit, stream })
605
+ )
606
+ }
523
607
  writeFileSync(join(outDir, 'util.js'), readFileSync(UTIL_PATH, 'utf8'))
524
608
 
609
+ const loaderTypes = emitTypes
610
+ ? createLoaderTypes({
611
+ exportFrom: customJs ? './custom.js' : './core.js',
612
+ })
613
+ : null
614
+
525
615
  if (emitBrowser) {
526
616
  writeFileSync(
527
617
  join(outDir, 'browser.js'),
@@ -532,6 +622,7 @@ export function emitRuntime({
532
622
  wasmDelivery,
533
623
  })
534
624
  )
625
+ if (emitTypes) writeFileSync(join(outDir, 'browser.d.ts'), loaderTypes)
535
626
  }
536
627
 
537
628
  if (emitNode) {
@@ -539,6 +630,7 @@ export function emitRuntime({
539
630
  join(outDir, 'node.js'),
540
631
  createNodeLoader({ name: artifactBaseName, autoInit, customJs })
541
632
  )
633
+ if (emitTypes) writeFileSync(join(outDir, 'node.d.ts'), loaderTypes)
542
634
  }
543
635
 
544
636
  if (emitInline && wasmPaths.baselinePath) {
@@ -546,10 +638,13 @@ export function emitRuntime({
546
638
  join(outDir, 'browser-inline.js'),
547
639
  createInlineLoader({ name: artifactBaseName, autoInit, customJs })
548
640
  )
641
+ if (emitTypes)
642
+ writeFileSync(join(outDir, 'browser-inline.d.ts'), loaderTypes)
549
643
  writeFileSync(
550
644
  join(outDir, 'node-inline.js'),
551
645
  createInlineLoader({ name: artifactBaseName, autoInit, customJs })
552
646
  )
647
+ if (emitTypes) writeFileSync(join(outDir, 'node-inline.d.ts'), loaderTypes)
553
648
  writeInlineModules({
554
649
  outDir,
555
650
  artifactBaseName,
package/src/cli/index.js CHANGED
@@ -19,11 +19,13 @@ export async function runBuild(cliOpts) {
19
19
  })
20
20
 
21
21
  emitRuntime({
22
+ crateDir: cfg.crateDir,
22
23
  outDir: cfg.outDir,
23
24
  artifactBaseName: cfg.artifactBaseName,
24
25
  emitNode: cfg.js.emit.node,
25
26
  emitBrowser: cfg.js.emit.browser,
26
27
  emitInline: cfg.inline && cfg.js.emit.inline,
28
+ emitTypes: cfg.js.emit.types,
27
29
  wasmPaths,
28
30
  exportsList: cfg.exports,
29
31
  autoInit: cfg.autoInit,
package/src/cli/pkg.js CHANGED
@@ -11,6 +11,9 @@ export function updatePackageJson({ crateDir, outDir, js, inline }) {
11
11
  if (!pkg.exports) pkg.exports = {}
12
12
 
13
13
  const mainExports = {}
14
+ if (js.emit.types) {
15
+ mainExports.types = `${relOutDir}/node.d.ts`
16
+ }
14
17
  if (js.emit.browser) {
15
18
  mainExports.browser = `${relOutDir}/browser.js`
16
19
  }
@@ -25,6 +28,9 @@ export function updatePackageJson({ crateDir, outDir, js, inline }) {
25
28
 
26
29
  if (inline && js.emit.inline) {
27
30
  const inlineExports = {}
31
+ if (js.emit.types) {
32
+ inlineExports.types = `${relOutDir}/node-inline.d.ts`
33
+ }
28
34
  if (js.emit.browser) {
29
35
  inlineExports.browser = `${relOutDir}/browser-inline.js`
30
36
  }
@@ -38,9 +44,16 @@ export function updatePackageJson({ crateDir, outDir, js, inline }) {
38
44
  }
39
45
  }
40
46
 
41
- // Also update main/module/types if they are missing?
42
- // For now let's just focus on exports as it's the modern way.
47
+ if (js.emit.types) {
48
+ pkg.types = `${relOutDir}/node.d.ts`
49
+ }
50
+ if (js.emit.node) {
51
+ pkg.main = `${relOutDir}/node.js`
52
+ }
53
+ if (js.emit.browser) {
54
+ pkg.module = `${relOutDir}/browser.js`
55
+ }
43
56
 
44
57
  writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n')
45
- console.log('Updated package.json exports')
58
+ console.log('Updated package.json exports and fields')
46
59
  }