watr 4.7.1 → 5.0.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.
package/src/compile.js CHANGED
@@ -37,17 +37,10 @@ const cleanup = (node, result) => {
37
37
  }
38
38
 
39
39
 
40
- /**
41
- * Converts a WebAssembly Text Format (WAT) tree to a WebAssembly binary format (WASM).
42
- *
43
- * @param {string|Array} nodes - The WAT tree or string to be compiled to WASM binary.
44
- * @returns {Uint8Array} The compiled WASM binary. When the WAT carries
45
- * `@metadata.code.<type>` annotations, the result also exposes a `.metadata`
46
- * property — `{ [type]: [[absoluteByteOffset, data], ...] }`, each offset the
47
- * instruction's position in the final binary. That's the hook a source-map
48
- * emitter needs to correlate generated wasm back to its source.
49
- */
50
- export default function compile(nodes) {
40
+ // Internal: assemble the module. sizeOnly=false → wasm bytes (Uint8Array); sizeOnly=true →
41
+ // just the byte LENGTH, skipping materialization of the multi-MB binary that's size()'s
42
+ // reason to exist (the optimizer's size-revert guard can't afford to build bytes it discards).
43
+ function assemble(nodes, sizeOnly) {
51
44
  // normalize to (module ...) form
52
45
  if (typeof nodes === 'string') err.src = nodes, nodes = parse(nodes) || []
53
46
  else err.src = '' // clear source if AST passed directly
@@ -63,10 +56,10 @@ export default function compile(nodes) {
63
56
  else if (typeof nodes[0] === 'string') nodes = [nodes]
64
57
 
65
58
  // binary abbr "\00" "\0x61" ...
66
- if (nodes[idx] === 'binary') return Uint8Array.from(nodes.slice(++idx).flat())
59
+ if (nodes[idx] === 'binary') { const b = Uint8Array.from(nodes.slice(++idx).flat()); return sizeOnly ? b.length : b }
67
60
 
68
61
  // quote "a" "b"
69
- if (nodes[idx] === 'quote') return compile(nodes.slice(++idx).map(v => v.valueOf().slice(1, -1)).flat().join(''))
62
+ if (nodes[idx] === 'quote') return assemble(nodes.slice(++idx).map(v => v.valueOf().slice(1, -1)).flat().join(''), sizeOnly)
70
63
 
71
64
  // expand grouped imports: (import "mod" (item "name" type)*) -> individual imports
72
65
  // compact import section (Phase 3)
@@ -241,6 +234,26 @@ export default function compile(nodes) {
241
234
  // pre-compute sections that may collect string constants (for strings section ordering)
242
235
  const globalSection = bin(SECTION.global)
243
236
  const elemSection = bin(SECTION.elem)
237
+ // measure: byte LENGTH only — skip building + materializing the multi-MB code byte array
238
+ // (the optimizer's size-revert guard only needs the count). Sizes the code section via
239
+ // codeItemSize; other sections are small, built normally + summed. Same string-collection
240
+ // ORDER as the emit path (global, elem, code, meta, data → strings).
241
+ if (sizeOnly) {
242
+ const codeSizes = ctx.code.filter(Boolean).map(item => codeItemSize(item, ctx))
243
+ const innerLen = codeSizes.length ? ulebSize(codeSizes.length) + codeSizes.reduce((a, b) => a + b, 0) : 0
244
+ const codeSecLen = codeSizes.length ? 1 + ulebSize(innerLen) + innerLen : 0 // SECTION.code + vec(vec(items))
245
+ const metaSection = binMeta()
246
+ const dataSection = bin(SECTION.data)
247
+ const stringsSection = ctx.strings.length ? [SECTION.strings, ...vec([0x00, ...vec(ctx.strings.map(s => vec(s)))])] : []
248
+ const others = [
249
+ bin(SECTION.custom), bin(SECTION.type), bin(SECTION.import), bin(SECTION.func),
250
+ bin(SECTION.table), bin(SECTION.memory), bin(SECTION.tag), stringsSection,
251
+ globalSection, bin(SECTION.export), bin(SECTION.start, false), elemSection,
252
+ bin(SECTION.datacount, false), metaSection, dataSection
253
+ ]
254
+ return 8 + codeSecLen + others.reduce((s, sec) => s + sec.length, 0) // 8 = magic + version
255
+ }
256
+
244
257
  // inline bin(code) so the per-function item bytes survive — with ctx.codeSizePrefix
245
258
  // they let us lift code-metadata positions to absolute binary offsets below
246
259
  const codeItems = ctx.code.filter(Boolean).map(item => build[SECTION.code](item, ctx)).filter(Boolean)
@@ -317,6 +330,19 @@ export default function compile(nodes) {
317
330
  }
318
331
  }
319
332
 
333
+ /**
334
+ * Convert a WAT tree (or source string) to a wasm binary (Uint8Array). When the WAT carries
335
+ * `@metadata.code.<type>` annotations the result also exposes `.metadata` —
336
+ * `{ [type]: [[absByteOffset, data], ...] }`, the hook a source-map emitter needs.
337
+ */
338
+ export default function compile(nodes) { return assemble(nodes) }
339
+
340
+ /**
341
+ * Byte size of `compile(nodes)` without materializing the binary — a peer transform for
342
+ * tooling (the optimizer's size-revert guard, size budgeting). Exactly `compile(nodes).length`,
343
+ * summed from section sizes instead of building them (invariant-tested).
344
+ */
345
+ export function size(nodes) { return assemble(nodes, true) }
320
346
 
321
347
  /** Check if node is a valid index reference ($name or number) */
322
348
  const isIdx = n => n?.[0] === '$' || !isNaN(n)
@@ -1062,6 +1088,59 @@ const instr = (nodes, ctx) => {
1062
1088
  return out.push(0x0b), out
1063
1089
  }
1064
1090
 
1091
+ // LEB128 byte-width of an unsigned integer (exact, reuses uleb so it can never drift).
1092
+ const ulebSize = (n) => uleb(n).length
1093
+
1094
+ // Size-only twin of instr(): the byte LENGTH of the encoded instruction stream,
1095
+ // WITHOUT building the (multi-MB) byte array. Reuses every HANDLER for exact
1096
+ // immediate widths + index resolution — only `out.push(...bytes)` accumulation is
1097
+ // replaced by integer summation (the dominant cost on large modules). The
1098
+ // opcode-value tweaks in instr() (typed-select / nullable-reftype) change a byte
1099
+ // VALUE, not the length, so they're irrelevant here. MUST equal instr(...).length
1100
+ // (asserted by the byteSize↔compile invariant test).
1101
+ const instrSize = (nodes, ctx) => {
1102
+ let size = 0, meta = []
1103
+ while (nodes?.length) {
1104
+ let op = nodes.shift()
1105
+ if (op?.[0] === '@metadata') { meta.push(op.slice(1)); continue }
1106
+ if (Array.isArray(op)) { op.loc != null && (err.loc = op.loc); err(`Unknown instruction ${op[0]}`) }
1107
+ const opc = INSTR[op] || err(`Unknown instruction ${op}`)
1108
+ let n = opc.length
1109
+ if (HANDLER[op]) n += HANDLER[op](nodes, ctx, op).length
1110
+ if (meta.length) { for (const [type, data] of meta) ((ctx.meta[type] ??= []).push([size, data])); meta = [] }
1111
+ size += n
1112
+ }
1113
+ return size + 1 // trailing 0x0b (end)
1114
+ }
1115
+
1116
+ // Size-only twin of build[SECTION.code]: byte LENGTH of one function's code item.
1117
+ // Mirrors the builder exactly (local setup, squash, metadata bookkeeping, vec
1118
+ // framing) but uses instrSize for the body — so locals/strings/metadata side
1119
+ // effects on ctx stay identical, only the body byte array is never materialized.
1120
+ const codeItemSize = (body, ctx) => {
1121
+ let [typeidx, param] = body.shift()
1122
+ if (!param) [, [param]] = ctx.type[id(typeidx, ctx.type)]
1123
+ ctx.local = Object.create(param); ctx.block = []
1124
+ ctx.local.name = 'local'; ctx.block.name = 'block'
1125
+ if (ctx._codeIdx === undefined) ctx._codeIdx = 0
1126
+ let codeIdx = ctx._codeIdx++
1127
+ while (body[0]?.[0] === 'local') {
1128
+ let [, ...types] = body.shift()
1129
+ if (isId(types[0])) { let nm = types.shift(); if (nm in ctx.local) err(`Duplicate local ${nm}`); else ctx.local[nm] = ctx.local.length }
1130
+ ctx.local.push(...types)
1131
+ }
1132
+ ctx.meta = {}
1133
+ const bytesLen = instrSize(body, ctx)
1134
+ let loctypes = ctx.local.slice(param.length).reduce((a, type) => (type == a[a.length - 1]?.[1] ? a[a.length - 1][0]++ : a.push([1, type]), a), [])
1135
+ const locals = vec(loctypes.map(([n, t]) => [...uleb(n), ...reftype(t, ctx)]))
1136
+ const funcIdx = ctx.import.filter(imp => imp[2][0] === 'func').length + codeIdx
1137
+ for (const type in ctx.meta) { for (const inst of ctx.meta[type]) inst[0] += locals.length; ((ctx.metadata ??= {})[type] ??= []).push([funcIdx, ctx.meta[type]]) }
1138
+ ctx.local = ctx.block = ctx.meta = null
1139
+ const bodyLen = locals.length + bytesLen
1140
+ ;(ctx.codeSizePrefix ??= [])[codeIdx] = ulebSize(bodyLen) // = vec prefix width
1141
+ return ulebSize(bodyLen) + bodyLen // vec([...locals, ...bytes]).length
1142
+ }
1143
+
1065
1144
  // instantiation time value initializer (consuming) - normalize then encode + add end byte
1066
1145
  const expr = (node, ctx) => instr(normalize([node], ctx), ctx)
1067
1146
 
package/src/optimize.js CHANGED
@@ -7,7 +7,7 @@
7
7
  * @module wat/optimize
8
8
  */
9
9
 
10
- import compile from './compile.js'
10
+ import compile, { size } from './compile.js'
11
11
  import parse from './parse.js'
12
12
 
13
13
  // Fixpoint round caps — empirical convergence bounds, not correctness limits.
@@ -68,7 +68,10 @@ const count = (node) => {
68
68
  * @returns {number}
69
69
  */
70
70
  const binarySize = (ast) => {
71
- try { return compile(ast).length } catch { return Infinity }
71
+ // `size` = byte length without materializing the binary the size-revert guard only needs
72
+ // the count, and re-encoding the whole module each round is the optimizer's dominant cost on
73
+ // large modules. Exactly compile(ast).length (invariant-tested).
74
+ try { return size(ast) } catch { return Infinity }
72
75
  }
73
76
 
74
77
  /**
package/src/template.js CHANGED
@@ -19,6 +19,24 @@ import { resultType } from './const.js'
19
19
  /** Private Use Area character as placeholder for interpolation */
20
20
  const PUA = '\uE000'
21
21
 
22
+ /**
23
+ * Apply a backend transform (`polyfill`/`optimize`), or throw an actionable
24
+ * pointer when this entry doesn't bundle it. The default `watr` build wires a
25
+ * lean backend (parse + compile) and leaves the heavy transforms to their own
26
+ * entries, so `compile(src, { optimize })` here directs you to compose instead.
27
+ *
28
+ * @param {Function|undefined} fn - transform from the backend
29
+ * @param {string} name - 'polyfill' | 'optimize'
30
+ * @param {Array} ast
31
+ * @param {any} opt - the option value
32
+ * @returns {Array} transformed AST
33
+ */
34
+ function applyTransform(fn, name, ast, opt) {
35
+ if (typeof fn !== 'function')
36
+ throw Error(`watr: '${name}' is not bundled in this entry \u2014 import it from 'watr/${name}' and compose: compile(${name}(src))`)
37
+ return fn(ast, opt)
38
+ }
39
+
22
40
  /**
23
41
  * Infer type of an expression AST node.
24
42
  * Used for auto-import parameter type inference.
@@ -209,9 +227,9 @@ export function compile(backend, source, values) {
209
227
  }
210
228
  }
211
229
 
212
- // Apply transforms
213
- if (opts.polyfill) ast = polyfill(ast, opts.polyfill)
214
- if (opts.optimize) ast = optimize(ast, opts.optimize)
230
+ // Apply transforms (heavy passes live in separate entries — see applyTransform)
231
+ if (opts.polyfill) ast = applyTransform(polyfill, 'polyfill', ast, opts.polyfill)
232
+ if (opts.optimize) ast = applyTransform(optimize, 'optimize', ast, opts.optimize)
215
233
 
216
234
  const binary = emit(ast)
217
235
  // Attach imports for watr() to use
@@ -222,8 +240,8 @@ export function compile(backend, source, values) {
222
240
  // String/AST source with options
223
241
  if (opts.polyfill || opts.optimize) {
224
242
  let ast = typeof source === 'string' ? parse(source) : source
225
- if (opts.polyfill) ast = polyfill(ast, opts.polyfill)
226
- if (opts.optimize) ast = optimize(ast, opts.optimize)
243
+ if (opts.polyfill) ast = applyTransform(polyfill, 'polyfill', ast, opts.polyfill)
244
+ if (opts.optimize) ast = applyTransform(optimize, 'optimize', ast, opts.optimize)
227
245
  return emit(ast)
228
246
  }
229
247
  return emit(source)
@@ -1,12 +1,13 @@
1
1
  /**
2
- * Converts a WebAssembly Text Format (WAT) tree to a WebAssembly binary format (WASM).
3
- *
4
- * @param {string|Array} nodes - The WAT tree or string to be compiled to WASM binary.
5
- * @returns {Uint8Array} The compiled WASM binary. When the WAT carries
6
- * `@metadata.code.<type>` annotations, the result also exposes a `.metadata`
7
- * property — `{ [type]: [[absoluteByteOffset, data], ...] }`, each offset the
8
- * instruction's position in the final binary. That's the hook a source-map
9
- * emitter needs to correlate generated wasm back to its source.
2
+ * Convert a WAT tree (or source string) to a wasm binary (Uint8Array). When the WAT carries
3
+ * `@metadata.code.<type>` annotations the result also exposes `.metadata` —
4
+ * `{ [type]: [[absByteOffset, data], ...] }`, the hook a source-map emitter needs.
10
5
  */
11
- export default function compile(nodes: string | any[]): Uint8Array;
6
+ export default function compile(nodes: any): any;
7
+ /**
8
+ * Byte size of `compile(nodes)` without materializing the binary — a peer transform for
9
+ * tooling (the optimizer's size-revert guard, size budgeting). Exactly `compile(nodes).length`,
10
+ * summed from section sizes instead of building them (invariant-tested).
11
+ */
12
+ export function size(nodes: any): any;
12
13
  //# sourceMappingURL=compile.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/compile.js"],"names":[],"mappings":"AAuCA;;;;;;;;;GASG;AACH,uCAPW,MAAM,QAAM,GACV,UAAU,CAkRtB"}
1
+ {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/compile.js"],"names":[],"mappings":"AA4UA;;;;GAIG;AACH,iDAAiE;AAEjE;;;;GAIG;AACH,sCAA4D"}
@@ -1 +1 @@
1
- {"version":3,"file":"optimize.d.ts","sourceRoot":"","sources":["../../src/optimize.js"],"names":[],"mappings":"AAmxHA,gEA6FC;AA5zHD;;;;GAIG;AACH,4BAHW,GAAG,GACD,MAAM,CAOlB;AAED;;;;GAIG;AACH,wCAFa,MAAM,CAIlB;AA8CD;;;;;GAKG;AACH,6CAgJC;AAwUD;;;;GAIG;AACH,wCAkDC;AA0YD;;;;GAIG;AACH,4CAqBC;AA+CD;;;;;GAKG;AACH,8CAmDC;AAndD;;;;GAIG;AACH,4CASC;AAID;;;;GAIG;AACH,4CAwDC;AAID;;;;GAIG;AACH,0CA6CC;AAuyBD,yCAqCC;AAmND;;;QAqEC;AAuQD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH;;UA+IC;AA/aD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,sCAwOC;AA0gDD;;;;;;;;GAQG;AACH,gCAHW,OAAO,GAAC,MAAM,MAAO,OAc/B;AAvBD,qEAAqE;AACrE,uBAA8D;AArlC9D;;;;;GAKG;AACH,0CA8DC;AA+ED;;;;GAIG;AACH,4CAQC;AAiCD;;;;;;;;;;;GAWG;AACH,2CAyDC;AAID,2EAA2E;AAC3E,sCAgEC;AAID;;;;GAIG;AACH,4CAyCC;AAID;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,2CAiDC;AAID;;;;;GAKG;AACH,4CAqBC;AAID;;;;;;GAMG;AACH,wCAmBC;AAID;;;;;GAKG;AACH,4CAiDC;AAoCD;;;;;GAKG;AACH,0CA8DC;AAwWD,uCAyBC;AA7XD;;;;;GAKG;AACH,8CAyEC;AA2ID;;;;GAIG;AACH,4CAyDC;AAqBD;;;;;GAKG;AACH,iDAgBC;AA/sCD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,+CAiFC;AAID;;;;;;;;;;;;;;;;GAgBG;AACH,kDAyFC"}
1
+ {"version":3,"file":"optimize.d.ts","sourceRoot":"","sources":["../../src/optimize.js"],"names":[],"mappings":"AAsxHA,gEA6FC;AA/zHD;;;;GAIG;AACH,4BAHW,GAAG,GACD,MAAM,CAOlB;AAED;;;;GAIG;AACH,wCAFa,MAAM,CAOlB;AA8CD;;;;;GAKG;AACH,6CAgJC;AAwUD;;;;GAIG;AACH,wCAkDC;AA0YD;;;;GAIG;AACH,4CAqBC;AA+CD;;;;;GAKG;AACH,8CAmDC;AAndD;;;;GAIG;AACH,4CASC;AAID;;;;GAIG;AACH,4CAwDC;AAID;;;;GAIG;AACH,0CA6CC;AAuyBD,yCAqCC;AAmND;;;QAqEC;AAuQD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH;;UA+IC;AA/aD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,sCAwOC;AA0gDD;;;;;;;;GAQG;AACH,gCAHW,OAAO,GAAC,MAAM,MAAO,OAc/B;AAvBD,qEAAqE;AACrE,uBAA8D;AArlC9D;;;;;GAKG;AACH,0CA8DC;AA+ED;;;;GAIG;AACH,4CAQC;AAiCD;;;;;;;;;;;GAWG;AACH,2CAyDC;AAID,2EAA2E;AAC3E,sCAgEC;AAID;;;;GAIG;AACH,4CAyCC;AAID;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,2CAiDC;AAID;;;;;GAKG;AACH,4CAqBC;AAID;;;;;;GAMG;AACH,wCAmBC;AAID;;;;;GAKG;AACH,4CAiDC;AAoCD;;;;;GAKG;AACH,0CA8DC;AAwWD,uCAyBC;AA7XD;;;;;GAKG;AACH,8CAyEC;AA2ID;;;;GAIG;AACH,4CAyDC;AAqBD;;;;;GAKG;AACH,iDAgBC;AA/sCD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,+CAiFC;AAID;;;;;;;;;;;;;;;;GAgBG;AACH,kDAyFC"}
@@ -1 +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"}
1
+ {"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../../src/template.js"],"names":[],"mappings":"AA8IA;;;;;;;;;;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"}
package/types/watr.d.ts CHANGED
@@ -17,18 +17,17 @@ export function watr(source: string | TemplateStringsArray, ...values: any[]): W
17
17
  *
18
18
  * @param {string|TemplateStringsArray} source - WAT source or template strings
19
19
  * @param {...any} values - Interpolation values (for template literal).
20
- * Last value can be an options object: { polyfill, optimize }.
21
20
  * @returns {Uint8Array} WebAssembly binary
22
21
  *
23
22
  * @example
24
23
  * compile('(func (export "f") (result i32) (i32.const 42))')
25
24
  * compile`(func (export "f") (result f64) (f64.const ${Math.PI}))`
26
- * compile(src, { polyfill: true, optimize: true })
25
+ * // transforms ship as separate entries — compose them:
26
+ * // import optimize from 'watr/optimize'
27
+ * // compile(optimize(src))
27
28
  */
28
29
  export function compile(source: string | TemplateStringsArray, ...values: any[]): Uint8Array;
29
30
  import parse from './src/parse.js';
30
31
  import print from './src/print.js';
31
- import _polyfill from './src/polyfill.js';
32
- import _optimize from './src/optimize.js';
33
- export { parse, print, _polyfill as polyfill, _optimize as optimize };
32
+ export { parse, print };
34
33
  //# sourceMappingURL=watr.d.ts.map
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"watr.d.ts","sourceRoot":"","sources":["../watr.js"],"names":[],"mappings":";AAoCA;;;;;;;;;;;GAWG;AACH,6BATW,MAAM,GAAC,oBAAoB,aACxB,GAAG,EAAA,GACJ,WAAW,CAAC,OAAO,CAS/B;AAhCD;;;;;;;;;;;;;GAaG;AACH,gCAXW,MAAM,GAAC,oBAAoB,aACxB,GAAG,EAAA,GACJ,UAAU,CAWtB;kBA3BiB,gBAAgB;kBAChB,gBAAgB"}
package/watr.js CHANGED
@@ -7,25 +7,28 @@
7
7
  import _compile from './src/compile.js'
8
8
  import parse from './src/parse.js'
9
9
  import print from './src/print.js'
10
- import _polyfill from './src/polyfill.js'
11
- import _optimize from './src/optimize.js'
12
10
  import { compile as _tcompile, watr as _twatr } from './src/template.js'
13
11
 
14
- /** JS-source backend primitives for the tagged-template layer. */
15
- const backend = { parse, compile: _compile, optimize: _optimize, polyfill: _polyfill }
12
+ /** JS-source backend primitives for the tagged-template layer.
13
+ * `polyfill` and `optimize` are intentionally NOT wired here they're heavy
14
+ * (the optimizer alone is ~5× the core encoder) and ship as separate entries,
15
+ * `watr/polyfill` and `watr/optimize`, that you compose explicitly:
16
+ * `compile(optimize(src))`. This keeps the default bundle minimal. */
17
+ const backend = { parse, compile: _compile }
16
18
 
17
19
  /**
18
20
  * Compile WAT to binary. Supports both string and template literal.
19
21
  *
20
22
  * @param {string|TemplateStringsArray} source - WAT source or template strings
21
23
  * @param {...any} values - Interpolation values (for template literal).
22
- * Last value can be an options object: { polyfill, optimize }.
23
24
  * @returns {Uint8Array} WebAssembly binary
24
25
  *
25
26
  * @example
26
27
  * compile('(func (export "f") (result i32) (i32.const 42))')
27
28
  * compile`(func (export "f") (result f64) (f64.const ${Math.PI}))`
28
- * compile(src, { polyfill: true, optimize: true })
29
+ * // transforms ship as separate entries — compose them:
30
+ * // import optimize from 'watr/optimize'
31
+ * // compile(optimize(src))
29
32
  */
30
33
  function compile(source, ...values) {
31
34
  return _tcompile(backend, source, values)
@@ -48,4 +51,4 @@ function watr(source, ...values) {
48
51
  }
49
52
 
50
53
  export default watr
51
- export { watr, compile, parse, print, _polyfill as polyfill, _optimize as optimize }
54
+ export { watr, compile, parse, print }