wasm-bindgen-lite 0.1.0

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.
@@ -0,0 +1,48 @@
1
+ import assert from 'node:assert'
2
+ import { init as initNode, process as processNode } from '../dist/node.js'
3
+ import {
4
+ init as initInline,
5
+ process as processInline,
6
+ } from '../dist/node-inline.js'
7
+
8
+ async function testNode() {
9
+ console.log('Testing Node external loader...')
10
+ await initNode()
11
+
12
+ const input = new Uint8Array([1, 2, 3])
13
+ const output = processNode(input)
14
+
15
+ console.log('Input:', input)
16
+ console.log('Output:', output)
17
+
18
+ assert.deepStrictEqual(Array.from(output), [2, 3, 4])
19
+ console.log('Node external loader test passed!')
20
+ }
21
+
22
+ async function testInline() {
23
+ console.log('\nTesting Node inline loader...')
24
+ // Note: /inline exports are mapped in package.json to ./dist/node-inline.js for Node
25
+ await initInline()
26
+
27
+ const input = new Uint8Array([10, 20, 30])
28
+ const output = processInline(input)
29
+
30
+ console.log('Input:', input)
31
+ console.log('Output:', output)
32
+
33
+ assert.deepStrictEqual(Array.from(output), [11, 21, 31])
34
+ console.log('Node inline loader test passed!')
35
+ }
36
+
37
+ async function runTests() {
38
+ try {
39
+ await testNode()
40
+ await testInline()
41
+ console.log('\nAll JS tests passed!')
42
+ } catch (e) {
43
+ console.error('JS tests failed:', e)
44
+ process.exit(1)
45
+ }
46
+ }
47
+
48
+ runTests()
@@ -0,0 +1,83 @@
1
+ import { execSync } from 'node:child_process'
2
+ import { copyFileSync, mkdirSync } from 'node:fs'
3
+ import { join } from 'node:path'
4
+
5
+ function runCargoBuild({ crateDir, release, simd }) {
6
+ const args = ['build', '--target', 'wasm32-unknown-unknown']
7
+ if (release) args.push('--release')
8
+
9
+ const env = { ...process.env }
10
+ if (simd) {
11
+ const base = process.env.RUSTFLAGS || ''
12
+ const extra = '-C target-feature=+simd128'
13
+ env.RUSTFLAGS = [base, extra].filter(Boolean).join(' ').trim()
14
+ }
15
+
16
+ execSync(`cargo ${args.join(' ')}`, {
17
+ cwd: crateDir,
18
+ stdio: 'inherit',
19
+ env,
20
+ })
21
+ }
22
+
23
+ function wasmPath({ crateDir, release, wasmFileStem }) {
24
+ const profile = release ? 'release' : 'debug'
25
+ return join(
26
+ crateDir,
27
+ 'target',
28
+ 'wasm32-unknown-unknown',
29
+ profile,
30
+ `${wasmFileStem}.wasm`
31
+ )
32
+ }
33
+
34
+ function maybeRunWasmOpt(wasmFile, wasmOpt) {
35
+ if (wasmOpt.mode === 'off') return
36
+ if (wasmOpt.mode === 'auto') {
37
+ try {
38
+ execSync('wasm-opt --version', { stdio: 'ignore' })
39
+ } catch {
40
+ return
41
+ }
42
+ }
43
+
44
+ const args = ['wasm-opt', ...wasmOpt.args, wasmFile, '-o', wasmFile]
45
+ execSync(args.join(' '), { stdio: 'inherit' })
46
+ }
47
+
48
+ export function buildArtifacts({
49
+ crateDir,
50
+ wasmFileStem,
51
+ artifactBaseName,
52
+ outDir,
53
+ targets,
54
+ release,
55
+ wasmOpt,
56
+ }) {
57
+ mkdirSync(outDir, { recursive: true })
58
+ const wasmOutDir = join(outDir, 'wasm')
59
+ mkdirSync(wasmOutDir, { recursive: true })
60
+
61
+ let baselinePath = null
62
+ let simdPath = null
63
+
64
+ if (targets.baseline) {
65
+ console.log('Building baseline wasm...')
66
+ runCargoBuild({ crateDir, release, simd: false })
67
+ const built = wasmPath({ crateDir, release, wasmFileStem })
68
+ baselinePath = join(wasmOutDir, `${artifactBaseName}.base.wasm`)
69
+ copyFileSync(built, baselinePath)
70
+ maybeRunWasmOpt(baselinePath, wasmOpt)
71
+ }
72
+
73
+ if (targets.simd) {
74
+ console.log('Building SIMD wasm...')
75
+ runCargoBuild({ crateDir, release, simd: true })
76
+ const built = wasmPath({ crateDir, release, wasmFileStem })
77
+ simdPath = join(wasmOutDir, `${artifactBaseName}.simd.wasm`)
78
+ copyFileSync(built, simdPath)
79
+ maybeRunWasmOpt(simdPath, wasmOpt)
80
+ }
81
+
82
+ return { baselinePath, simdPath, wasmOutDir }
83
+ }
@@ -0,0 +1,211 @@
1
+ import { existsSync, readFileSync } from 'node:fs'
2
+ import { resolve, join } from 'node:path'
3
+
4
+ const DEFAULT_CONFIG = {
5
+ outDir: 'dist-wasm-bindgen-lite',
6
+ artifactBaseName: 'mod',
7
+ targets: {
8
+ baseline: true,
9
+ simd: true,
10
+ },
11
+ inline: true,
12
+ release: true,
13
+ wasmOpt: {
14
+ mode: 'auto', // auto | on | off
15
+ args: ['-Oz'],
16
+ },
17
+ js: {
18
+ emit: {
19
+ node: true,
20
+ browser: true,
21
+ inline: true,
22
+ },
23
+ custom: null, // path to custom JS file to include and re-export
24
+ },
25
+ exports: [
26
+ {
27
+ abi: 'process_bytes',
28
+ name: 'process',
29
+ return: 'bytes', // bytes | f32 | f64 | i32 | u32 | i16 | u16 | i8 | u8
30
+ reuseBuffer: false,
31
+ },
32
+ ],
33
+ autoInit: 'off', // off | lazy | eager
34
+ stream: {
35
+ enable: false,
36
+ export: 'process',
37
+ delimiter: null, // null | number (byte value)
38
+ },
39
+ wasmDelivery: {
40
+ type: 'relative', // relative | jsdelivr
41
+ },
42
+ }
43
+
44
+ function parseTomlName(contents) {
45
+ // leniently find the first name in the [package] section
46
+ const pkgMatch = /\[package\]([\s\S]*?)(?:\n\[[^\]]|\r?\n\[[^\]])/m.exec(
47
+ contents + '\n['
48
+ ) // sentinel [
49
+ if (!pkgMatch) return null
50
+ const body = pkgMatch[1]
51
+ const nameMatch = /name\s*=\s*["']([^"']+)["']/m.exec(body)
52
+ return nameMatch ? nameMatch[1] : null
53
+ }
54
+
55
+ function readCrateName(crateDir) {
56
+ const cargoPath = join(crateDir, 'Cargo.toml')
57
+ const contents = readFileSync(cargoPath, 'utf8')
58
+ const crateName = parseTomlName(contents)
59
+ if (!crateName) {
60
+ throw new Error(`Could not find package.name in ${cargoPath}`)
61
+ }
62
+ return crateName
63
+ }
64
+
65
+ function normalizeEmit(value) {
66
+ if (!value) return { node: true, browser: true, inline: true }
67
+ if (Array.isArray(value)) {
68
+ const set = new Set(value)
69
+ return {
70
+ node: set.has('node'),
71
+ browser: set.has('browser'),
72
+ inline: set.has('inline'),
73
+ }
74
+ }
75
+ if (typeof value === 'object') {
76
+ return {
77
+ node: value.node !== false,
78
+ browser: value.browser !== false,
79
+ inline: value.inline !== false,
80
+ }
81
+ }
82
+ return { node: true, browser: true, inline: true }
83
+ }
84
+
85
+ function normalizeWasmOpt(input) {
86
+ if (!input || input.mode === 'auto' || input === 'auto') {
87
+ return { mode: 'auto', args: input?.args || DEFAULT_CONFIG.wasmOpt.args }
88
+ }
89
+ if (input === 'off' || input?.mode === 'off') {
90
+ return { mode: 'off', args: input?.args || DEFAULT_CONFIG.wasmOpt.args }
91
+ }
92
+ return { mode: 'on', args: input?.args || DEFAULT_CONFIG.wasmOpt.args }
93
+ }
94
+
95
+ export function loadConfigFromCli(cliOpts = {}) {
96
+ const crateDir = resolve(cliOpts.crate || '.')
97
+ const cfgPath = cliOpts.configPath
98
+ ? resolve(crateDir, cliOpts.configPath)
99
+ : resolve(crateDir, 'wasm-bindgen-lite.config.json')
100
+
101
+ let fileConfig = {}
102
+ if (existsSync(cfgPath)) {
103
+ fileConfig = JSON.parse(readFileSync(cfgPath, 'utf8'))
104
+ }
105
+
106
+ const crateName = readCrateName(crateDir)
107
+ const artifactBaseName =
108
+ cliOpts.artifactBaseName ??
109
+ fileConfig.artifactBaseName ??
110
+ DEFAULT_CONFIG.artifactBaseName
111
+
112
+ const outDir = resolve(
113
+ crateDir,
114
+ cliOpts.out ?? fileConfig.outDir ?? DEFAULT_CONFIG.outDir
115
+ )
116
+
117
+ const release =
118
+ typeof cliOpts.release === 'boolean'
119
+ ? cliOpts.release
120
+ : (fileConfig.release ?? DEFAULT_CONFIG.release)
121
+
122
+ const targets = {
123
+ baseline:
124
+ cliOpts.baseline ??
125
+ fileConfig.targets?.baseline ??
126
+ DEFAULT_CONFIG.targets.baseline,
127
+ simd:
128
+ typeof cliOpts.simd === 'boolean'
129
+ ? cliOpts.simd
130
+ : (fileConfig.targets?.simd ?? DEFAULT_CONFIG.targets.simd),
131
+ }
132
+
133
+ const inline =
134
+ typeof cliOpts.inline === 'boolean'
135
+ ? cliOpts.inline
136
+ : (fileConfig.inline ?? DEFAULT_CONFIG.inline)
137
+
138
+ const wasmOpt = normalizeWasmOpt(
139
+ cliOpts.wasmOptMode
140
+ ? { mode: cliOpts.wasmOptMode, args: cliOpts.wasmOptArgs }
141
+ : (fileConfig.wasmOpt ?? DEFAULT_CONFIG.wasmOpt)
142
+ )
143
+
144
+ const jsEmit = normalizeEmit(fileConfig.js?.emit ?? DEFAULT_CONFIG.js.emit)
145
+ const jsCustom = fileConfig.js?.custom ?? DEFAULT_CONFIG.js.custom
146
+
147
+ const exportsList =
148
+ fileConfig.exports &&
149
+ Array.isArray(fileConfig.exports) &&
150
+ fileConfig.exports.length
151
+ ? fileConfig.exports
152
+ : DEFAULT_CONFIG.exports
153
+
154
+ const autoInit =
155
+ fileConfig.autoInit === 'lazy' ||
156
+ fileConfig.autoInit === 'eager' ||
157
+ fileConfig.autoInit === 'off'
158
+ ? fileConfig.autoInit
159
+ : DEFAULT_CONFIG.autoInit
160
+
161
+ const streamCfg = {
162
+ enable: fileConfig.stream?.enable ?? DEFAULT_CONFIG.stream.enable,
163
+ export:
164
+ fileConfig.stream?.export ??
165
+ exportsList[0]?.name ??
166
+ DEFAULT_CONFIG.stream.export,
167
+ delimiter: fileConfig.stream?.delimiter ?? DEFAULT_CONFIG.stream.delimiter,
168
+ }
169
+
170
+ const wasmDelivery = {
171
+ type: fileConfig.wasmDelivery?.type ?? DEFAULT_CONFIG.wasmDelivery.type,
172
+ package: fileConfig.wasmDelivery?.package ?? fileConfig.name ?? crateName,
173
+ version: fileConfig.wasmDelivery?.version ?? fileConfig.version ?? 'latest',
174
+ }
175
+
176
+ const config = {
177
+ crateDir,
178
+ crateName,
179
+ wasmFileStem: crateName.replace(/-/g, '_'),
180
+ artifactBaseName,
181
+ outDir,
182
+ release,
183
+ inline,
184
+ targets,
185
+ wasmOpt,
186
+ js: { emit: jsEmit, custom: jsCustom },
187
+ exports: exportsList,
188
+ autoInit,
189
+ stream: streamCfg,
190
+ wasmDelivery,
191
+ }
192
+
193
+ return config
194
+ }
195
+
196
+ export function summarizeConfig(cfg) {
197
+ return {
198
+ crateDir: cfg.crateDir,
199
+ outDir: cfg.outDir,
200
+ artifactBaseName: cfg.artifactBaseName,
201
+ targets: cfg.targets,
202
+ inline: cfg.inline,
203
+ wasmOpt: cfg.wasmOpt,
204
+ release: cfg.release,
205
+ jsEmit: cfg.js.emit,
206
+ exports: cfg.exports,
207
+ autoInit: cfg.autoInit,
208
+ stream: cfg.stream,
209
+ wasmDelivery: cfg.wasmDelivery,
210
+ }
211
+ }