pywire 0.1.1__py3-none-any.whl → 0.1.2__py3-none-any.whl

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 (101) hide show
  1. pywire/__init__.py +2 -0
  2. pywire/cli/__init__.py +1 -0
  3. pywire/cli/generators.py +48 -0
  4. pywire/cli/main.py +309 -0
  5. pywire/cli/tui.py +563 -0
  6. pywire/cli/validate.py +26 -0
  7. pywire/client/.prettierignore +8 -0
  8. pywire/client/.prettierrc +7 -0
  9. pywire/client/build.mjs +73 -0
  10. pywire/client/eslint.config.js +46 -0
  11. pywire/client/package.json +39 -0
  12. pywire/client/pnpm-lock.yaml +2971 -0
  13. pywire/client/src/core/app.ts +263 -0
  14. pywire/client/src/core/dom-updater.test.ts +78 -0
  15. pywire/client/src/core/dom-updater.ts +321 -0
  16. pywire/client/src/core/index.ts +5 -0
  17. pywire/client/src/core/transport-manager.test.ts +179 -0
  18. pywire/client/src/core/transport-manager.ts +159 -0
  19. pywire/client/src/core/transports/base.ts +122 -0
  20. pywire/client/src/core/transports/http.ts +142 -0
  21. pywire/client/src/core/transports/index.ts +13 -0
  22. pywire/client/src/core/transports/websocket.ts +97 -0
  23. pywire/client/src/core/transports/webtransport.ts +149 -0
  24. pywire/client/src/dev/dev-app.ts +93 -0
  25. pywire/client/src/dev/error-trace.test.ts +97 -0
  26. pywire/client/src/dev/error-trace.ts +76 -0
  27. pywire/client/src/dev/index.ts +4 -0
  28. pywire/client/src/dev/status-overlay.ts +63 -0
  29. pywire/client/src/events/handler.test.ts +318 -0
  30. pywire/client/src/events/handler.ts +454 -0
  31. pywire/client/src/pywire.core.ts +22 -0
  32. pywire/client/src/pywire.dev.ts +27 -0
  33. pywire/client/tsconfig.json +17 -0
  34. pywire/client/vitest.config.ts +15 -0
  35. pywire/compiler/__init__.py +6 -0
  36. pywire/compiler/ast_nodes.py +304 -0
  37. pywire/compiler/attributes/__init__.py +6 -0
  38. pywire/compiler/attributes/base.py +24 -0
  39. pywire/compiler/attributes/conditional.py +37 -0
  40. pywire/compiler/attributes/events.py +55 -0
  41. pywire/compiler/attributes/form.py +37 -0
  42. pywire/compiler/attributes/loop.py +75 -0
  43. pywire/compiler/attributes/reactive.py +34 -0
  44. pywire/compiler/build.py +28 -0
  45. pywire/compiler/build_artifacts.py +342 -0
  46. pywire/compiler/codegen/__init__.py +5 -0
  47. pywire/compiler/codegen/attributes/__init__.py +6 -0
  48. pywire/compiler/codegen/attributes/base.py +19 -0
  49. pywire/compiler/codegen/attributes/events.py +35 -0
  50. pywire/compiler/codegen/directives/__init__.py +6 -0
  51. pywire/compiler/codegen/directives/base.py +16 -0
  52. pywire/compiler/codegen/directives/path.py +53 -0
  53. pywire/compiler/codegen/generator.py +2341 -0
  54. pywire/compiler/codegen/template.py +2178 -0
  55. pywire/compiler/directives/__init__.py +7 -0
  56. pywire/compiler/directives/base.py +20 -0
  57. pywire/compiler/directives/component.py +33 -0
  58. pywire/compiler/directives/context.py +93 -0
  59. pywire/compiler/directives/layout.py +49 -0
  60. pywire/compiler/directives/no_spa.py +24 -0
  61. pywire/compiler/directives/path.py +71 -0
  62. pywire/compiler/directives/props.py +88 -0
  63. pywire/compiler/exceptions.py +19 -0
  64. pywire/compiler/interpolation/__init__.py +6 -0
  65. pywire/compiler/interpolation/base.py +28 -0
  66. pywire/compiler/interpolation/jinja.py +272 -0
  67. pywire/compiler/parser.py +750 -0
  68. pywire/compiler/paths.py +29 -0
  69. pywire/compiler/preprocessor.py +43 -0
  70. pywire/core/wire.py +119 -0
  71. pywire/py.typed +0 -0
  72. pywire/runtime/__init__.py +7 -0
  73. pywire/runtime/aioquic_server.py +194 -0
  74. pywire/runtime/app.py +901 -0
  75. pywire/runtime/compile_error_page.py +195 -0
  76. pywire/runtime/debug.py +203 -0
  77. pywire/runtime/dev_server.py +434 -0
  78. pywire/runtime/dev_server.py.broken +268 -0
  79. pywire/runtime/error_page.py +64 -0
  80. pywire/runtime/error_renderer.py +23 -0
  81. pywire/runtime/escape.py +23 -0
  82. pywire/runtime/files.py +40 -0
  83. pywire/runtime/helpers.py +97 -0
  84. pywire/runtime/http_transport.py +253 -0
  85. pywire/runtime/loader.py +272 -0
  86. pywire/runtime/logging.py +72 -0
  87. pywire/runtime/page.py +384 -0
  88. pywire/runtime/pydantic_integration.py +52 -0
  89. pywire/runtime/router.py +229 -0
  90. pywire/runtime/server.py +25 -0
  91. pywire/runtime/style_collector.py +31 -0
  92. pywire/runtime/upload_manager.py +76 -0
  93. pywire/runtime/validation.py +449 -0
  94. pywire/runtime/websocket.py +665 -0
  95. pywire/runtime/webtransport_handler.py +195 -0
  96. {pywire-0.1.1.dist-info → pywire-0.1.2.dist-info}/METADATA +1 -1
  97. pywire-0.1.2.dist-info/RECORD +104 -0
  98. pywire-0.1.1.dist-info/RECORD +0 -9
  99. {pywire-0.1.1.dist-info → pywire-0.1.2.dist-info}/WHEEL +0 -0
  100. {pywire-0.1.1.dist-info → pywire-0.1.2.dist-info}/entry_points.txt +0 -0
  101. {pywire-0.1.1.dist-info → pywire-0.1.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,454 @@
1
+ import { PyWireApp } from '../core/app'
2
+ import { DOMUpdater } from '../core/dom-updater'
3
+ import { EventData } from '../core/transports'
4
+
5
+ // Type alias for backward compatibility
6
+ type Application = PyWireApp
7
+
8
+ export class UnifiedEventHandler {
9
+ private app: Application
10
+ private debouncers = new Map<string, number>()
11
+ private throttlers = new Map<string, number>()
12
+
13
+ private supportedEvents = [
14
+ 'click',
15
+ 'submit',
16
+ 'input',
17
+ 'change',
18
+ 'keydown',
19
+ 'keyup',
20
+ 'focus',
21
+ 'blur',
22
+ 'mouseenter',
23
+ 'mouseleave',
24
+ 'scroll',
25
+ 'contextmenu',
26
+ ]
27
+
28
+ // Events that should be suppressed during DOM updates to prevent loops
29
+ private suppressDuringUpdate = ['focus', 'blur', 'mouseenter', 'mouseleave']
30
+
31
+ constructor(app: Application) {
32
+ this.app = app
33
+ }
34
+
35
+ private debugLog(...args: unknown[]): void {
36
+ if (this.app.getConfig().debug) {
37
+ console.log(...args)
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Initialize global event listeners.
43
+ * Uses event delegation on document body.
44
+ */
45
+ init(): void {
46
+ this.supportedEvents.forEach((eventType) => {
47
+ const options =
48
+ eventType === 'mouseenter' ||
49
+ eventType === 'mouseleave' ||
50
+ eventType === 'focus' ||
51
+ eventType === 'blur' ||
52
+ eventType === 'scroll'
53
+ ? { capture: true } // These don't bubble nicely or at all in some cases
54
+ : undefined
55
+
56
+ document.addEventListener(eventType, (e) => this.handleEvent(e), options)
57
+ })
58
+ }
59
+
60
+ /**
61
+ * Helper to parse handlers from element (legacy or multiple/JSON).
62
+ */
63
+ private getHandlers(
64
+ element: HTMLElement,
65
+ eventType: string
66
+ ): Array<{ name: string; modifiers: string[]; args?: unknown[] }> {
67
+ const handlerAttr = `data-on-${eventType}`
68
+ const attrValue = element.getAttribute(handlerAttr)
69
+ if (!attrValue) return []
70
+
71
+ if (attrValue.trim().startsWith('[')) {
72
+ try {
73
+ const handlers = JSON.parse(attrValue) as unknown
74
+ if (Array.isArray(handlers)) {
75
+ return handlers.flatMap((handler) => {
76
+ if (!handler || typeof handler !== 'object') return []
77
+ const name =
78
+ 'handler' in handler && typeof handler.handler === 'string' ? handler.handler : null
79
+ if (!name) return []
80
+
81
+ const modifiers =
82
+ 'modifiers' in handler && Array.isArray(handler.modifiers)
83
+ ? handler.modifiers.filter((m: unknown): m is string => typeof m === 'string')
84
+ : []
85
+
86
+ const args = 'args' in handler && Array.isArray(handler.args) ? handler.args : undefined
87
+
88
+ return [{ name, modifiers, args }]
89
+ })
90
+ }
91
+ } catch (e) {
92
+ console.error('Error parsing event handlers:', e)
93
+ }
94
+ } else {
95
+ // Legacy single handler
96
+ const modifiersAttr = element.getAttribute(`data-modifiers-${eventType}`)
97
+ const modifiers = modifiersAttr ? modifiersAttr.split(' ').filter((m) => m) : []
98
+ return [{ name: attrValue, modifiers, args: undefined }]
99
+ }
100
+ return []
101
+ }
102
+
103
+ /**
104
+ * Main event handler.
105
+ */
106
+ private async handleEvent(e: Event): Promise<void> {
107
+ const eventType = e.type
108
+
109
+ // Skip focus/blur/mouseenter/mouseleave events during DOM updates to prevent loops
110
+ if (DOMUpdater.isUpdating && this.suppressDuringUpdate.includes(eventType)) {
111
+ this.debugLog(
112
+ '[Handler] SUPPRESSING event during update:',
113
+ eventType,
114
+ 'isUpdating=',
115
+ DOMUpdater.isUpdating
116
+ )
117
+ return
118
+ }
119
+
120
+ this.debugLog('[Handler] Processing event:', eventType, 'isUpdating=', DOMUpdater.isUpdating)
121
+
122
+ // 1. Delegated handlers (standard path walk with bubbling)
123
+ const path = e.composedPath ? e.composedPath() : []
124
+ let propagationStopped = false
125
+
126
+ for (const node of path) {
127
+ if (propagationStopped) break
128
+
129
+ if (node instanceof HTMLElement) {
130
+ const element = node
131
+ const handlers = this.getHandlers(element, eventType)
132
+
133
+ if (handlers.length > 0) {
134
+ this.debugLog('[handleEvent] Found handlers on', element.tagName, handlers)
135
+
136
+ for (const h of handlers) {
137
+ // Skip if it's a .window or .outside handler - those are handled globally
138
+ if (!h.modifiers.includes('window') && !h.modifiers.includes('outside')) {
139
+ this.processEvent(element, eventType, h.name, h.modifiers, e, h.args)
140
+ if (e.cancelBubble) propagationStopped = true
141
+ }
142
+ }
143
+ }
144
+ }
145
+ }
146
+
147
+ // 2. Global handlers (.window, .outside)
148
+ this.handleGlobalEvent(e)
149
+ }
150
+
151
+ /**
152
+ * Handle modifiers that listen outside the normal delegation path.
153
+ */
154
+ private handleGlobalEvent(e: Event): void {
155
+ const eventType = e.type
156
+ const windowSelector = `[data-modifiers-${eventType}*="window"]`
157
+ const outsideSelector = `[data-modifiers-${eventType}*="outside"]`
158
+
159
+ const candidates = document.querySelectorAll(`${windowSelector}, ${outsideSelector}`)
160
+
161
+ candidates.forEach((el) => {
162
+ if (!(el instanceof HTMLElement)) return
163
+
164
+ const handlers = this.getHandlers(el, eventType)
165
+ for (const h of handlers) {
166
+ // .window: trigger regardless of where the event happened
167
+ if (h.modifiers.includes('window')) {
168
+ this.processEvent(el, eventType, h.name, h.modifiers, e, h.args)
169
+ }
170
+
171
+ // .outside: trigger if target is NOT inside this element
172
+ if (h.modifiers.includes('outside')) {
173
+ const target = e.target as Node | null
174
+ if (target && !el.contains(target)) {
175
+ this.processEvent(el, eventType, h.name, h.modifiers, e, h.args)
176
+ }
177
+ }
178
+ }
179
+ })
180
+ }
181
+
182
+ /**
183
+ * Process an event for a specific element after it has been matched.
184
+ */
185
+ private processEvent(
186
+ element: HTMLElement,
187
+ eventType: string,
188
+ handlerName: string,
189
+ modifiers: string[],
190
+ e: Event,
191
+ explicitArgs?: unknown[]
192
+ ): void {
193
+ this.debugLog('[processEvent]', eventType, 'handler:', handlerName, 'modifiers:', modifiers)
194
+
195
+ // --- 1. Logic Modifers ---
196
+
197
+ // .prevent
198
+ if (modifiers.includes('prevent') || eventType === 'submit') {
199
+ this.debugLog('[processEvent] Calling preventDefault')
200
+ e.preventDefault()
201
+ }
202
+
203
+ // .stop
204
+ if (modifiers.includes('stop')) {
205
+ e.stopPropagation()
206
+ }
207
+
208
+ // .self
209
+ if (modifiers.includes('self')) {
210
+ if (e.target !== element) return
211
+ }
212
+
213
+ // --- 2. Filter Modifiers ---
214
+
215
+ // System modifiers (Shift, Ctrl, Alt, Meta) - supported on Keyboard and Mouse events
216
+ if (modifiers.includes('shift') && (!('shiftKey' in e) || !e.shiftKey)) return
217
+ if (modifiers.includes('ctrl') && (!('ctrlKey' in e) || !e.ctrlKey)) return
218
+ if (modifiers.includes('alt') && (!('altKey' in e) || !e.altKey)) return
219
+ if (modifiers.includes('meta') && (!('metaKey' in e) || !e.metaKey)) return
220
+ if (modifiers.includes('cmd') && (!('metaKey' in e) || !e.metaKey)) return
221
+
222
+ if (e instanceof KeyboardEvent) {
223
+ // Known key modifiers
224
+ const knownKeys = ['enter', 'escape', 'space', 'tab', 'up', 'down', 'left', 'right']
225
+ // System modifiers that should NOT be treated as key constraints
226
+ const systemMods = [
227
+ 'shift',
228
+ 'ctrl',
229
+ 'alt',
230
+ 'meta',
231
+ 'cmd',
232
+ 'window',
233
+ 'outside',
234
+ 'prevent',
235
+ 'stop',
236
+ 'self',
237
+ 'debounce',
238
+ 'throttle',
239
+ ]
240
+
241
+ // Key modifiers are anything that's not a system mod and is either a known key or a single character
242
+ const keyModifiers = modifiers.filter((m) => {
243
+ if (systemMods.includes(m)) return false
244
+ if (m.startsWith('debounce') || m.startsWith('throttle')) return false
245
+ if (m.endsWith('ms')) return false // Duration like 500ms
246
+ return knownKeys.includes(m) || m.length === 1
247
+ })
248
+
249
+ if (keyModifiers.length > 0) {
250
+ const pressedKey = e.key.toLowerCase()
251
+ this.debugLog('[processEvent] Key check. Pressed:', pressedKey, 'Modifiers:', keyModifiers)
252
+
253
+ // Map for special keys
254
+ const keyMap: Record<string, string> = {
255
+ escape: 'escape',
256
+ esc: 'escape',
257
+ enter: 'enter',
258
+ space: ' ',
259
+ spacebar: ' ',
260
+ ' ': ' ',
261
+ tab: 'tab',
262
+ up: 'arrowup',
263
+ arrowup: 'arrowup',
264
+ down: 'arrowdown',
265
+ arrowdown: 'arrowdown',
266
+ left: 'arrowleft',
267
+ arrowleft: 'arrowleft',
268
+ right: 'arrowright',
269
+ arrowright: 'arrowright',
270
+ }
271
+
272
+ // Normalize the pressed key
273
+ const normalizedPressedKey = keyMap[pressedKey] || pressedKey
274
+
275
+ // Check if any key constraint matches
276
+ let match = false
277
+ for (const constraint of keyModifiers) {
278
+ const targetKey = keyMap[constraint] || constraint
279
+ this.debugLog(
280
+ '[processEvent] Comparing constraint:',
281
+ constraint,
282
+ '->',
283
+ targetKey,
284
+ 'vs',
285
+ normalizedPressedKey,
286
+ 'code:',
287
+ e.code
288
+ )
289
+
290
+ // Match against key (normalized)
291
+ if (targetKey === normalizedPressedKey) {
292
+ match = true
293
+ break
294
+ }
295
+
296
+ // Fallback: match against code (e.g. 'h' matches 'KeyH')
297
+ // This handles cases where modifiers change the key value (e.g. Alt+H -> ˙)
298
+ if (e.code && e.code.toLowerCase() === `key${targetKey}`) {
299
+ match = true
300
+ break
301
+ }
302
+ }
303
+ if (!match) {
304
+ this.debugLog('[processEvent] No key match found.')
305
+ return
306
+ }
307
+ }
308
+ }
309
+
310
+ // --- 3. Performance Modifiers ---
311
+ const debounceMod = modifiers.find((m) => m.startsWith('debounce'))
312
+ const throttleMod = modifiers.find((m) => m.startsWith('throttle'))
313
+
314
+ const elementId = element.id || this.getUniqueId(element)
315
+ const eventKey = `${elementId}-${eventType}-${handlerName}`
316
+
317
+ if (debounceMod) {
318
+ const duration = this.parseDuration(modifiers, 250)
319
+
320
+ if (this.debouncers.has(eventKey)) {
321
+ window.clearTimeout(this.debouncers.get(eventKey))
322
+ }
323
+
324
+ const timer = window.setTimeout(() => {
325
+ this.debouncers.delete(eventKey)
326
+ this.dispatchEvent(element, eventType, handlerName, e, explicitArgs)
327
+ }, duration)
328
+
329
+ this.debouncers.set(eventKey, timer)
330
+ return
331
+ }
332
+
333
+ if (throttleMod) {
334
+ const duration = this.parseDuration(modifiers, 250)
335
+ if (this.throttlers.has(eventKey)) return
336
+
337
+ this.throttlers.set(eventKey, Date.now())
338
+ // Execute immediately
339
+ this.dispatchEvent(element, eventType, handlerName, e, explicitArgs)
340
+
341
+ window.setTimeout(() => {
342
+ this.throttlers.delete(eventKey)
343
+ }, duration)
344
+ return
345
+ }
346
+
347
+ // Direct dispatch
348
+ this.dispatchEvent(element, eventType, handlerName, e, explicitArgs)
349
+ }
350
+
351
+ /**
352
+ * Extract data and send event.
353
+ */
354
+ private dispatchEvent(
355
+ element: HTMLElement,
356
+ eventType: string,
357
+ handler: string,
358
+ e: Event,
359
+ explicitArgs?: unknown[]
360
+ ): void {
361
+ // Merge explicit args (from JSON) into args payload
362
+ let args: Record<string, unknown> = {}
363
+ if (explicitArgs && explicitArgs.length > 0) {
364
+ explicitArgs.forEach((val, i) => {
365
+ args[`arg${i}`] = val
366
+ })
367
+ } else {
368
+ args = this.getArgs(element)
369
+ }
370
+
371
+ const eventData: EventData = {
372
+ type: eventType,
373
+ id: element.id,
374
+ args: args,
375
+ }
376
+
377
+ // Extract specific data based on element type
378
+ if (element instanceof HTMLInputElement) {
379
+ eventData.value = element.value
380
+ if (element.type === 'checkbox' || element.type === 'radio') {
381
+ eventData.checked = element.checked
382
+ }
383
+ } else if (element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement) {
384
+ eventData.value = element.value
385
+ }
386
+
387
+ // Extract Key data
388
+ if (e instanceof KeyboardEvent) {
389
+ eventData.key = e.key
390
+ eventData.keyCode = e.keyCode
391
+ }
392
+
393
+ // Extract Form Data for submit
394
+ if (eventType === 'submit' && element instanceof HTMLFormElement) {
395
+ const formData = new FormData(element)
396
+ const data: Record<string, string> = {}
397
+ formData.forEach((value, key) => {
398
+ if (!(value instanceof File)) {
399
+ data[key] = value.toString()
400
+ }
401
+ })
402
+ eventData.formData = data
403
+ }
404
+
405
+ this.app.sendEvent(handler, eventData)
406
+ }
407
+
408
+ private parseDuration(modifiers: string[], defaultDuration: number): number {
409
+ const debounceIdx = modifiers.findIndex((m) => m.startsWith('debounce'))
410
+ const throttleIdx = modifiers.findIndex((m) => m.startsWith('throttle'))
411
+ const idx = debounceIdx !== -1 ? debounceIdx : throttleIdx
412
+
413
+ if (idx !== -1 && modifiers[idx + 1]) {
414
+ const next = modifiers[idx + 1]
415
+ if (next.endsWith('ms')) {
416
+ const val = parseInt(next)
417
+ if (!isNaN(val)) return val
418
+ }
419
+ }
420
+
421
+ // Support hyphenated: debounce-500ms
422
+ const mod = modifiers[idx]
423
+ if (mod && mod.includes('-')) {
424
+ const parts = mod.split('-')
425
+ const val = parseInt(parts[1])
426
+ if (!isNaN(val)) return val
427
+ }
428
+
429
+ return defaultDuration
430
+ }
431
+
432
+ private getUniqueId(element: HTMLElement): string {
433
+ if (!element.id) {
434
+ element.id = 'pywire-uid-' + Math.random().toString(36).substr(2, 9)
435
+ }
436
+ return element.id
437
+ }
438
+
439
+ private getArgs(element: Element): Record<string, unknown> {
440
+ const args: Record<string, unknown> = {}
441
+ if (element instanceof HTMLElement) {
442
+ for (const key in element.dataset) {
443
+ if (key.startsWith('arg')) {
444
+ try {
445
+ args[key] = JSON.parse(element.dataset[key] || 'null')
446
+ } catch {
447
+ args[key] = element.dataset[key]
448
+ }
449
+ }
450
+ }
451
+ }
452
+ return args
453
+ }
454
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * PyWire Core Bundle Entry Point
3
+ * Production-optimized client with minimal footprint.
4
+ * Excludes dev features: status overlay, error trace with source loading.
5
+ */
6
+ import { PyWireApp } from './core/app'
7
+
8
+ export { PyWireApp, PyWireConfig } from './core/app'
9
+ export { TransportManager, TransportConfig } from './core/transport-manager'
10
+ export { DOMUpdater } from './core/dom-updater'
11
+ export * from './core/transports'
12
+
13
+ // Auto-init
14
+ const app = new PyWireApp()
15
+
16
+ if (document.readyState === 'loading') {
17
+ document.addEventListener('DOMContentLoaded', () => app.init())
18
+ } else {
19
+ app.init()
20
+ }
21
+
22
+ export { app }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * PyWire Dev Bundle Entry Point
3
+ * Includes all core features plus development tools:
4
+ * - Connection status overlay
5
+ * - Error trace with source loading for DevTools
6
+ * - Enhanced console output
7
+ */
8
+ import { PyWireDevApp } from './dev/dev-app'
9
+
10
+ // Re-export core
11
+ export * from './core'
12
+
13
+ // Export dev-specific
14
+ export { PyWireDevApp } from './dev/dev-app'
15
+ export { StatusOverlay } from './dev/status-overlay'
16
+ export { ErrorTraceHandler } from './dev/error-trace'
17
+
18
+ // Auto-init with dev app
19
+ const app = new PyWireDevApp()
20
+
21
+ if (document.readyState === 'loading') {
22
+ document.addEventListener('DOMContentLoaded', () => app.init())
23
+ } else {
24
+ app.init()
25
+ }
26
+
27
+ export { app }
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "declaration": false,
11
+ "outDir": "./dist",
12
+ "rootDir": "./src",
13
+ "lib": ["ES2020", "DOM", "DOM.Iterable"]
14
+ },
15
+ "include": ["src/**/*"],
16
+ "exclude": ["node_modules", "dist"]
17
+ }
@@ -0,0 +1,15 @@
1
+ import { defineConfig } from 'vitest/config'
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ environment: 'happy-dom',
6
+ globals: true,
7
+ include: ['src/**/*.test.ts'],
8
+ coverage: {
9
+ provider: 'v8',
10
+ reporter: ['text', 'json', 'html'],
11
+ include: ['src/**/*.ts'],
12
+ exclude: ['src/**/*.test.ts', 'src/index.ts', 'src/pywire.core.ts', 'src/pywire.dev.ts'],
13
+ },
14
+ },
15
+ })
@@ -0,0 +1,6 @@
1
+ """Compiler module."""
2
+
3
+ from pywire.compiler.codegen.generator import CodeGenerator
4
+ from pywire.compiler.parser import PyWireParser
5
+
6
+ __all__ = ["PyWireParser", "CodeGenerator"]