watr 4.6.6 → 4.6.7

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.
@@ -15,27 +15,21 @@
15
15
  */
16
16
  export default function polyfill(ast: any[] | string, opts?: boolean | string | any): any[];
17
17
  /**
18
- * Detect which polyfillable features are used in AST.
18
+ * Detect which polyfillable features an AST uses.
19
+ *
19
20
  * @param {Array} ast
20
21
  * @returns {Set<string>} Set of feature names
21
22
  */
22
23
  export function detect(ast: any[]): Set<string>;
23
24
  /**
24
- * Normalize polyfill options to { feature: bool } map.
25
+ * Normalize polyfill options to a { feature: bool } map. `true` enables every
26
+ * feature, a string enables only the named ones (or all via `'all'`), and an
27
+ * explicit object is passed through untouched.
28
+ *
25
29
  * @param {boolean|string|Object} opts
26
30
  * @returns {Object} Normalized options
27
31
  */
28
32
  export function normalize(opts: boolean | string | any): any;
29
- export namespace FEATURES {
30
- let funcref: string[];
31
- let sign_ext: string[];
32
- let nontrapping: string[];
33
- let bulk_memory: string[];
34
- let return_call: string[];
35
- let i31ref: string[];
36
- let extended_const: string[];
37
- let multi_value: any[];
38
- let gc: string[];
39
- let ref_cast: string[];
40
- }
33
+ /** Feature name → trigger-op list — the public catalogue of polyfillable features. */
34
+ export const FEATURES: any;
41
35
  //# sourceMappingURL=polyfill.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"polyfill.d.ts","sourceRoot":"","sources":["../../src/polyfill.js"],"names":[],"mappings":"AA0pCA;;;;;;;;;;;;;;GAcG;AACH,sCAZW,QAAM,MAAM,SACZ,OAAO,GAAC,MAAM,MAAO,SA0B/B;AArnCD;;;;GAIG;AACH,oCAFa,GAAG,CAAC,MAAM,CAAC,CAyCvB;AAnFD;;;;GAIG;AACH,gCAHW,OAAO,GAAC,MAAM,MAAO,OAW/B"}
1
+ {"version":3,"file":"polyfill.d.ts","sourceRoot":"","sources":["../../src/polyfill.js"],"names":[],"mappings":"AA+mCA;;;;;;;;;;;;;;GAcG;AACH,sCAZW,QAAM,MAAM,SACZ,OAAO,GAAC,MAAM,MAAO,SAyB/B;AA1ED;;;;;GAKG;AACH,oCAFa,GAAG,CAAC,MAAM,CAAC,CAuCvB;AA5DD;;;;;;;GAOG;AACH,gCAHW,OAAO,GAAC,MAAM,MAAO,OAU/B;AAlBD,sFAAsF;AACtF,2BAAqE"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Compile WAT to binary. Supports string, AST, and tagged template.
3
+ *
4
+ * @param {Object} backend - { parse, compile, optimize, polyfill } primitives
5
+ * @param {string|Array|TemplateStringsArray} source - WAT source, AST, or template strings
6
+ * @param {any[]} values - Interpolation values (for template literal)
7
+ * Last value can be options object:
8
+ * - polyfill: true | 'funcref sign_ext' | { funcref: true }
9
+ * - optimize: true | 'fold treeshake' | { fold: true }
10
+ * @returns {Uint8Array} WebAssembly binary
11
+ */
12
+ export function compile(backend: any, source: string | any[] | TemplateStringsArray, values: any[]): Uint8Array;
13
+ /**
14
+ * Compile and instantiate WAT, returning exports.
15
+ *
16
+ * @param {Object} backend - { parse, compile, optimize, polyfill } primitives
17
+ * @param {string|Array|TemplateStringsArray} source - WAT source, AST, or template strings
18
+ * @param {any[]} values - Interpolation values (for template literal)
19
+ * @returns {WebAssembly.Exports} Module exports
20
+ */
21
+ export function watr(backend: any, source: string | any[] | TemplateStringsArray, values: any[]): WebAssembly.Exports;
22
+ //# sourceMappingURL=template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../../src/template.js"],"names":[],"mappings":"AA4HA;;;;;;;;;;GAUG;AACH,8CAPW,MAAM,WAAO,oBAAoB,UACjC,GAAG,EAAE,GAIH,UAAU,CAgGtB;AAED;;;;;;;GAOG;AACH,2CAJW,MAAM,WAAO,oBAAoB,UACjC,GAAG,EAAE,GACH,WAAW,CAAC,OAAO,CAO/B"}
@@ -8,11 +8,13 @@
8
8
  * @throws {Error}
9
9
  */
10
10
  export const err: (text: string, pos?: number) => never;
11
- export function clone(items: any[]): any[];
12
11
  /** Regex to detect invalid underscore placement in numbers */
13
12
  export const sepRE: RegExp;
14
13
  /** Regex to match valid integer literals (decimal or hex) */
15
14
  export const intRE: RegExp;
16
15
  export function str(s: string): number[];
17
16
  export function unescape(s: string): string;
17
+ export function clone(node: any): any;
18
+ export function walk(node: any, fn: Function, parent?: any, idx?: number): void;
19
+ export function walkPost(node: any, fn: Function, parent?: any, idx?: number): any;
18
20
  //# sourceMappingURL=util.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/util.js"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,mBAAoB,MAJT,MAIa,EAAE,MAHf,MAG0B,WAUpC;AAOM,2CAAkF;AAEzF,8DAA8D;AAC9D,2BAAiD;AAEjD,6DAA6D;AAC7D,2BAAiD;AAe1C,uBAHI,MAAM,GACJ,MAAM,EAAE,CA8BpB;AAUM,4BAHI,MAAM,GACJ,MAAM,CAE6C"}
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/util.js"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,mBAAoB,MAJT,MAIa,EAAE,MAHf,MAG0B,WAUpC;AAED,8DAA8D;AAC9D,2BAAiD;AAEjD,6DAA6D;AAC7D,2BAAiD;AAe1C,uBAHI,MAAM,GACJ,MAAM,EAAE,CA8BpB;AAUM,4BAHI,MAAM,GACJ,MAAM,CAE6C;AAUzD,4BAHI,GAAG,GACD,GAAG,CAE2D;AASpE,2BALI,GAAG,yBAEH,GAAG,QACH,MAAM,QAKhB;AAgBM,+BANI,GAAG,yBAEH,GAAG,QACH,MAAM,GACJ,GAAG,CAOf"}
package/types/watr.d.ts CHANGED
@@ -2,28 +2,22 @@ export default watr;
2
2
  /**
3
3
  * Compile and instantiate WAT, returning exports.
4
4
  *
5
- * @param {string|TemplateStringsArray} strings - WAT source string or template strings
5
+ * @param {string|TemplateStringsArray} source - WAT source or template strings
6
6
  * @param {...any} values - Interpolation values (for template literal)
7
7
  * @returns {WebAssembly.Exports} Module exports
8
8
  *
9
9
  * @example
10
- * // Template literal
11
10
  * const { add } = watr`(func (export "add") (param i32 i32) (result i32)
12
11
  * (i32.add (local.get 0) (local.get 1))
13
12
  * )`
14
- *
15
- * // Plain string
16
- * const { add } = watr('(func (export "add") (param i32 i32) (result i32) (i32.add (local.get 0) (local.get 1)))')
17
13
  */
18
- export function watr(strings: string | TemplateStringsArray, ...values: any[]): WebAssembly.Exports;
14
+ export function watr(source: string | TemplateStringsArray, ...values: any[]): WebAssembly.Exports;
19
15
  /**
20
16
  * Compile WAT to binary. Supports both string and template literal.
21
17
  *
22
18
  * @param {string|TemplateStringsArray} source - WAT source or template strings
23
- * @param {...any} values - Interpolation values (for template literal)
24
- * Last value can be options object:
25
- * - polyfill: true | 'funcref sign_ext' | { funcref: true }
26
- * - optimize: true | 'fold treeshake' | { fold: true }
19
+ * @param {...any} values - Interpolation values (for template literal).
20
+ * Last value can be an options object: { polyfill, optimize }.
27
21
  * @returns {Uint8Array} WebAssembly binary
28
22
  *
29
23
  * @example
@@ -1 +1 @@
1
- {"version":3,"file":"watr.d.ts","sourceRoot":"","sources":["../watr.js"],"names":[],"mappings":";AAiPA;;;;;;;;;;;;;;;GAeG;AACH,8BAbW,MAAM,GAAC,oBAAoB,aACxB,GAAG,EAAA,GACJ,WAAW,CAAC,OAAO,CAgB/B;AA9HD;;;;;;;;;;;;;;GAcG;AACH,gCAZW,MAAM,GAAC,oBAAoB,aACxB,GAAG,EAAA,GAIJ,UAAU,CA+FtB;kBAxOiB,gBAAgB;kBAChB,gBAAgB;sBACZ,mBAAmB;sBACnB,mBAAmB"}
1
+ {"version":3,"file":"watr.d.ts","sourceRoot":"","sources":["../watr.js"],"names":[],"mappings":";AAiCA;;;;;;;;;;;GAWG;AACH,6BATW,MAAM,GAAC,oBAAoB,aACxB,GAAG,EAAA,GACJ,WAAW,CAAC,OAAO,CAS/B;AA/BD;;;;;;;;;;;;GAYG;AACH,gCAVW,MAAM,GAAC,oBAAoB,aACxB,GAAG,EAAA,GAEJ,UAAU,CAStB;kBAxBiB,gBAAgB;kBAChB,gBAAgB;sBACZ,mBAAmB;sBACnB,mBAAmB"}
package/watr.js CHANGED
@@ -9,139 +9,17 @@ import parse from './src/parse.js'
9
9
  import print from './src/print.js'
10
10
  import _polyfill from './src/polyfill.js'
11
11
  import _optimize from './src/optimize.js'
12
+ import { compile as _tcompile, watr as _twatr } from './src/template.js'
12
13
 
13
- /** Private Use Area character as placeholder for interpolation */
14
- const PUA = '\uE000'
15
-
16
- /**
17
- * Infer result type from instruction name.
18
- * E.g., 'i32.add' → 'i32', 'f64.const' → 'f64'
19
- *
20
- * @param {string} op - Instruction name
21
- * @returns {string|null} Type string or null if unknown
22
- */
23
- const instrType = op => {
24
- if (!op || typeof op !== 'string') return null
25
- // i32.add → i32, f64.const → f64, v128.load → v128
26
- const prefix = op.split('.')[0]
27
- if (/^[if](32|64)|v128/.test(prefix)) return prefix
28
- // comparisons return i32: .eq .ne .lt .gt .le .ge .eqz
29
- if (/\.(eq|ne|[lg][te]|eqz)/.test(op)) return 'i32'
30
- // memory.size/grow return i32
31
- if (op === 'memory.size' || op === 'memory.grow') return 'i32'
32
- return null
33
- }
34
-
35
- /**
36
- * Infer type of an expression AST node.
37
- * Used for auto-import parameter type inference.
38
- *
39
- * @param {any} node - AST node (array or primitive)
40
- * @param {Object} [ctx={}] - Context with locals/funcs type info
41
- * @returns {string|null} Type string or null if unknown
42
- */
43
- const exprType = (node, ctx = {}) => {
44
- if (!Array.isArray(node)) {
45
- // local.get $x - lookup type
46
- if (typeof node === 'string' && node[0] === '$' && ctx.locals?.[node]) return ctx.locals[node]
47
- return null
48
- }
49
- const [op, ...args] = node
50
- // (i32.const 42) → i32
51
- if (instrType(op)) return instrType(op)
52
- // (local.get $x) → lookup
53
- if (op === 'local.get' && ctx.locals?.[args[0]]) return ctx.locals[args[0]]
54
- // (call $fn ...) → lookup function result type
55
- if (op === 'call' && ctx.funcs?.[args[0]]) return ctx.funcs[args[0]].result?.[0]
56
- return null
57
- }
58
-
59
- /**
60
- * Walk AST and transform nodes depth-first.
61
- * Handles array splicing when child has `_splice` property.
62
- *
63
- * @param {any} node - AST node to walk
64
- * @param {Function} fn - Transform function (node) => node
65
- * @returns {any} Transformed node
66
- */
67
- function walk(node, fn) {
68
- node = fn(node)
69
- if (Array.isArray(node)) {
70
- for (let i = 0; i < node.length; i++) {
71
- let child = walk(node[i], fn)
72
- if (child?._splice) node.splice(i, 1, ...child), i += child.length - 1
73
- else node[i] = child
74
- }
75
- }
76
- return node
77
- }
78
-
79
- /**
80
- * Find function references in AST and infer import signatures.
81
- * Scans for `(call fn args...)` where fn is a JS function,
82
- * infers param types from arguments, generates import entries.
83
- *
84
- * @param {Array} ast - AST to scan
85
- * @param {Function[]} funcs - Functions to look for
86
- * @returns {Array<{idx: number, name: string, params: string[], fn: Function}>} Import entries
87
- */
88
- function inferImports(ast, funcs) {
89
- const imports = []
90
- const importMap = new Map() // fn → import index
91
-
92
- walk(ast, node => {
93
- if (!Array.isArray(node)) return node
94
-
95
- // Find (call ${fn} args...) where fn is a function
96
- if (node[0] === 'call' && typeof node[1] === 'function') {
97
- const fn = node[1]
98
-
99
- if (!importMap.has(fn)) {
100
- // Infer param types from arguments
101
- const params = []
102
- for (let i = 2; i < node.length; i++) {
103
- const t = exprType(node[i])
104
- if (t) params.push(t)
105
- }
106
-
107
- // Create import entry
108
- const idx = imports.length
109
- const name = fn.name || `$fn${idx}`
110
- importMap.set(fn, { idx, name: name.startsWith('$') ? name : '$' + name, params, fn })
111
- imports.push(importMap.get(fn))
112
- }
113
-
114
- // Replace function with import reference
115
- const imp = importMap.get(fn)
116
- node[1] = imp.name
117
- }
118
-
119
- return node
120
- })
121
-
122
- return imports
123
- }
124
-
125
- /**
126
- * Generate WAT import declarations from inferred imports.
127
- *
128
- * @param {Array<{name: string, params: string[]}>} imports - Import entries
129
- * @returns {Array} AST nodes for import declarations
130
- */
131
- function genImports(imports) {
132
- return imports.map(({ name, params }) =>
133
- ['import', '"env"', `"${name.slice(1)}"`, ['func', name, ...params.map(t => ['param', t])]]
134
- )
135
- }
14
+ /** JS-source backend primitives for the tagged-template layer. */
15
+ const backend = { parse, compile: _compile, optimize: _optimize, polyfill: _polyfill }
136
16
 
137
17
  /**
138
18
  * Compile WAT to binary. Supports both string and template literal.
139
19
  *
140
20
  * @param {string|TemplateStringsArray} source - WAT source or template strings
141
- * @param {...any} values - Interpolation values (for template literal)
142
- * Last value can be options object:
143
- * - polyfill: true | 'funcref sign_ext' | { funcref: true }
144
- * - optimize: true | 'fold treeshake' | { fold: true }
21
+ * @param {...any} values - Interpolation values (for template literal).
22
+ * Last value can be an options object: { polyfill, optimize }.
145
23
  * @returns {Uint8Array} WebAssembly binary
146
24
  *
147
25
  * @example
@@ -150,116 +28,23 @@ function genImports(imports) {
150
28
  * compile(src, { polyfill: true, optimize: true })
151
29
  */
152
30
  function compile(source, ...values) {
153
- // Options object as last argument (non-template call)
154
- let opts = {}
155
- if (!Array.isArray(source) && values.length && typeof values[values.length - 1] === 'object' && values[values.length - 1] !== null && !values[values.length - 1].byteLength) {
156
- opts = values.pop()
157
- }
158
-
159
- // Template literal: source is TemplateStringsArray
160
- if (Array.isArray(source) && source.raw) {
161
- // Build source with placeholders
162
- let src = source[0]
163
- for (let i = 0; i < values.length; i++) {
164
- src += PUA + source[i + 1]
165
- }
166
-
167
- // Parse to AST
168
- let ast = parse(src)
169
-
170
- // Collect functions for auto-import
171
- const funcsToImport = []
172
-
173
- // Replace placeholders with actual values
174
- let idx = 0
175
- ast = walk(ast, node => {
176
- if (node === PUA) {
177
- const value = values[idx++]
178
- // Function → mark for import inference
179
- if (typeof value === 'function') {
180
- funcsToImport.push(value)
181
- return value // keep function reference for now
182
- }
183
- // String containing WAT code → parse and splice
184
- if (typeof value === 'string' && (value[0] === '(' || /^\s*\(/.test(value))) {
185
- const parsed = parse(value)
186
- if (Array.isArray(parsed) && Array.isArray(parsed[0])) {
187
- parsed._splice = true
188
- }
189
- return parsed
190
- }
191
- // Uint8Array → convert to plain array for flat() compatibility
192
- if (value.byteLength !== undefined) return [...value]
193
- return value
194
- }
195
- return node
196
- })
197
-
198
- // If we have functions to import, infer and generate imports
199
- let importObjs = null
200
- if (funcsToImport.length) {
201
- const imports = inferImports(ast, funcsToImport)
202
- if (imports.length) {
203
- // Insert import declarations at start of module
204
- const importDecls = genImports(imports)
205
- if (ast[0] === 'module') {
206
- ast.splice(1, 0, ...importDecls)
207
- } else if (typeof ast[0] === 'string') {
208
- // Single top-level node like ['func', ...] - wrap in array with imports
209
- ast = [...importDecls, ast]
210
- } else {
211
- // Multiple top-level nodes like [['func', ...], ['func', ...]]
212
- ast.unshift(...importDecls)
213
- }
214
- // Build imports object for instantiation
215
- importObjs = { env: {} }
216
- for (const imp of imports) {
217
- importObjs.env[imp.name.slice(1)] = imp.fn
218
- }
219
- }
220
- }
221
-
222
- // Apply transforms
223
- if (opts.polyfill) ast = _polyfill(ast, opts.polyfill)
224
- if (opts.optimize) ast = _optimize(ast, opts.optimize)
225
-
226
- const binary = _compile(ast)
227
- // Attach imports for watr() to use
228
- if (importObjs) binary._imports = importObjs
229
- return binary
230
- }
231
-
232
- // String/AST source with options
233
- if (opts.polyfill || opts.optimize) {
234
- let ast = typeof source === 'string' ? parse(source) : source
235
- if (opts.polyfill) ast = _polyfill(ast, opts.polyfill)
236
- if (opts.optimize) ast = _optimize(ast, opts.optimize)
237
- return _compile(ast)
238
- }
239
- return _compile(source)
31
+ return _tcompile(backend, source, values)
240
32
  }
241
33
 
242
34
  /**
243
35
  * Compile and instantiate WAT, returning exports.
244
36
  *
245
- * @param {string|TemplateStringsArray} strings - WAT source string or template strings
37
+ * @param {string|TemplateStringsArray} source - WAT source or template strings
246
38
  * @param {...any} values - Interpolation values (for template literal)
247
39
  * @returns {WebAssembly.Exports} Module exports
248
40
  *
249
41
  * @example
250
- * // Template literal
251
42
  * const { add } = watr`(func (export "add") (param i32 i32) (result i32)
252
43
  * (i32.add (local.get 0) (local.get 1))
253
44
  * )`
254
- *
255
- * // Plain string
256
- * const { add } = watr('(func (export "add") (param i32 i32) (result i32) (i32.add (local.get 0) (local.get 1)))')
257
45
  */
258
- function watr(strings, ...values) {
259
- const binary = compile(strings, ...values)
260
- const module = new WebAssembly.Module(binary)
261
- const instance = new WebAssembly.Instance(module, binary._imports)
262
- return instance.exports
46
+ function watr(source, ...values) {
47
+ return _twatr(backend, source, values)
263
48
  }
264
49
 
265
50
  export default watr