zyzz 0.0.32 → 0.0.34

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.
Files changed (41) hide show
  1. package/binding/compiler.wasm +0 -0
  2. package/binding/wasi/zyzz.wasm32-wasi.wasm +0 -0
  3. package/binding/zyzz.darwin-arm64.node +0 -0
  4. package/binding/zyzz.darwin-x64.node +0 -0
  5. package/binding/zyzz.linux-arm64-gnu.node +0 -0
  6. package/binding/zyzz.linux-arm64-musl.node +0 -0
  7. package/binding/zyzz.linux-x64-gnu.node +0 -0
  8. package/binding/zyzz.linux-x64-musl.node +0 -0
  9. package/binding/zyzz.win32-arm64-msvc.node +0 -0
  10. package/binding/zyzz.win32-x64-msvc.node +0 -0
  11. package/dist/binding/compiler.wasm +0 -0
  12. package/dist/compiler/internal/Modules.d.ts +33 -0
  13. package/dist/compiler/internal/Modules.d.ts.map +1 -0
  14. package/dist/compiler/internal/Modules.js +56 -0
  15. package/dist/compiler/internal/Modules.js.map +1 -0
  16. package/dist/compiler/internal/Results.d.ts +2 -26
  17. package/dist/compiler/internal/Results.d.ts.map +1 -1
  18. package/dist/compiler/internal/Results.js +4 -57
  19. package/dist/compiler/internal/Results.js.map +1 -1
  20. package/dist/compiler/wasm/Graph.d.ts +70 -0
  21. package/dist/compiler/wasm/Graph.d.ts.map +1 -0
  22. package/dist/compiler/wasm/Graph.js +70 -0
  23. package/dist/compiler/wasm/Graph.js.map +1 -0
  24. package/dist/compiler/wasm/index.d.ts +8 -0
  25. package/dist/compiler/wasm/index.d.ts.map +1 -0
  26. package/dist/compiler/wasm/index.js +8 -0
  27. package/dist/compiler/wasm/index.js.map +1 -0
  28. package/dist/internal/Wasm.d.ts +7 -5
  29. package/dist/internal/Wasm.d.ts.map +1 -1
  30. package/dist/internal/Wasm.js +19 -7
  31. package/dist/internal/Wasm.js.map +1 -1
  32. package/dist/vite/index.d.ts.map +1 -1
  33. package/dist/vite/index.js +22 -3
  34. package/dist/vite/index.js.map +1 -1
  35. package/package.json +11 -1
  36. package/src/compiler/internal/Modules.ts +94 -0
  37. package/src/compiler/internal/Results.ts +6 -91
  38. package/src/compiler/wasm/Graph.ts +178 -0
  39. package/src/compiler/wasm/index.ts +7 -0
  40. package/src/internal/Wasm.ts +22 -7
  41. package/src/vite/index.ts +31 -3
@@ -8,13 +8,13 @@ import * as Variants from '../../react-native/Variants.js'
8
8
  import * as Css from '../../web/Css.js'
9
9
  import * as ClassName from '../../web/internal/ClassName.js'
10
10
  import * as Engine from '../../web/internal/Engine.js'
11
- import * as ThemeRules from '../../web/internal/Themes.js'
12
11
  import * as Wire from '../../web/internal/Wire.js'
13
12
  import type * as Graph from '../Graph.js'
14
13
  import * as Native from '../Native.js'
15
14
  import * as Source from '../Source.js'
16
15
  import type * as Transform from '../Transform.js'
17
16
  import * as Edits from './Edits.js'
17
+ import * as Modules from './Modules.js'
18
18
  import * as Stylesheets from './Stylesheets.js'
19
19
 
20
20
  /** A failure as the engine encodes it. */
@@ -25,16 +25,6 @@ type Failure = {
25
25
  readonly source?: string | undefined
26
26
  }
27
27
 
28
- /** One module's transform output as the engine encodes it. */
29
- export type Module = Records & {
30
- readonly code: string
31
- readonly css: string
32
- readonly cssMap: Mapping.EncodedSourceMap
33
- readonly map: Transform.compile.ReturnType['map']
34
- readonly shared?: readonly ThemeRules.Resource[] | undefined
35
- readonly vars: Readonly<Record<string, string>>
36
- }
37
-
38
28
  /** One native graph module as the engine encodes it. */
39
29
  type NativeModule = {
40
30
  readonly code: string
@@ -50,13 +40,6 @@ export type NativeOutput = {
50
40
  readonly recipes: Readonly<Record<string, unknown>>
51
41
  }
52
42
 
53
- /** A module's class, rule, and unit records as the engine encodes them. */
54
- type Records = {
55
- readonly classes: Readonly<Record<string, string>>
56
- readonly rules: Readonly<Record<string, string>>
57
- readonly units: readonly (readonly [string, boolean, string])[]
58
- }
59
-
60
43
  /** One rendered stylesheet as the engine encodes it. */
61
44
  type Rendered = {
62
45
  readonly assets: Readonly<Record<string, string>>
@@ -73,7 +56,7 @@ type Rendered = {
73
56
  export type Output = {
74
57
  readonly contracts: Readonly<Record<string, string>>
75
58
  readonly dependencies: Readonly<Record<string, readonly string[]>>
76
- readonly modules: Readonly<Record<string, Module | NativeModule | 0>>
59
+ readonly modules: Readonly<Record<string, Modules.Encoded | NativeModule | 0>>
77
60
  readonly packed?: readonly Rendered[] | undefined
78
61
  readonly prune?: true | undefined
79
62
  readonly reset?: Rendered | undefined
@@ -116,10 +99,10 @@ export function transform(
116
99
  const split = text.indexOf('\0')
117
100
 
118
101
  // Failures write no records, and decoding throws them.
119
- if (split === -1) return module(decode<Module>(text), source)
102
+ if (split === -1) return Modules.decode(decode<Modules.Encoded>(text), source)
120
103
 
121
- return module(
122
- decode<Omit<Module, keyof Records>>(text.slice(0, split)),
104
+ return Modules.decode(
105
+ decode<Omit<Modules.Encoded, keyof Modules.Records>>(text.slice(0, split)),
123
106
  source,
124
107
  text.slice(split + 1),
125
108
  )
@@ -227,7 +210,7 @@ export function graph(
227
210
  if (encoded === 0) return decoded!.get(id)!
228
211
  if ('edits' in encoded) return nativeModule(encoded)
229
212
 
230
- return module(encoded)
213
+ return Modules.decode(encoded)
231
214
  })(),
232
215
  ]),
233
216
  )
@@ -281,74 +264,6 @@ export function graph(
281
264
  /** Graph option for hosts that read module code, stylesheets, and configuration catalogs only. */
282
265
  export const lean = Symbol('lean graph output')
283
266
 
284
- /**
285
- * Rebuilds one module's frozen transform output. Records decode when first read, so a module
286
- * whose classes, rules, and units are never read skips their parsing.
287
- * @param value - The encoded module, with its records unless `records` holds them.
288
- * @param source - Module text the engine left out of the maps' `sourcesContent`.
289
- * @param records - The encoded records, which `transform.compile` writes apart.
290
- * @returns The output `Transform.compile` returns.
291
- */
292
- export function module(
293
- value: Omit<Module, keyof Records> & Partial<Records>,
294
- source?: string | undefined,
295
- records?: string | undefined,
296
- ): Transform.compile.ReturnType {
297
- // The engine writes `0` for content the caller supplied separately, so it crosses once.
298
- if (source !== undefined)
299
- for (const map of [value.cssMap, value.map]) {
300
- const contents = map.sourcesContent as (string | null | 0)[] | undefined
301
-
302
- for (let index = 0; index < (contents?.length ?? 0); index++)
303
- if (contents![index] === 0) contents![index] = source
304
- }
305
-
306
- let decoded: Records | undefined =
307
- records === undefined ? (value as Records) : undefined
308
- let classes: Transform.compile.ReturnType['classes'] | undefined
309
- let rules: Transform.compile.ReturnType[typeof ClassName.rules] | undefined
310
- let units: Transform.compile.ReturnType[typeof ClassName.units] | undefined
311
- const read = () => (decoded ??= JSON.parse(records!) as Records)
312
-
313
- const result = {
314
- ...(value.shared
315
- ? {
316
- [ThemeRules.shared]: Object.freeze(
317
- value.shared.map((resource) => Object.freeze(resource)),
318
- ),
319
- }
320
- : {}),
321
- // Parsed records are fresh, so they freeze in place rather than as copies.
322
- get classes() {
323
- return (classes ??= Object.freeze(read().classes))
324
- },
325
- code: value.code,
326
- css: value.css,
327
- cssMap: value.cssMap,
328
- map: value.map,
329
- vars: Object.freeze(Object.setPrototypeOf(value.vars, null)),
330
- }
331
-
332
- Object.defineProperties(result, {
333
- [ClassName.rules]: {
334
- enumerable: false,
335
- get: () => (rules ??= Object.freeze(read().rules)),
336
- },
337
- [ClassName.units]: {
338
- enumerable: false,
339
- get: () =>
340
- (units ??= new Map(
341
- read().units.map(([key, borrowed, name]) => [
342
- key,
343
- { borrowed, name },
344
- ]),
345
- )),
346
- },
347
- })
348
-
349
- return Object.freeze(result) as Transform.compile.ReturnType
350
- }
351
-
352
267
  /**
353
268
  * Encodes native options as the engine reads them. Sets are written in the `Css.compile` wire
354
269
  * format, so the engine decodes them as it decodes literal definitions.
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Compiles source graphs in the WebAssembly compiler, for browsers and workers without the native
3
+ * addon. The host loads the module, and compilation reads no files and imports no Node built-ins.
4
+ * @module
5
+ */
6
+ import type * as Css from '../../web/Css.js'
7
+ import * as Wasm from '../../internal/Wasm.js'
8
+ import type * as Graph from '../Graph.js'
9
+ import * as Modules from '../internal/Modules.js'
10
+ import type * as Source from '../Source.js'
11
+
12
+ /** A failure as the engine encodes it. */
13
+ type Failure = {
14
+ readonly diagnostics?: readonly CompileError.Diagnostic[] | undefined
15
+ readonly message: string
16
+ readonly name: string
17
+ }
18
+
19
+ /** A web graph result as the engine encodes it. */
20
+ type Output = {
21
+ readonly contracts: Readonly<Record<string, string>>
22
+ readonly dependencies: Readonly<Record<string, readonly string[]>>
23
+ readonly modules: Readonly<Record<string, Modules.Encoded>>
24
+ readonly shared?: Shared | undefined
25
+ }
26
+
27
+ /** Shared contributions and responsive token defaults as the engine encodes them. */
28
+ type Shared = {
29
+ readonly assets: Readonly<Record<string, string>>
30
+ readonly css: string
31
+ readonly map: NonNullable<Graph.compile.ReturnType['sharedCssMap']>
32
+ readonly owners: Readonly<Record<string, string>>
33
+ }
34
+
35
+ /** Contracts of one web graph compilation. */
36
+ export declare namespace compile {
37
+ /** Failures the compiler reports, and a trap of the WebAssembly module. */
38
+ type ErrorType = CompileError | Wasm.TrapError
39
+ /** The web options of `Graph.compile` from `zyzz/compiler`. */
40
+ type Options = Pick<
41
+ Graph.compile.Options,
42
+ | 'compiler'
43
+ | 'composition'
44
+ | 'contracts'
45
+ | 'cssOutput'
46
+ | 'development'
47
+ | 'imports'
48
+ | 'modules'
49
+ >
50
+ /** The output of `Graph.compile` from `zyzz/compiler` for the same options. */
51
+ type ReturnType = Graph.compile.ReturnType
52
+ }
53
+
54
+ /**
55
+ * A graph the compiler rejects. `failure` names the error that `Graph.compile` from
56
+ * `zyzz/compiler` throws for the same input, and the message matches it.
57
+ */
58
+ export class CompileError extends Error {
59
+ /** Freezes the reported diagnostics in the compiler's reporting order. */
60
+ constructor(options: CompileError.Options) {
61
+ super(options.message)
62
+ this.diagnostics = Object.freeze(
63
+ options.diagnostics.map((item) => Object.freeze({ ...item })),
64
+ )
65
+ this.failure = options.failure
66
+ }
67
+ /** Source and CSS failures. Empty when the failure has no location, such as a missing import. */
68
+ readonly diagnostics: readonly CompileError.Diagnostic[]
69
+ /** Error name the native compiler reports, such as `Source.ExtractError` or `Css.CompileError`. */
70
+ readonly failure: string
71
+ /** Stable namespaced error identifier. */
72
+ override name = 'Graph.CompileError'
73
+ }
74
+
75
+ /** Compile error contracts. */
76
+ export declare namespace CompileError {
77
+ /** A source extraction or CSS compilation diagnostic. */
78
+ type Diagnostic = Css.Diagnostic | Source.Diagnostic
79
+ /** The failure the compiler reports. */
80
+ type Options = {
81
+ /** Source and CSS failures, in the compiler's reporting order. */
82
+ readonly diagnostics: readonly Diagnostic[]
83
+ /** Error name the native compiler reports. */
84
+ readonly failure: string
85
+ /** The native error's message. */
86
+ readonly message: string
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Instantiates the compiler from the `zyzz/compiler.wasm` module, which the host loads as an
92
+ * asset. Each compilation is independent, as `Graph.compile` from `zyzz/compiler` is.
93
+ * @param options - The WebAssembly module, compiled or as bytes.
94
+ * @returns A compiler that owns one WebAssembly instance.
95
+ */
96
+ export function create(options: create.Options): create.ReturnType {
97
+ const engine = Wasm.instantiate(options.module)
98
+
99
+ return Object.freeze({
100
+ compile(options: compile.Options): compile.ReturnType {
101
+ const output = JSON.parse(
102
+ engine.call(
103
+ 'graph.compile',
104
+ JSON.stringify({
105
+ compiler: options.compiler,
106
+ composition: options.composition,
107
+ contracts: options.contracts,
108
+ cssOutput: options.cssOutput,
109
+ development: options.development,
110
+ imports: options.imports,
111
+ modules: options.modules,
112
+ }),
113
+ ),
114
+ ) as Output & { readonly error?: Failure | undefined }
115
+
116
+ if (output.error)
117
+ throw new CompileError({
118
+ diagnostics: output.error.diagnostics ?? [],
119
+ failure: output.error.name,
120
+ message: output.error.message,
121
+ })
122
+
123
+ // Keys follow the order `Graph.compile` from `zyzz/compiler` writes, so both outputs
124
+ // serialize identically.
125
+ return Object.freeze({
126
+ ...(output.shared
127
+ ? {
128
+ sharedCss: output.shared.css,
129
+ sharedCssMap: output.shared.map,
130
+ sharedAssets: Object.freeze(
131
+ Object.assign(Object.create(null), output.shared.assets),
132
+ ),
133
+ sharedAssetOwners: Object.freeze(
134
+ Object.assign(Object.create(null), output.shared.owners),
135
+ ),
136
+ }
137
+ : {}),
138
+ contracts: Object.freeze({ ...output.contracts }),
139
+ dependencies: Object.freeze(
140
+ Object.assign(
141
+ Object.create(null),
142
+ Object.fromEntries(
143
+ Object.entries(output.dependencies).map((entry) => [
144
+ entry[0],
145
+ Object.freeze([...entry[1]]),
146
+ ]),
147
+ ),
148
+ ),
149
+ ),
150
+ modules: Object.freeze(
151
+ Object.fromEntries(
152
+ Object.entries(output.modules).map((entry) => [
153
+ entry[0],
154
+ Modules.decode(entry[1]),
155
+ ]),
156
+ ),
157
+ ),
158
+ }) as compile.ReturnType
159
+ },
160
+ })
161
+ }
162
+
163
+ /** WebAssembly compiler contracts. */
164
+ export declare namespace create {
165
+ /** The compiler module. */
166
+ type Options = {
167
+ /**
168
+ * The `zyzz/compiler.wasm` module. Bytes compile synchronously, which Cloudflare Workers
169
+ * forbid and browsers limit on the main thread, so those hosts pass a compiled module.
170
+ */
171
+ readonly module: BufferSource | WebAssembly.Module
172
+ }
173
+ /** A compiler that owns one WebAssembly instance and its memory. */
174
+ type ReturnType = {
175
+ /** Compiles one complete web graph snapshot. */
176
+ readonly compile: (options: compile.Options) => compile.ReturnType
177
+ }
178
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Exposes source graph compilation in the WebAssembly compiler, for browsers and workers without
3
+ * the native addon. The host loads the module from `zyzz/compiler.wasm`.
4
+ * @module
5
+ */
6
+ /** Web graph compilation in a host-loaded WebAssembly compiler. */
7
+ export * as Graph from './Graph.js'
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Instantiates the WebAssembly compiler synchronously from its bytes, for hosts without the native addon.
2
+ * Instantiates the WebAssembly compiler synchronously, for hosts without the native addon.
3
3
  * @module
4
4
  */
5
5
 
@@ -28,13 +28,20 @@ export class TrapError extends Error {
28
28
  }
29
29
 
30
30
  /**
31
- * Compiles and instantiates the module without awaiting, so synchronous APIs can call it.
32
- * A trap leaves Rust state undefined, so the next call starts a fresh instance.
33
- * @param bytes - The `crates/wasm` module.
31
+ * Instantiates the module without awaiting, so synchronous APIs can call it. Bytes compile
32
+ * synchronously first. Hosts that forbid runtime compilation, such as Cloudflare Workers, pass
33
+ * a compiled module instead. A trap leaves Rust state undefined, so the next call starts a
34
+ * fresh instance.
35
+ * @param source - The `crates/wasm` module, compiled or as bytes.
34
36
  * @returns The instance's operations.
35
37
  */
36
- export function instantiate(bytes: BufferSource): Instance {
37
- const module = new WebAssembly.Module(bytes)
38
+ export function instantiate(
39
+ source: BufferSource | WebAssembly.Module,
40
+ ): Instance {
41
+ const module =
42
+ source instanceof WebAssembly.Module
43
+ ? source
44
+ : new WebAssembly.Module(source)
38
45
  const encoder = new TextEncoder()
39
46
  const decoder = new TextDecoder()
40
47
  let exports: Exports | undefined
@@ -42,7 +49,8 @@ export function instantiate(bytes: BufferSource): Instance {
42
49
 
43
50
  function start(): Exports {
44
51
  stderr = ''
45
- // The reactor reads no files, clock, or environment. WASI output only carries panic messages.
52
+ // The reactor reads no files, clock, or environment. Parser dependencies seed internal hash
53
+ // tables with entropy, but emitted class identities use the compiler's deterministic hashes.
46
54
  const wasi = {
47
55
  environ_get: () => 0,
48
56
  environ_sizes_get: (count: number, size: number) => {
@@ -67,6 +75,13 @@ export function instantiate(bytes: BufferSource): Instance {
67
75
  proc_exit: (code: number) => {
68
76
  throw new TrapError(`WebAssembly compiler exited with code ${code}.`)
69
77
  },
78
+ random_get: (pointer: number, length: number) => {
79
+ const bytes = new Uint8Array(exports!.memory.buffer, pointer, length)
80
+ // Web Crypto limits each request to 65,536 bytes.
81
+ for (let offset = 0; offset < length; offset += 65536)
82
+ crypto.getRandomValues(bytes.subarray(offset, offset + 65536))
83
+ return 0
84
+ },
70
85
  }
71
86
  const instance = new WebAssembly.Instance(module, {
72
87
  wasi_snapshot_preview1: wasi,
package/src/vite/index.ts CHANGED
@@ -340,7 +340,9 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
340
340
  return (
341
341
  query !== undefined &&
342
342
  [...new URLSearchParams(query).keys()].some(
343
- (key) => !['v', 't', 'import'].includes(key),
343
+ // TanStack splits fresh physical source after pre-transforms, not the
344
+ // transformed route. Compile these requests under the same source identity.
345
+ (key) => !['import', 't', 'tsr-split', 'v'].includes(key),
344
346
  )
345
347
  )
346
348
  }
@@ -946,7 +948,17 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
946
948
  }
947
949
 
948
950
  const resolved = await resolve(specifier, file)
949
- if (!resolved)
951
+ if (!resolved) {
952
+ // Framework transforms can remove server-only protocols from client code.
953
+ // Resolve first so aliases and plugins can still supply analyzable source.
954
+ if (
955
+ !Path.isAbsolute(specifier) &&
956
+ /^[a-z][a-z\d+.-]*:/i.test(specifier)
957
+ ) {
958
+ resolutions[specifier] = null
959
+ continue
960
+ }
961
+
950
962
  throw new Source.ExtractError([
951
963
  {
952
964
  code: 'unsupported_syntax',
@@ -956,6 +968,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
956
968
  start: node.start,
957
969
  },
958
970
  ])
971
+ }
959
972
 
960
973
  if (resource(specifier) || resource(resolved.id)) {
961
974
  resolutions[specifier] = null
@@ -2278,6 +2291,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
2278
2291
  if (id.startsWith(prefix)) return id
2279
2292
  },
2280
2293
  async transform(code, id) {
2294
+ const split = new URLSearchParams(id.split('?')[1]).has('tsr-split')
2281
2295
  id = normalize(id)
2282
2296
 
2283
2297
  if (!eligible(id)) return
@@ -2340,7 +2354,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
2340
2354
  ? ''
2341
2355
  : `\nimport ${JSON.stringify(cssId(id))};`
2342
2356
 
2343
- return {
2357
+ const transformed = {
2344
2358
  code: `${before}${sharedImport}${output.code.slice(offset)}${stylesheetImport}`,
2345
2359
  map: JSON.stringify({
2346
2360
  ...output.map,
@@ -2351,6 +2365,20 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
2351
2365
  ),
2352
2366
  }),
2353
2367
  }
2368
+
2369
+ if (split) {
2370
+ // TanStack's dead-code elimination does not track TypeScript namespace
2371
+ // bindings. Lower them before splitting, leaving JSX for the framework plugin.
2372
+ const { transformWithOxc } = await import('vite')
2373
+ return transformWithOxc(
2374
+ transformed.code,
2375
+ id,
2376
+ { jsx: 'preserve' },
2377
+ JSON.parse(transformed.map),
2378
+ )
2379
+ }
2380
+
2381
+ return transformed
2354
2382
  },
2355
2383
  transformIndexHtml: {
2356
2384
  order: 'post',