From bbd5d996670c8e645ff26ae4b864287f19cc0cfa Mon Sep 17 00:00:00 2001 From: Ian VanSchooten Date: Tue, 11 Nov 2025 04:25:57 -0500 Subject: [PATCH] [v3] Typed Events, revisited (#4633) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add strong event typings * Make `EmitEvent` take one data argument only * Add event registration logic * Report event cancellation to the emitter * Prevent registration of system events * Add support for typed event data initialisation * Binding generation for events * Tests for event bindings * Add vite plugin for typed events * Fix dev command execution order Co-authored-by: Fabio Massaioli * Propagate module path to templates * Update templates Co-authored-by: Ian VanSchooten * Go mod tidy for examples * Switch to tsconfig.json for jetbrains IDE support * Replace jsconfig in example * Convert vite plugin to typescript * Downgrade vite for now The templates all use 5.x * Remove root plugins dir from npm files It's now '/dist/plugins' * Include types for Create But keep out of the docs * Assign a type for cancelAll results * Restore variadic argument in EmitEvent methods * Support registered events with void data * Test cases for void alias support * Support strict mode * Support custom event hooks * Update docs * Update changelog * Testdata for typed events * Test data for void alias support * fix webview_window emit event * Update changelog.mdx * Update events * Fix generator test path normalization for cross-platform compatibility The generator tests were failing on CI because they compared absolute file paths in warning messages. These paths differ between development machines and CI environments. Changes: - Normalize file paths in warnings to be relative to testcases/ directory - Handle both Unix and Windows path separators - Use Unix line endings consistently in test output - Update all test expectation files to use normalized paths This ensures tests pass consistently across different environments including Windows, macOS, Linux, and CI systems. * Remove stale comment * Handle errors returned from validation * Restore variadic argument to Emit (fix bad rebase) * Event emitters return a boolean * Don't use `EmitEvent` in docs Supposedly it's for internal use, according to comment * Fix event docs (from rebase) * Ensure all templates specify @wailsio/runtime: "latest" * Fix Windows test failure due to CRLF line endings The test was failing on Windows because: 1. Hardcoded "\n" was being used instead of render.Newline when writing warning logs, causing CRLF vs LF mismatch 2. The render package import was missing 3. .got.log files weren't being skipped when building expected file list Changes: - Add render package import - Use render.Newline instead of hardcoded "\n" for cross-platform compatibility - Skip .got.log files in test file walker 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude * Fix template tests by using local runtime package The template tests were failing because they were installing @wailsio/runtime@latest from npm, which doesn't have the new vite plugin yet. This change packs the local runtime and uses it in template tests instead. Changes: - Pack the runtime to a tarball in test_js job - Upload the runtime package as an artifact - Download and install the local runtime in template tests before building - Update cleanup job to delete the runtime package artifact * Apply suggestion from @leaanthony * Fix: Install local runtime in frontend directory with correct path The previous fix wasn't working because: 1. npm install was run in the project root, not in frontend/ 2. wails3 build runs npm install again, which would reinstall from npm Fixed by: - Using npm pkg set to modify package.json to use file:// protocol - This ensures subsequent npm install calls use the local tarball * Fix Vue template syntax conflicts with Go template delimiters The Vue templates were converted to .tmpl files to support dynamic module paths, but Vue's template syntax {{ }} conflicts with Go's template syntax. Fixed by escaping Vue template braces: - {{ becomes {{"{{"}} - }} becomes {{"}}"}} This allows the Go template engine to output the literal {{ }} for Vue to process. * Fix Vue template escaping and Windows shell compatibility Two issues fixed: 1. Vue template escaping: Changed from {{"{{"}} to {{ "{{" }} - The previous syntax caused "missing value for command" error - Correct Go template syntax uses spaces between delimiters and strings 2. Windows PowerShell compatibility: Added 'shell: bash' to template generation step - The bash syntax (ls, head, $()) doesn't work in PowerShell - Git Bash is available on all GitHub runners including Windows * Fix: test_templates depends on test_js for runtime package artifact The runtime-package artifact is created in test_js job, not test_go. Added test_js to the needs array so the artifact is available for download. * Fix Windows path compatibility for runtime package artifact Changed from absolute Unix path '/tmp/wails-runtime' to relative path 'wails-runtime-temp' which works cross-platform. Using realpath to convert to absolute path for file:// URL in npm pkg set command. * Fix realpath issue on Windows for runtime package realpath on Windows Git Bash was producing malformed paths with duplicate drive letters (D:\d\a\...). Replaced with portable solution using pwd that works correctly across all platforms. * Use pwd -W on Windows to get native Windows paths Git Bash's pwd returns Unix-style paths (/d/a/wails/wails) which npm then incorrectly resolves as D:/d/a/wails/wails. Using pwd -W returns native Windows paths (D:\a\wails\wails) that npm can handle correctly. This is the root cause of all the Windows path issues. * Improve typechecking for Events.Emit() * [docs] Clarify where `Events` is imported from in each example * Add docs for runtime Events.Emit() * Revert to v2-style Events.Emit (name, data) * Update changelog --------- Co-authored-by: Fabio Massaioli Co-authored-by: Atterpac Co-authored-by: Lea Anthony Co-authored-by: Claude --- .github/workflows/build-and-test-v3.yml | 36 +- docs/src/content/docs/changelog.mdx | 1517 +++++++++-------- .../content/docs/guides/events-reference.mdx | 52 +- docs/src/content/docs/guides/gin-services.mdx | 21 +- docs/src/content/docs/learn/events.mdx | 114 +- v3/UNRELEASED_CHANGELOG.md | 2 + v3/examples/badge-custom/frontend/src/main.ts | 7 +- v3/examples/badge/frontend/src/main.ts | 7 +- .../frontend/package.json | 2 +- .../frontend/{jsconfig.json => tsconfig.json} | 3 +- v3/examples/gin-service/assets/index.html | 2 +- v3/internal/commands/bindings.go | 3 +- .../commands/build_assets/Taskfile.tmpl.yml | 2 +- v3/internal/commands/build_assets/config.yml | 10 +- v3/internal/commands/init.go | 106 +- v3/internal/commands/init_test.go | 10 +- v3/internal/flags/bindings.go | 1 + v3/internal/flags/init.go | 1 + v3/internal/generator/analyse.go | 54 +- v3/internal/generator/analyse_test.go | 25 +- v3/internal/generator/collect/collector.go | 10 +- v3/internal/generator/collect/declaration.go | 40 +- v3/internal/generator/collect/events.go | 283 +++ v3/internal/generator/collect/imports.go | 7 +- v3/internal/generator/collect/known_events.go | 220 +++ v3/internal/generator/collect/package.go | 11 +- v3/internal/generator/collect/predicates.go | 120 ++ v3/internal/generator/collect/service.go | 4 +- v3/internal/generator/collect/stats.go | 2 + v3/internal/generator/collect/void.go | 32 + v3/internal/generator/config/paths.go | 4 + v3/internal/generator/errors.go | 5 + v3/internal/generator/events.go | 53 + v3/internal/generator/generate.go | 44 +- v3/internal/generator/generate_test.go | 33 +- v3/internal/generator/load.go | 15 +- v3/internal/generator/render/create.go | 66 +- v3/internal/generator/render/renderer.go | 60 +- v3/internal/generator/render/templates.go | 3 + .../render/templates/eventcreate.js.tmpl | 47 + .../render/templates/eventdata.d.ts.tmpl | 32 + v3/internal/generator/render/type.go | 5 + .../testcases/complex_json/events.json | 1 + .../generator/testcases/complex_json/main.go | 5 + .../generator/testcases/events_only/events.go | 26 + .../testcases/events_only/events.json | 1 + .../generator/testcases/events_only/other.go | 26 + .../testcases/marshalers/events.json | 1 + .../generator/testcases/marshalers/main.go | 6 + .../testcases/no_bindings_here/more/more.go | 4 + .../wailsapp/wails/v3/internal/eventcreate.js | 39 + .../wailsapp/wails/v3/internal/eventdata.d.ts | 30 + .../generator/testcases/events_only/index.js | 7 + .../generator/testcases/events_only/models.js | 56 + .../testcases/no_bindings_here/more/index.js | 10 + .../testcases/no_bindings_here/more/models.js | 12 + .../UseNames=false/warnings.log | 13 + .../wailsapp/wails/v3/internal/eventcreate.js | 42 + .../wailsapp/wails/v3/internal/eventdata.d.ts | 33 + .../generator/testcases/events_only/index.js | 7 + .../generator/testcases/events_only/models.js | 56 + .../testcases/no_bindings_here/more/index.js | 10 + .../testcases/no_bindings_here/more/models.js | 12 + .../wails/v3/pkg/application/index.js | 11 + .../wails/v3/pkg/application/models.js | 13 + .../UseNames=true/warnings.log | 14 + .../wailsapp/wails/v3/internal/eventcreate.js | 9 + .../wailsapp/wails/v3/internal/eventdata.d.ts | 33 + .../generator/testcases/events_only/index.js | 10 + .../generator/testcases/events_only/models.js | 18 + .../testcases/no_bindings_here/more/index.js | 10 + .../testcases/no_bindings_here/more/models.js | 12 + .../wails/v3/pkg/application/index.js | 11 + .../wails/v3/pkg/application/models.js | 13 + .../UseNames=false/warnings.log | 14 + .../wailsapp/wails/v3/internal/eventcreate.js | 9 + .../wailsapp/wails/v3/internal/eventdata.d.ts | 33 + .../generator/testcases/events_only/index.js | 10 + .../generator/testcases/events_only/models.js | 18 + .../testcases/no_bindings_here/more/index.js | 10 + .../testcases/no_bindings_here/more/models.js | 12 + .../wails/v3/pkg/application/index.js | 11 + .../wails/v3/pkg/application/models.js | 13 + .../UseNames=true/warnings.log | 14 + .../wailsapp/wails/v3/internal/eventcreate.ts | 42 + .../wailsapp/wails/v3/internal/eventdata.d.ts | 33 + .../generator/testcases/events_only/index.ts | 6 + .../generator/testcases/events_only/models.ts | 45 + .../testcases/no_bindings_here/more/index.ts | 6 + .../testcases/no_bindings_here/more/models.ts | 11 + .../wails/v3/pkg/application/index.ts | 6 + .../wails/v3/pkg/application/models.ts | 12 + .../UseNames=false/warnings.log | 14 + .../wailsapp/wails/v3/internal/eventcreate.ts | 42 + .../wailsapp/wails/v3/internal/eventdata.d.ts | 33 + .../generator/testcases/events_only/index.ts | 6 + .../generator/testcases/events_only/models.ts | 45 + .../testcases/no_bindings_here/more/index.ts | 6 + .../testcases/no_bindings_here/more/models.ts | 11 + .../wails/v3/pkg/application/index.ts | 6 + .../wails/v3/pkg/application/models.ts | 12 + .../UseNames=true/warnings.log | 14 + .../wailsapp/wails/v3/internal/eventcreate.ts | 9 + .../wailsapp/wails/v3/internal/eventdata.d.ts | 33 + .../generator/testcases/events_only/index.ts | 6 + .../generator/testcases/events_only/models.ts | 14 + .../testcases/no_bindings_here/more/index.ts | 6 + .../testcases/no_bindings_here/more/models.ts | 7 + .../wails/v3/pkg/application/index.ts | 6 + .../wails/v3/pkg/application/models.ts | 8 + .../UseNames=false/warnings.log | 14 + .../wailsapp/wails/v3/internal/eventcreate.ts | 9 + .../wailsapp/wails/v3/internal/eventdata.d.ts | 33 + .../generator/testcases/events_only/index.ts | 6 + .../generator/testcases/events_only/models.ts | 14 + .../testcases/no_bindings_here/more/index.ts | 6 + .../testcases/no_bindings_here/more/models.ts | 7 + .../wails/v3/pkg/application/index.ts | 6 + .../wails/v3/pkg/application/models.ts | 8 + .../UseNames=true/warnings.log | 14 + v3/internal/generator/testdata/tsconfig.json | 14 +- .../@wailsio/runtime/package-lock.json | 493 +++--- .../desktop/@wailsio/runtime/package.json | 11 +- .../@wailsio/runtime/src/cancellable.ts | 6 +- .../desktop/@wailsio/runtime/src/create.ts | 6 + .../@wailsio/runtime/src/event_types.ts | 15 +- .../desktop/@wailsio/runtime/src/events.ts | 82 +- .../desktop/@wailsio/runtime/src/index.ts | 1 - .../@wailsio/runtime/src/plugins/vite.ts | 76 + .../desktop/@wailsio/runtime/tsconfig.json | 5 +- v3/internal/templates/_common/go.mod.tmpl | 2 +- v3/internal/templates/_common/main.go.tmpl | 7 + .../main.js => base/frontend/main.js.tmpl} | 2 +- .../src/{my-element.ts => my-element.ts.tmpl} | 2 +- .../templates/lit-ts/frontend/tsconfig.json | 2 +- .../templates/lit-ts/frontend/vite.config.ts | 7 + .../src/{my-element.js => my-element.js.tmpl} | 2 +- .../templates/lit/frontend/src/vite-env.d.ts | 1 + .../templates/lit/frontend/tsconfig.json | 25 + .../templates/lit/frontend/vite.config.js | 7 + .../frontend/src/{app.tsx => app.tsx.tmpl} | 2 +- .../preact-ts/frontend/tsconfig.json | 3 +- .../preact-ts/frontend/tsconfig.node.json | 10 - .../preact-ts/frontend/vite.config.ts | 9 +- .../frontend/src/{app.jsx => app.jsx.tmpl} | 2 +- .../preact/frontend/src/vite-env.d.ts | 1 + .../templates/preact/frontend/tsconfig.json | 25 + .../templates/preact/frontend/vite.config.js | 9 +- .../frontend/src/{app.tsx => app.tsx.tmpl} | 2 +- .../qwik-ts/frontend/src/vite-env.d.ts | 1 + .../templates/qwik-ts/frontend/tsconfig.json | 3 +- .../qwik-ts/frontend/tsconfig.node.json | 10 - .../templates/qwik-ts/frontend/vite.config.js | 11 - .../templates/qwik-ts/frontend/vite.config.ts | 13 + .../frontend/src/{app.jsx => app.jsx.tmpl} | 2 +- .../templates/qwik/frontend/src/main.jsx | 2 +- .../templates/qwik/frontend/src/vite-env.d.ts | 1 + .../templates/qwik/frontend/tsconfig.json | 25 + .../templates/qwik/frontend/vite.config.js | 8 +- .../frontend/src/{App.tsx => App.tsx.tmpl} | 2 +- .../react-swc-ts/frontend/tsconfig.json | 3 +- .../react-swc-ts/frontend/tsconfig.node.json | 10 - .../react-swc-ts/frontend/vite.config.ts | 9 +- .../frontend/src/App.jsx.tmpl} | 2 +- .../react-swc/frontend/src/vite-env.d.ts | 1 + .../react-swc/frontend/tsconfig.json | 25 + .../react-swc/frontend/vite.config.js | 9 +- .../frontend/src/{App.tsx => App.tsx.tmpl} | 2 +- .../templates/react-ts/frontend/tsconfig.json | 3 +- .../react-ts/frontend/tsconfig.node.json | 10 - .../react-ts/frontend/vite.config.ts | 9 +- .../frontend/src/App.jsx.tmpl} | 2 +- .../react/frontend/src/vite-env.d.ts | 1 + .../templates/react/frontend/tsconfig.json | 25 + .../templates/react/frontend/vite.config.js | 9 +- .../frontend/src/{App.tsx => App.tsx.tmpl} | 2 +- .../solid-ts/frontend/src/vite-env.d.ts | 1 + .../templates/solid-ts/frontend/tsconfig.json | 3 +- .../solid-ts/frontend/tsconfig.node.json | 10 - .../solid-ts/frontend/vite.config.ts | 9 +- .../frontend/src/{App.jsx => App.jsx.tmpl} | 2 +- .../solid/frontend/src/vite-env.d.ts | 1 + .../templates/solid/frontend/tsconfig.json | 25 + .../templates/solid/frontend/vite.config.js | 10 +- .../src/{App.svelte => App.svelte.tmpl} | 2 +- .../svelte-ts/frontend/tsconfig.json | 3 +- .../svelte-ts/frontend/tsconfig.node.json | 9 - .../svelte-ts/frontend/vite.config.ts | 9 +- .../templates/svelte/frontend/README.md | 1 - .../templates/svelte/frontend/jsconfig.json | 33 - .../src/{App.svelte => App.svelte.tmpl} | 2 +- .../templates/svelte/frontend/tsconfig.json | 25 + .../templates/svelte/frontend/vite.config.js | 9 +- .../sveltekit-ts/frontend/package.json | 2 +- .../{+page.svelte => +page.svelte.tmpl} | 2 +- .../sveltekit-ts/frontend/vite.config.ts | 25 +- .../frontend/frontend/Inter-Medium.ttf | Bin 315132 -> 0 bytes .../sveltekit/frontend/frontend/svelte.svg | 1 - .../sveltekit/frontend/frontend/wails.png | Bin 9057 -> 0 bytes .../templates/sveltekit/frontend/package.json | 2 +- .../{+page.svelte => +page.svelte.tmpl} | 2 +- .../sveltekit/frontend/tsconfig.json | 25 + .../sveltekit/frontend/vite.config.js | 26 +- .../vanilla-ts/frontend/package.json | 4 +- .../frontend/src/{main.ts => main.ts.tmpl} | 16 +- .../vanilla-ts/frontend/tsconfig.json | 26 +- .../vanilla-ts/frontend/vite.config.ts | 7 + .../templates/vanilla/frontend/index.html | 2 +- .../frontend/src/main.js.tmpl} | 14 +- .../templates/vanilla/frontend/tsconfig.json | 25 + .../templates/vanilla/frontend/vite.config.js | 7 + .../{HelloWorld.vue => HelloWorld.vue.tmpl} | 8 +- .../templates/vue-ts/frontend/tsconfig.json | 3 +- .../vue-ts/frontend/tsconfig.node.json | 9 - .../templates/vue-ts/frontend/vite.config.ts | 9 +- .../{HelloWorld.vue => HelloWorld.vue.tmpl} | 8 +- .../templates/vue/frontend/src/vite-env.d.ts | 1 + .../templates/vue/frontend/tsconfig.json | 25 + .../templates/vue/frontend/vite.config.js | 9 +- v3/pkg/application/application.go | 6 +- v3/pkg/application/event_manager.go | 43 +- v3/pkg/application/events.go | 145 +- v3/pkg/application/events_loose.go | 7 + v3/pkg/application/events_strict.go | 27 + v3/pkg/application/events_test.go | 18 +- v3/pkg/application/messageprocessor_call.go | 2 +- v3/pkg/application/messageprocessor_events.go | 20 +- v3/pkg/application/services.go | 2 +- v3/pkg/application/webview_window.go | 36 +- v3/pkg/application/window.go | 4 +- v3/pkg/events/known_events.go | 220 +++ v3/tasks/events/generate.go | 87 +- 232 files changed, 4734 insertions(+), 1646 deletions(-) rename v3/examples/dev/frontend/{jsconfig.json => tsconfig.json} (90%) create mode 100644 v3/internal/generator/collect/events.go create mode 100644 v3/internal/generator/collect/known_events.go create mode 100644 v3/internal/generator/collect/void.go create mode 100644 v3/internal/generator/events.go create mode 100644 v3/internal/generator/render/templates/eventcreate.js.tmpl create mode 100644 v3/internal/generator/render/templates/eventdata.d.ts.tmpl create mode 100644 v3/internal/generator/testcases/complex_json/events.json create mode 100644 v3/internal/generator/testcases/events_only/events.go create mode 100644 v3/internal/generator/testcases/events_only/events.json create mode 100644 v3/internal/generator/testcases/events_only/other.go create mode 100644 v3/internal/generator/testcases/marshalers/events.json create mode 100644 v3/internal/generator/testcases/no_bindings_here/more/more.go create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/eventcreate.js create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/eventdata.d.ts create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.js create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.js create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.js create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.js create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/eventcreate.js create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/eventdata.d.ts create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.js create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.js create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.js create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.js create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/index.js create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/models.js create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/eventcreate.js create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/eventdata.d.ts create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.js create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.js create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.js create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.js create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/pkg/application/index.js create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/pkg/application/models.js create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/eventcreate.js create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/eventdata.d.ts create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.js create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.js create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.js create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.js create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/index.js create mode 100644 v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/models.js create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/eventcreate.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/eventdata.d.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/pkg/application/index.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/pkg/application/models.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/eventcreate.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/eventdata.d.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/index.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/models.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/eventcreate.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/eventdata.d.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/pkg/application/index.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/pkg/application/models.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/eventcreate.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/eventdata.d.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/index.ts create mode 100644 v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/models.ts create mode 100644 v3/internal/runtime/desktop/@wailsio/runtime/src/plugins/vite.ts rename v3/internal/templates/{vanilla/frontend/main.js => base/frontend/main.js.tmpl} (89%) rename v3/internal/templates/lit-ts/frontend/src/{my-element.ts => my-element.ts.tmpl} (98%) create mode 100644 v3/internal/templates/lit-ts/frontend/vite.config.ts rename v3/internal/templates/lit/frontend/src/{my-element.js => my-element.js.tmpl} (98%) create mode 100644 v3/internal/templates/lit/frontend/src/vite-env.d.ts create mode 100644 v3/internal/templates/lit/frontend/tsconfig.json create mode 100644 v3/internal/templates/lit/frontend/vite.config.js rename v3/internal/templates/preact-ts/frontend/src/{app.tsx => app.tsx.tmpl} (96%) delete mode 100644 v3/internal/templates/preact-ts/frontend/tsconfig.node.json rename v3/internal/templates/preact/frontend/src/{app.jsx => app.jsx.tmpl} (96%) create mode 100644 v3/internal/templates/preact/frontend/src/vite-env.d.ts create mode 100644 v3/internal/templates/preact/frontend/tsconfig.json rename v3/internal/templates/qwik-ts/frontend/src/{app.tsx => app.tsx.tmpl} (96%) create mode 100644 v3/internal/templates/qwik-ts/frontend/src/vite-env.d.ts delete mode 100644 v3/internal/templates/qwik-ts/frontend/tsconfig.node.json delete mode 100644 v3/internal/templates/qwik-ts/frontend/vite.config.js create mode 100644 v3/internal/templates/qwik-ts/frontend/vite.config.ts rename v3/internal/templates/qwik/frontend/src/{app.jsx => app.jsx.tmpl} (96%) create mode 100644 v3/internal/templates/qwik/frontend/src/vite-env.d.ts create mode 100644 v3/internal/templates/qwik/frontend/tsconfig.json rename v3/internal/templates/react-swc-ts/frontend/src/{App.tsx => App.tsx.tmpl} (96%) delete mode 100644 v3/internal/templates/react-swc-ts/frontend/tsconfig.node.json rename v3/internal/templates/{react/frontend/src/App.jsx => react-swc/frontend/src/App.jsx.tmpl} (96%) create mode 100644 v3/internal/templates/react-swc/frontend/src/vite-env.d.ts create mode 100644 v3/internal/templates/react-swc/frontend/tsconfig.json rename v3/internal/templates/react-ts/frontend/src/{App.tsx => App.tsx.tmpl} (96%) delete mode 100644 v3/internal/templates/react-ts/frontend/tsconfig.node.json rename v3/internal/templates/{react-swc/frontend/src/App.jsx => react/frontend/src/App.jsx.tmpl} (96%) create mode 100644 v3/internal/templates/react/frontend/src/vite-env.d.ts create mode 100644 v3/internal/templates/react/frontend/tsconfig.json rename v3/internal/templates/solid-ts/frontend/src/{App.tsx => App.tsx.tmpl} (96%) create mode 100644 v3/internal/templates/solid-ts/frontend/src/vite-env.d.ts delete mode 100644 v3/internal/templates/solid-ts/frontend/tsconfig.node.json rename v3/internal/templates/solid/frontend/src/{App.jsx => App.jsx.tmpl} (96%) create mode 100644 v3/internal/templates/solid/frontend/src/vite-env.d.ts create mode 100644 v3/internal/templates/solid/frontend/tsconfig.json rename v3/internal/templates/svelte-ts/frontend/src/{App.svelte => App.svelte.tmpl} (95%) delete mode 100644 v3/internal/templates/svelte-ts/frontend/tsconfig.node.json delete mode 100644 v3/internal/templates/svelte/frontend/README.md delete mode 100644 v3/internal/templates/svelte/frontend/jsconfig.json rename v3/internal/templates/svelte/frontend/src/{App.svelte => App.svelte.tmpl} (95%) create mode 100644 v3/internal/templates/svelte/frontend/tsconfig.json rename v3/internal/templates/sveltekit-ts/frontend/src/routes/{+page.svelte => +page.svelte.tmpl} (94%) delete mode 100644 v3/internal/templates/sveltekit/frontend/frontend/Inter-Medium.ttf delete mode 100644 v3/internal/templates/sveltekit/frontend/frontend/svelte.svg delete mode 100644 v3/internal/templates/sveltekit/frontend/frontend/wails.png rename v3/internal/templates/sveltekit/frontend/src/routes/{+page.svelte => +page.svelte.tmpl} (94%) create mode 100644 v3/internal/templates/sveltekit/frontend/tsconfig.json rename v3/internal/templates/vanilla-ts/frontend/src/{main.ts => main.ts.tmpl} (62%) create mode 100644 v3/internal/templates/vanilla-ts/frontend/vite.config.ts rename v3/internal/templates/{base/frontend/main.js => vanilla/frontend/src/main.js.tmpl} (59%) create mode 100644 v3/internal/templates/vanilla/frontend/tsconfig.json create mode 100644 v3/internal/templates/vanilla/frontend/vite.config.js rename v3/internal/templates/vue-ts/frontend/src/components/{HelloWorld.vue => HelloWorld.vue.tmpl} (82%) delete mode 100644 v3/internal/templates/vue-ts/frontend/tsconfig.node.json rename v3/internal/templates/vue/frontend/src/components/{HelloWorld.vue => HelloWorld.vue.tmpl} (81%) create mode 100644 v3/internal/templates/vue/frontend/src/vite-env.d.ts create mode 100644 v3/internal/templates/vue/frontend/tsconfig.json create mode 100644 v3/pkg/application/events_loose.go create mode 100644 v3/pkg/application/events_strict.go create mode 100644 v3/pkg/events/known_events.go diff --git a/.github/workflows/build-and-test-v3.yml b/.github/workflows/build-and-test-v3.yml index a1b482e11..b9d8b659f 100644 --- a/.github/workflows/build-and-test-v3.yml +++ b/.github/workflows/build-and-test-v3.yml @@ -79,6 +79,10 @@ jobs: working-directory: v3/internal/runtime/desktop/@wailsio/runtime run: npm run build + - name: Pack runtime for template tests + working-directory: v3/internal/runtime/desktop/@wailsio/runtime + run: npm pack + - name: Store runtime build artifacts uses: actions/upload-artifact@v4 with: @@ -88,6 +92,12 @@ jobs: v3/internal/runtime/desktop/@wailsio/runtime/types/ v3/internal/runtime/desktop/@wailsio/runtime/tsconfig.tsbuildinfo + - name: Store runtime package + uses: actions/upload-artifact@v4 + with: + name: runtime-package + path: v3/internal/runtime/desktop/@wailsio/runtime/*.tgz + test_go: name: Run Go Tests v3 needs: [check_approval, test_js] @@ -165,17 +175,19 @@ jobs: cleanup: name: Cleanup build artifacts if: always() - needs: [test_js, test_go] + needs: [test_js, test_go, test_templates] runs-on: ubuntu-latest steps: - uses: geekyeggo/delete-artifact@v5 with: - name: runtime-build-artifacts + name: | + runtime-build-artifacts + runtime-package failOnError: false test_templates: name: Test Templates - needs: test_go + needs: [test_js, test_go] runs-on: ${{ matrix.os }} if: github.base_ref == 'v3-alpha' strategy: @@ -226,12 +238,28 @@ jobs: task install wails3 doctor + - name: Download runtime package + uses: actions/download-artifact@v4 + with: + name: runtime-package + path: wails-runtime-temp + - name: Generate template '${{ matrix.template }}' + shell: bash run: | + # Get absolute path - use pwd -W on Windows for native paths, pwd elsewhere + if [[ "$RUNNER_OS" == "Windows" ]]; then + RUNTIME_TGZ="$(cd wails-runtime-temp && pwd -W)/$(ls wails-runtime-temp/*.tgz | xargs basename)" + else + RUNTIME_TGZ="$(cd wails-runtime-temp && pwd)/$(ls wails-runtime-temp/*.tgz | xargs basename)" + fi mkdir -p ./test-${{ matrix.template }} cd ./test-${{ matrix.template }} wails3 init -n ${{ matrix.template }} -t ${{ matrix.template }} - cd ${{ matrix.template }} + cd ${{ matrix.template }}/frontend + # Replace @wailsio/runtime version with local tarball + npm pkg set dependencies.@wailsio/runtime="file://$RUNTIME_TGZ" + cd .. wails3 build build_results: diff --git a/docs/src/content/docs/changelog.mdx b/docs/src/content/docs/changelog.mdx index 60d723f02..c55ca3f23 100644 --- a/docs/src/content/docs/changelog.mdx +++ b/docs/src/content/docs/changelog.mdx @@ -1,33 +1,33 @@ ---- -title: Changelog ---- - - -Legend: --  - macOS -- ⊞ - Windows -- 🐧 - Linux - -/*-- -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -- `Added` for new features. -- `Changed` for changes in existing functionality. -- `Deprecated` for soon-to-be removed features. -- `Removed` for now removed features. -- `Fixed` for any bug fixes. -- `Security` in case of vulnerabilities. - -*/ - -/* - ** PLEASE DO NOT UPDATE THIS FILE ** - Updates should be added to `v3/UNRELEASED_CHANGELOG.md` - Thank you! -*/ +--- +title: Changelog +--- + + +Legend: +-  - macOS +- ⊞ - Windows +- 🐧 - Linux + +/*-- +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +- `Added` for new features. +- `Changed` for changes in existing functionality. +- `Deprecated` for soon-to-be removed features. +- `Removed` for now removed features. +- `Fixed` for any bug fixes. +- `Security` in case of vulnerabilities. + +*/ + +/* + ** PLEASE DO NOT UPDATE THIS FILE ** + Updates should be added to `v3/UNRELEASED_CHANGELOG.md` + Thank you! +*/ ## [Unreleased] ## v3.0.0-alpha.38 - 2025-11-04 @@ -125,730 +125,733 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## v3.0.0-alpha.27 - 2025-09-07 ## Fixed -- Fixed redefinition error for liquid glass demo in [#4542](https://github.com/wailsapp/wails/pull/4542) by @Etesam913 - -## v3.0.0-alpha.26 - 2025-08-24 - -## Added -- Add native Liquid Glass effect support for macOS with NSGlassEffectView (macOS 15.0+) and NSVisualEffectView fallback, including comprehensive material customization options by @leaanthony in [#4534](https://github.com/wailsapp/wails/pull/4534) - -## v3.0.0-alpha.25 - 2025-08-16 - -## Changed -- When running `wails3 update build-assets` with the `-config` parameter, values set via the `-product*` parameters are - no longer ignored, and override the config value. - -## v3.0.0-alpha.24 - 2025-08-13 - -## Added -- Browser URL Sanitisation by @leaanthony in [#4500](https://github.dev/wailsapp/wails/pull/4500). Based on [#4484](https://github.com/wailsapp/wails/pull/4484) by @APShenkin. - -## v3.0.0-alpha.23 - 2025-08-11 - -## Fixed -- Fix SetBackgroundColour on Windows by @PPTGamer in [PR](https://github.com/wailsapp/wails/pull/4492) - -## v3.0.0-alpha.22 - 2025-08-10 - -## Added -- Add Content Protection on Windows/Mac by [@leaanthony](https://github.com/leaanthony) based on the original work of [@Taiterbase](https://github.com/Taiterbase) in this [PR](https://github.com/wailsapp/wails/pull/4241) -- Add support for passing CLI variables to Task commands through `wails3 build` and `wails3 package` aliases (#4422) by @leaanthony in [PR](https://github.com/wailsapp/wails/pull/4488) - -## Changed -- `window.NativeWindowHandle()` -> `window.NativeWindow()` by @leaanthony in [#4471](https://github.com/wailsapp/wails/pull/4471) -- Refactor internal window handling by @leaanthony in [#4471](https://github.com/wailsapp/wails/pull/4471) -+ Fix extra-broad Linux package dependencies, fix outdated RPM dependencies. - -## v3.0.0-alpha.21 - 2025-08-07 - -## Fixed -- Update docs to reflect changes from Manager API Refactoring by @yulesxoxo in [PR #4476](https://github.com/wailsapp/wails/pull/4476) -- Fix Linux .desktop file appicon variable in Linux taskfile [PR #4477](https://github.com/wailsapp/wails/pull/4477) - -## v3.0.0-alpha.20 - 2025-08-06 - -## Fixed -- Update docs to reflect changes from Manager API Refactoring by @yulesxoxo in [PR #4476](https://github.com/wailsapp/wails/pull/4476) - -## v3.0.0-alpha.19 - 2025-08-05 - -## Added -- Support for dropzones with event sourcing dropped element data [@atterpac](https://github.com/atterpac) in [#4318](https://github.com/wailsapp/wails/pull/4318) -- Added `AdditionalLaunchArgs` to `WindowsWindow` options to allow for additional command line arguments to be passed to the WebView2 browser. in [PR](https://github.com/wailsapp/wails/pull/4467) -- Added Run go mod tidy automatically after wails init [@triadmoko](https://github.com/triadmoko) in [PR](https://github.com/wailsapp/wails/pull/4286) -- Windows Snapassist feature by @leaanthony in [PR](https://github.dev/wailsapp/wails/pull/4463) - -## Fixed -- Fix Windows nil pointer dereference bug reported in [#4456](https://github.com/wailsapp/wails/issues/4456) by @leaanthony in [#4460](https://github.com/wailsapp/wails/pull/4460) -- Add support for `allowsBackForwardNavigationGestures` in macOS WKWebView to enable two-finger swipe navigation gestures (#1857) -- Fixes issue where onClick didn't work for menu items initially set as disabled by @leaanthony in [PR #4469](https://github.com/wailsapp/wails/pull/4469). Thanks to @IanVS for the initial investigation. -- Fix Vite server not being cleaned up when build fails (#4403) -- Fixed panic when closing or cancelling a `SaveFileDialog` on windows. Fixed in [PR](https://github.com/wailsapp/wails/pull/4284) by @hkhere -- Fixed HTML level drag and drop on Windows by [@mbaklor](https://github.com/mbaklor) in [#4259](https://github.com/wailsapp/wails/pull/4259) - -## v3.0.0-alpha.18 - 2025-08-03 - -## Added -- Added `AdditionalLaunchArgs` to `WindowsWindow` options to allow for additional command line arguments to be passed to the WebView2 browser. in [PR](https://github.com/wailsapp/wails/pull/4467) -- Added Run go mod tidy automatically after wails init [@triadmoko](https://github.com/triadmoko) in [PR](https://github.com/wailsapp/wails/pull/4286) -- Windows Snapassist feature by @leaanthony in [PR](https://github.dev/wailsapp/wails/pull/4463) - -## Fixed -- Add support for `allowsBackForwardNavigationGestures` in macOS WKWebView to enable two-finger swipe navigation gestures (#1857) -- Fixes issue where onClick didn't work for menu items initially set as disabled by @leaanthony in [PR #4469](https://github.com/wailsapp/wails/pull/4469). Thanks to @IanVS for the initial investigation. -- Fix Vite server not being cleaned up when build fails (#4403) - -## v3.0.0-alpha.17 - 2025-07-31 - -## Fixed -- Fixed notification parsing on Windows @popaprozac in [PR](https://github.com/wailsapp/wails/pull/4450) - -## v3.0.0-alpha.16 - 2025-07-25 - -## Added -- Add Windows `getAccentColor` implementation by [@almas-x](https://github.com/almas-x) in [PR](https://github.com/wailsapp/wails/pull/4427) - -## v3.0.0-alpha.15 - 2025-07-25 - -## Added -- Add Windows `getAccentColor` implementation by [@almas-x](https://github.com/almas-x) in [PR](https://github.com/wailsapp/wails/pull/4427) - -## v3.0.0-alpha.14 - 2025-07-25 - -## Added -- Windows dark theme menus + menubar. By @leaanthony in [a29b4f0861b1d0a700e9eb213c6f1076ec40efd5](https://github.com/wailsapp/wails/commit/a29b4f0861b1d0a700e9eb213c6f1076ec40efd5) -- Rename built-in services for clearer JS/TS bindings by @popaprozac in [PR](https://github.com/wailsapp/wails/pull/4405) - -## v3.0.0-alpha.12 - 2025-07-15 - -### Added -- `app.Env.GetAccentColor` to get the accent color of a user's system. Works on MacOS. by [@etesam913](https://github.com/etesam913) -- Add `window.ToggleFrameless()` api by [@atterpac](https://github.com/atterpac) in [#4137](https://github.com/wailsapp/wails/pull/4137) - -### Fixed -- Fixed doctor command to check for Windows SDK dependencies by [@kodumulo](https://github.com/kodumulo) in [#4390](https://github.com/wailsapp/wails/issues/4390) - - -## v3.0.0-alpha.11 - 2025-07-12 - -## Added -- Add distribution-specific build dependencies for Linux by @leaanthony in [PR](https://github.com/wailsapp/wails/pull/4345) -- Added bindings guide by @atterpac in [PR](https://github.com/wailsapp/wails/pull/4404) - -## v3.0.0-alpha.10 - 2025-07-06 - -### Breaking Changes -- **Manager API Refactoring**: Reorganized application API from flat structure to organized managers for better code organization and discoverability by [@leaanthony](https://github.com/leaanthony) in [#4359](https://github.com/wailsapp/wails/pull/4359) - - `app.NewWebviewWindow()` → `app.Window.New()` - - `app.CurrentWindow()` → `app.Window.Current()` - - `app.GetAllWindows()` → `app.Window.GetAll()` - - `app.WindowByName()` → `app.Window.GetByName()` - - `app.EmitEvent()` → `app.Event.Emit()` - - `app.OnApplicationEvent()` → `app.Event.OnApplicationEvent()` - - `app.OnWindowEvent()` → `app.Event.OnWindowEvent()` - - `app.SetApplicationMenu()` → `app.Menu.SetApplicationMenu()` - - `app.OpenFileDialog()` → `app.Dialog.OpenFile()` - - `app.SaveFileDialog()` → `app.Dialog.SaveFile()` - - `app.MessageDialog()` → `app.Dialog.Message()` - - `app.InfoDialog()` → `app.Dialog.Info()` - - `app.WarningDialog()` → `app.Dialog.Warning()` - - `app.ErrorDialog()` → `app.Dialog.Error()` - - `app.QuestionDialog()` → `app.Dialog.Question()` - - `app.NewSystemTray()` → `app.SystemTray.New()` - - `app.GetSystemTray()` → `app.SystemTray.Get()` - - `app.ShowContextMenu()` → `app.ContextMenu.Show()` - - `app.RegisterKeybinding()` → `app.KeyBinding.Register()` - - `app.UnregisterKeybinding()` → `app.KeyBinding.Unregister()` - - `app.GetPrimaryScreen()` → `app.Screen.GetPrimary()` - - `app.GetAllScreens()` → `app.Screen.GetAll()` - - `app.BrowserOpenURL()` → `app.Browser.OpenURL()` - - `app.Environment()` → `app.Env.GetAll()` - - `app.ClipboardGetText()` → `app.Clipboard.Text()` - - `app.ClipboardSetText()` → `app.Clipboard.SetText()` -- Renamed Service methods: `Name` -> `ServiceName`, `OnStartup` -> `ServiceStartup`, `OnShutdown` -> `ServiceShutdown` by [@leaanthony](https://github.com/leaanthony) -- Moved `Path` and `Paths` methods to `application` package by [@leaanthony](https://github.com/leaanthony) -- The application menu is now macOS only by [@leaanthony](https://github.com/leaanthony) - -### Added - -- **Organized Testing Infrastructure**: Moved Docker test files to dedicated `test/docker/` directory with optimized images and enhanced build reliability by [@leaanthony](https://github.com/leaanthony) in [#4359](https://github.com/wailsapp/wails/pull/4359) -- **Improved Resource Management Patterns**: Added proper event handler cleanup and context-aware goroutine management in examples by [@leaanthony](https://github.com/leaanthony) in [#4359](https://github.com/wailsapp/wails/pull/4359) -- Support aarch64 AppImage builds by [@AkshayKalose](https://github.com/AkshayKalose) in [#3981](https://github.com/wailsapp/wails/pull/3981) -- Add diagnostics section to `wails doctor` by [@leaanthony](https://github.com/leaanthony) -- Add window to context when calling a service method by [@leaanthony](https://github.com/leaanthony) -- Add `window-call` example to demonstrate how to know which window is calling a service by [@leaanthony](https://github.com/leaanthony) -- New Menu guide by [@leaanthony](https://github.com/leaanthony) -- Better panic handling by [@leaanthony](https://github.com/leaanthony) -- New Menu guide by [@leaanthony](https://github.com/leaanthony) -- Add doc comments for Service API by [@fbbdev](https://github.com/fbbdev) in [#4024](https://github.com/wailsapp/wails/pull/4024) -- Add function `application.NewServiceWithOptions` to initialise services with additional configuration by [@leaanthony](https://github.com/leaanthony) in [#4024](https://github.com/wailsapp/wails/pull/4024) -- Improved menu control by [@FalcoG](https://github.com/FalcoG) and [@leaanthony](https://github.com/leaanthony) in [#4031](https://github.com/wailsapp/wails/pull/4031) -- More documentation by [@leaanthony](https://github.com/leaanthony) -- Support cancellation of events in standard event listeners by [@leaanthony](https://github.com/leaanthony) -- Systray `Hide`, `Show` and `Destroy` support by [@leaanthony](https://github.com/leaanthony) -- Systray `SetTooltip` support by [@leaanthony](https://github.com/leaanthony). Original idea by [@lujihong](https://github.com/wailsapp/wails/issues/3487#issuecomment-2633242304) -- Report package path in binding generator warnings about unsupported types by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) -- Add binding generator support for generic aliases by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) -- Add binding generator support for `omitzero` JSON flag by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) -- Add `//wails:ignore` directive to prevent binding generation for chosen service methods by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) -- Add `//wails:internal` directive on services and models to allow for types that are exported in Go but not in JS/TS by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) -- Add binding generator support for constants of alias type to allow for weakly typed enums by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) -- Add binding generator tests for Go 1.24 features by [@fbbdev](https://github.com/fbbdev) in [#4068](https://github.com/wailsapp/wails/pull/4068) -- Add support for macOS 15 "Sequoia" to `OSInfo.Branding` for improved OS version detection in [#4065](https://github.com/wailsapp/wails/pull/4065) -- Add `PostShutdown` hook for running custom code after the shutdown process completes by [@fbbdev](https://github.com/fbbdev) in [#4066](https://github.com/wailsapp/wails/pull/4066) -- Add `FatalError` struct to support detection of fatal errors in custom error handlers by [@fbbdev](https://github.com/fbbdev) in [#4066](https://github.com/wailsapp/wails/pull/4066) -- Standardise and document service startup and shutdown order by [@fbbdev](https://github.com/fbbdev) in [#4066](https://github.com/wailsapp/wails/pull/4066) -- Add test harness for application startup/shutdown sequence and service startup/shutdown tests by [@fbbdev](https://github.com/fbbdev) in [#4066](https://github.com/wailsapp/wails/pull/4066) -- Add `RegisterService` method for registering services after the application has been created by [@fbbdev](https://github.com/fbbdev) in [#4066](https://github.com/wailsapp/wails/pull/4066) -- Add `MarshalError` field in application and service options for custom error handling in binding calls by [@fbbdev](https://github.com/fbbdev) in [#4066](https://github.com/wailsapp/wails/pull/4066) -- Add cancellable promise wrapper that propagates cancellation requests through promise chains by [@fbbdev](https://github.com/fbbdev) in [#4100](https://github.com/wailsapp/wails/pull/4100) -- Add the ability to tie binding call cancellation to an `AbortSignal` by [@fbbdev](https://github.com/fbbdev) in [#4100](https://github.com/wailsapp/wails/pull/4100) -- Support `data-wml-*` attributes for WML alongside the usual `wml-*` attributes by [@leaanthony](https://github.com/leaanthony) -- Add `Configure` method on all services for late configuration/dynamic reconfiguration by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) -- `fileserver` service sends a 503 Service Unavailable response when unconfigured by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) -- `kvstore` service provides an in-memory key-value store by default when unconfigured by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) -- Add `Load` method on `kvstore` service to reload data from file after config changes by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) -- Add `Clear` method on `kvstore` service to delete all keys by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) -- Add type `Level` in `log` service to provide JS-side log-level constants by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) -- Add `Log` method on `log` service to specify log-level dynamically by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) -- `sqlite` service provides an in-memory DB by default when unconfigured by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) -- Add method `Close` on `sqlite` service to close the DB manually by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) -- Add cancellation support for query methods on `sqlite` service by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) -- Add prepared statement support to `sqlite` service with JS bindings by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) -- Gin support by [Lea Anthony](https://github.com/leaanthony) in [PR](https://github.com/wailsapp/wails/pull/3537) based on the original work of [@AnalogJ](https://github.com/AnalogJ) in this [PR](https://github.com/wailsapp/wails/pull/3537) -- Fix auto save and password auto save always enabled by [@oSethoum](https://github.com/osethoum) in [#4134](https://github.com/wailsapp/wails/pull/4134) -- Add `SetMenu()` on window to allow for setting a menu on a window by [@leaanthony](https://github.com/leaanthony) -- Add Notification support by [@popaprozac](https://github.com/popaprozac) in [#4098](https://github.com/wailsapp/wails/pull/4098) --  Add File Association support for mac by [@wimaha](https://github.com/wimaha) in [#4177](https://github.com/wailsapp/wails/pull/4177) -- Add `wails3 tool version` for semantic version bumping by [@leaanthony](https://github.com/leaanthony) -- Add badging support for macOS and Windows by [@popaprozac](https://github.com/popaprozac) in [#](https://github.com/wailsapp/wails/pull/4234) - -### Fixed - -- Fixed nil pointer dereference in processURLRequest for Mac by [@etesam913](https://github.com/etesam913) in [#4366](https://github.com/wailsapp/wails/pull/4366) -- Fixed a linux bug preventing filtered dialogs by [@bh90210](https://github.com/bh90210) in [#4287](https://github.com/wailsapp/wails/pull/4287) -- Fixed Windows+Linux Edit Menu issues by [@leaanthony](https://github.com/leaanthony) in [#3f78a3a](https://github.com/wailsapp/wails/commit/3f78a3a8ce7837e8b32242c8edbbed431c68c062) -- Updated the minimum system version in macOS .plist files from 10.13.0 to 10.15.0 by [@AkshayKalose](https://github.com/AkshayKalose) in [#3981](https://github.com/wailsapp/wails/pull/3981) -- Window ID skip issue by [@leaanthony](https://github.com/leaanthony) -- Fix nil menu issue when calling RegisterContextMenu by [@leaanthony](https://github.com/leaanthony) -- Fixed dependency cycles in binding generator output by [@fbbdev](https://github.com/fbbdev) in [#4001](https://github.com/wailsapp/wails/pull/4001) -- Fixed use-before-define errors in binding generator output by [@fbbdev](https://github.com/fbbdev) in [#4001](https://github.com/wailsapp/wails/pull/4001) -- Pass build flags to binding generator by [@fbbdev](https://github.com/fbbdev) in [#4023](https://github.com/wailsapp/wails/pull/4023) -- Change paths in windows Taskfile to forward slashes to ensure it works on non-Windows platforms by [@leaanthony](https://github.com/leaanthony) -- Mac + Mac JS events now fixed by [@leaanthony](https://github.com/leaanthony) -- Fixed event deadlock for macOS by [@leaanthony](https://github.com/leaanthony) -- Fixed a `Parameter incorrect` error in Window initialisation on Windows when HTML provided but no JS by [@leaanthony](https://github.com/leaanthony) -- Fixed size of response prefix used for content type sniffing in asset server by [@fbbdev](https://github.com/fbbdev) in [#4049](https://github.com/wailsapp/wails/pull/4049) -- Fixed handling of non-404 responses on root index path in asset server by [@fbbdev](https://github.com/fbbdev) in [#4049](https://github.com/wailsapp/wails/pull/4049) -- Fixed undefined behaviour in binding generator when testing properties of generic types by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) -- Fixed binding generator output for models when underlying type has not the same properties as named wrapper by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) -- Fixed binding generator output for map key types and preprocessing by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) -- Fixed binding generator output for structs that implement marshaler interfaces by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) -- Fixed detection of type cycles involving generic types in binding generator by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) -- Fixed invalid references to unexported models in binding generator output by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) -- Moved injected code to the end of service files by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) -- Fixed handling of errors from file close operations in binding generator by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) -- Suppressed warnings for services that define lifecycle or http methods but no other bound methods by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) -- Fixed non-React templates failing to display Hello World footer when using light system colour scheme by [@marcus-crane](https://github.com/marcus-crane) in [#4056](https://github.com/wailsapp/wails/pull/4056) -- Fixed hidden menu items on macOS by [@leaanthony](https://github.com/leaanthony) -- Fixed handling and formatting of errors in message processors by [@fbbdev](https://github.com/fbbdev) in [#4066](https://github.com/wailsapp/wails/pull/4066) --  Fixed skipped service shutdown when quitting application by [@fbbdev](https://github.com/fbbdev) in [#4066](https://github.com/wailsapp/wails/pull/4066) --  Ensure menu updates occur on the main thread by [@leaanthony](https://github.com/leaanthony) -- The dragging and resizing mechanism is now more robust and matches expected platform behaviour more closely by [@fbbdev](https://github.com/fbbdev) in [#4100](https://github.com/wailsapp/wails/pull/4100) -- Fixed [#4097](https://github.com/wailsapp/wails/issues/4097) Webpack/angular discards runtime init code by [@fbbdev](https://github.com/fbbdev) in [#4100](https://github.com/wailsapp/wails/pull/4100) -- Fixed initially-hidden menu items by [@IanVS](https://github.com/IanVS) in [#4116](https://github.com/wailsapp/wails/pull/4116) -- Fixed assetFileServer not serving `.html` files when non-extension request when `[request]` doesn't exist but `[request].html` does -- Fixed icon generation paths by [@robin-samuel](https://github.com/robin-samuel) in [#4125](https://github.com/wailsapp/wails/pull/4125) -- Fixed `fullscreen`, `unfullscreen`, `unminimise` and `unmaximise` events not being emitted by [@oSethoum](https://github.com/osethoum) in [#4130](https://github.com/wailsapp/wails/pull/4130) -- Fixed NSIS Error because of incorrect prefix on default version in config by [@robin-samuel](https://github.com/robin-samuel) in [#4126](https://github.com/wailsapp/wails/pull/4126) -- Fixed Dialogs runtime function returning escaped paths on Windows by [TheGB0077](https://github.com/TheGB0077) in [#4188](https://github.com/wailsapp/wails/pull/4188) -- Fixed Webview2 detection path in HKCU by [@leaanthony](https://github.com/leaanthony). -- Fixed input issue with macOS by [@leaanthony](https://github.com/leaanthony). -- Fixed Windows icon generation task file name by [@yulesxoxo](https://github.com/yulesxoxo) in [#4219](https://github.com/wailsapp/wails/pull/4219). -- Fixed transparency issue for frameless windows by [@leaanthony](https://github.com/leaanthony) based on work by @kron. -- Fixed focus calls when window is disabled or minimised by [@leaanthony](https://github.com/leaanthony) based on work by @kron. -- Fixed system trays not showing after taskbar restarts by [@leaanthony](https://github.com/leaanthony) based on work by @kron. -- Fixed fallbackResponseWriter not implementing Flush() in [#4245](https://github.com/wailsapp/wails/pull/4245) -- Fixed fallbackResponseWriter not implementing Flush() by [@superDingda] in [#4236](https://github.com/wailsapp/wails/issues/4236) -- Fixed macOS window close with pending async Go-bound function call crashes by [@joshhardy](https://github.com/joshhardy) in [#4354](https://github.com/wailsapp/wails/pull/4354) -- Fixed Windows Efficiency mode startup race condition by [@leaanthony](https://github.com/leaanthony) -- Fixed Windows icon handle cleanup by [@leaanthony](https://github.com/leaanthony). -- Fixed `OpenFileManager` on Windows by [@PPTGamer](https://github.com/PPTGamer) in [#4375](https://github.com/wailsapp/wails/pull/4375). - -### Changed - -- Removed `application.WindowIDKey` and `application.WindowNameKey` (replaced by `application.WindowKey`) by [@leaanthony](https://github.com/leaanthony) -- ContextMenuData now returns a string instead of any by [@leaanthony](https://github.com/leaanthony) -- In JS/TS bindings, class fields of fixed-length array types are now initialized with their expected length instead of being empty by [@fbbdev](https://github.com/fbbdev) in [#4001](https://github.com/wailsapp/wails/pull/4001) -- ContextMenuData now returns a string instead of any by [@leaanthony](https://github.com/leaanthony) -- `application.NewService` does not accept options as an optional parameter anymore (use `application.NewServiceWithOptions` instead) by [@leaanthony](https://github.com/leaanthony) in [#4024](https://github.com/wailsapp/wails/pull/4024) -- Removed `nanoid` dependency by [@leaanthony](https://github.com/leaanthony) -- Updated Window example for mica/acrylic/tabbed window styles by [@leaanthony](https://github.com/leaanthony) -- In JS/TS bindings, `internal.js/ts` model files have been removed; all models can now be found in `models.js/ts` by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) -- In JS/TS bindings, named types are never rendered as aliases for other named types; the old behaviour is now restricted to aliases by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) -- In JS/TS bindings, in class mode, struct fields whose type is a type parameter are marked optional and never initialised automatically by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) -- Remove ESLint from templates by by [@IanVS](https://github.com/IanVS) in [#4059](https://github.com/wailsapp/wails/pull/4059) -- Update copyright date to 2025 by [@IanVS](https://github.com/IanVS) in [#4037](https://github.com/wailsapp/wails/pull/4037) -- Add docs for event.Sender by [@IanVS](https://github.com/IanVS) in [#4075](https://github.com/wailsapp/wails/pull/4075) -- Go 1.24 support by [@leaanthony](https://github.com/leaanthony) -- `ServiceStartup` hooks are now invoked when `App.Run` is called, not in `application.New` by [@fbbdev](https://github.com/fbbdev) in [#4066](https://github.com/wailsapp/wails/pull/4066) -- `ServiceStartup` errors are now returned from `App.Run` instead of terminating the process by [@fbbdev](https://github.com/fbbdev) in [#4066](https://github.com/wailsapp/wails/pull/4066) -- Binding and dialog calls from JS now reject with error objects instead of strings by [@fbbdev](https://github.com/fbbdev) in [#4066](https://github.com/wailsapp/wails/pull/4066) -- Improved systray menu positioning on Windows by [@leaanthony](https://github.com/leaanthony) -- The JS runtime has been ported to TypeScript by [@fbbdev](https://github.com/fbbdev) in [#4100](https://github.com/wailsapp/wails/pull/4100) -- The runtime initialises as soon as it is imported, no need to wait for the window to load by [@fbbdev](https://github.com/fbbdev) in [#4100](https://github.com/wailsapp/wails/pull/4100) -- The runtime does not export an init method anymore. A side effects import can be used to initialise it by [@fbbdev](https://github.com/fbbdev) in [#4100](https://github.com/wailsapp/wails/pull/4100) -- Bound methods now return a `CancellablePromise` that rejects with a `CancelError` if cancelled. The actual result of the call is discarded by [@fbbdev](https://github.com/fbbdev) in [#4100](https://github.com/wailsapp/wails/pull/4100) -- Built-in service types are now consistently called `Service` by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) -- Built-in service creation functions with options are now consistently called `NewWithConfig` by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) -- `Select` method on `sqlite` service is now named `Query` for consistency with Go APIs by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) -- Templates: moved runtime to "dependencies", organized package.json files by [@IanVS](https://github.com/IanVS) in [#4133](https://github.com/wailsapp/wails/pull/4133) -- Creates and ad-hoc signs app bundles in dev to enable certain macOS APIs by [@popaprozac](https://github.com/popaprozac) in [#4171](https://github.com/wailsapp/wails/pull/4171) - -## v3.0.0-alpha.9 - 2025-01-13 - -### Added - -- `app.OpenFileManager(path string, selectFile bool)` to open the system file manager to the path `path` with optional highlighting via `selectFile` by [@Krzysztofz01](https://github.com/Krzysztofz01) [@rcalixte](https://github.com/rcalixte) -- New `-git` flag for `wails3 init` command by [@leaanthony](https://github.com/leaanthony) -- New `wails3 generate webview2bootstrapper` command by [@leaanthony](https://github.com/leaanthony) -- Added `init()` method in runtime to allow manual initialisation of the runtime by [@leaanthony](https://github.com/leaanthony) -- Added `WindowDidMoveDebounceMS` option to Window's WindowOptions by [@leaanthony](https://github.com/leaanthony) -- Added Single Instance feature by [@leaanthony](https://github.com/leaanthony). Based on the [v2 PR](https://github.com/wailsapp/wails/pull/2951) by @APshenkin. -- `wails3 generate template` command by [@leaanthony](https://github.com/leaanthony) -- `wails3 releasenotes` command by [@leaanthony](https://github.com/leaanthony) -- `wails3 update cli` command by [@leaanthony](https://github.com/leaanthony) -- `-clean` option for `wails3 generate bindings` command by [@leaanthony](https://github.com/leaanthony) -- Allow for aarch64 (arm64) AppImage Linux builds by [@AkshayKalose](https://github.com/AkshayKalose) in [#3981](https://github.com/wailsapp/wails/pull/3981) - -### Fixed - -- Fixed min/max width options for linux by @atterpac in [#3979](https://github.com/wailsapp/wails/pull/3979) -- Typescript templates types definitions via npm version bump by @atterpac in [#3966](https://github.com/wailsapp/wails/pull/3966) -- Fix Sveltekit template CSS referance by @atterpac in [#3945](https://github.com/wailsapp/wails/pull/3945) -- Ensure key callbacks in window run() are called on the main thread by [@leaanthony](https://github.com/leaanthony) -- Fix dialog directory chooser examples by [@leaanthony](https://github.com/leaanthony) -- Created new Chinese error page when index.html is missing by [@leaanthony](https://github.com/leaanthony) --  Ensure `windowDidBecomeKey` callback is running on main thread by [@leaanthony](https://github.com/leaanthony) --  Support fullscreen for frameless windows by [@leaanthony](https://github.com/leaanthony) --  Improved window destroying logic by [@leaanthony](https://github.com/leaanthony) --  Fix window position logic when attached to system trays by [@leaanthony](https://github.com/leaanthony) --  Support fullscreen for frameless windows by [@leaanthony](https://github.com/leaanthony) -- Fix event handling by [@leaanthony](https://github.com/leaanthony) -- Fixed window shutdown logic by [@leaanthony](https://github.com/leaanthony) -- Common taskfile now defaults to generating Typescript bindings for Typescript templates by [@leaanthony](https://github.com/leaanthony) -- Fix Close application on WM_CLOSE message when no windows are open/systray only by [@mmalcek](https://github.com/mmalcek) in [#3990](https://github.com/wailsapp/wails/pull/3990) -- Fixed garble build by @5aaee9 in [#3192](https://github.com/wailsapp/wails/pull/3192) -- Fixed windows nsis builds by [@leaanthony](https://github.com/leaanthony) - -### Changed - -- Moved build assets to platform specific directories by [@leaanthony](https://github.com/leaanthony) -- Moved and renamed Taskfiles to platform specific directories by [@leaanthony](https://github.com/leaanthony) -- Created a much better experience when `index.html` is missing by [@leaanthony](https://github.com/leaanthony) -- [Windows] Improved performance of minimise and restore by [@leaanthony](https://github.com/leaanthony). Based on original [PR](https://github.com/wailsapp/wails/pull/3955) by [562589540](https://github.com/562589540) -- Removed `ShouldClose` option (Register a hook for events.Common.WindowClosing instead) by [@leaanthony](https://github.com/leaanthony) -- [Windows] Reduced flicker when opening a window by [@leaanthony](https://github.com/leaanthony) -- Removed `Window.Destroy` as this was intended to be an internal function by [@leaanthony](https://github.com/leaanthony) -- Renamed `WindowClose` events to `WindowClosing` by [@leaanthony](https://github.com/leaanthony) -- Frontend builds now use vite environment "development" or "production" depending on build type by [@leaanthony](https://github.com/leaanthony) -- Update to go-webview2 v1.19 by [@leaanthony](https://github.com/leaanthony) - -## v3.0.0-alpha.8.3 - 2024-12-07 - -### Changed - -- Ensure fork of taskfile is used by @leaanthony - -## v3.0.0-alpha.8.2 - 2024-12-07 - -### Changed - -- Update fork of Taskfile to fix version issues when installing using - `go install` by @leaanthony - -## v3.0.0-alpha.8.1 - 2024-12-07 - -### Changed - -- Using fork of Taskfile to fix version issues when installing using - `go install` by @leaanthony - -## v3.0.0-alpha.8 - 2024-12-06 - -### Added - -- Added hyperlink for sponsor by @ansxuman in [#3958](https://github.com/wailsapp/wails/pull/3958) -- Support of linux packaging of deb,rpm, and arch linux packager builds by - @atterpac in [#3909](https://github.com/wailsapp/wails/3909) -- Added Support for darwin universal builds and packages by - [ansxuman](https://github.com/ansxuman) in - [#3902](https://github.com/wailsapp/wails/pull/3902) -- Events documentation to the website by - [atterpac](https://github.com/atterpac) in - [#3867](https://github.com/wailsapp/wails/pull/3867) -- Templates for sveltekit and sveltekit-ts that are set for non-SSR development - by [atterpac](https://github.com/atterpac) in - [#3829](https://github.com/wailsapp/wails/pull/3829) -- Update build assets using new `wails3 update build-assets` command by - [leaanthony](https://github.com/leaanthony) -- Example to test the HTML Drag and Drop API by - [FerroO2000](https://github.com/FerroO2000) in - [#3856](https://github.com/wailsapp/wails/pull/3856) -- File Association support by [leaanthony](https://github.com/leaanthony) in - [#3873](https://github.com/wailsapp/wails/pull/3873) -- New `wails3 generate runtime` command by - [leaanthony](https://github.com/leaanthony) -- New `InitialPosition` option to specify if the window should be centered or - positioned at the given X/Y location by - [leaanthony](https://github.com/leaanthony) in - [#3885](https://github.com/wailsapp/wails/pull/3885) -- Add `Path` & `Paths` methods to `application` package by - [ansxuman](https://github.com/ansxuman) and - [leaanthony](https://github.com/leaanthony) in - [#3823](https://github.com/wailsapp/wails/pull/3823) -- Added `GeneralAutofillEnabled` and `PasswordAutosaveEnabled` Windows options - by [leaanthony](https://github.com/leaanthony) in - [#3766](https://github.com/wailsapp/wails/pull/3766) -- Added the ability to retrieve the window calling a service method by - [leaanthony](https://github.com/leaanthony) in - [#3888](https://github.com/wailsapp/wails/pull/3888) -- Added `EnabledFeatures` and `DisabledFeatures` options for Webview2 by - [leaanthony](https://github.com/leaanthony). -- - -### Changed - -- `service.OnStartup` now shutdowns the application on error and runs - `service.OnShutdown`for any prior services that started by @atterpac in - [#3920](https://github.com/wailsapp/wails/pull/3920) -- Refactored systray click messaging to better align with user interactions by - @atterpac in [#3907](https://github.com/wailsapp/wails/pull/3907) -- Asset embed to include `all:frontend/dist` to support frameworks that generate - subfolders by @atterpac in - [#3887](https://github.com/wailsapp/wails/pull/3887) -- Taskfile refactor by [leaanthony](https://github.com/leaanthony) in - [#3748](https://github.com/wailsapp/wails/pull/3748) -- Upgrade to `go-webview2` v1.0.16 by - [leaanthony](https://github.com/leaanthony) -- Fixed `Screen` type to include `ID` not `Id` by - [etesam913](https://github.com/etesam913) in - [#3778](https://github.com/wailsapp/wails/pull/3778) -- Update `go.mod.tmpl` wails version to support `application.ServiceOptions` by - [northes](https://github.com/northes) in - [#3836](https://github.com/wailsapp/wails/pull/3836) -- Fixed service name determination by [windom](https://github.com/windom/) in - [#3827](https://github.com/wailsapp/wails/pull/3827) -- mkdocs serve now uses docker by [leaanthony](https://github.com/leaanthony) -- Consolidated dev config into `config.yml` by - [leaanthony](https://github.com/leaanthony) -- Systray dialog now defaults to the application icon if available (Windows) by - [@leaanthony](https://github.com/leaanthony) -- Better reporting of GPU + Memory for macOS by - [@leaanthony](https://github.com/leaanthony) -- Removed `WebviewGpuIsDisabled` and `EnableFraudulentWebsiteWarnings` - (superseded by `EnabledFeatures` and `DisabledFeatures` options) by - [leaanthony](https://github.com/leaanthony) - -### Fixed - -- Fixed deadlock in Linux dialog for multiple selections caused by unclosed - channel variable by @michael-freling in - [#3925](https://github.com/wailsapp/wails/pull/3925) -- Fixed cross-platform cleanup for .syso files during Windows build by - [ansxuman](https://github.com/ansxuman) in - [#3924](https://github.com/wailsapp/wails/pull/3924) -- Fixed amd64 appimage compile by @atterpac in - [#3898](https://github.com/wailsapp/wails/pull/3898) -- Fixed build assets update by @ansxuman in - [#3901](https://github.com/wailsapp/wails/pull/3901) -- Fixed Linux systray `OnClick` and `OnRightClick` implementation by @atterpac - in [#3886](https://github.com/wailsapp/wails/pull/3886) -- Fixed `AlwaysOnTop` not working on Mac by - [leaanthony](https://github.com/leaanthony) in - [#3841](https://github.com/wailsapp/wails/pull/3841) --  Fixed `application.NewEditMenu` including a duplicate - `PasteAndMatchStyle` role in the edit menu on Darwin by - [johnmccabe](https://github.com/johnmccabe) in - [#3839](https://github.com/wailsapp/wails/pull/3839) -- 🐧 Fixed aarch64 compilation - [#3840](https://github.com/wailsapp/wails/issues/3840) in - [#3854](https://github.com/wailsapp/wails/pull/3854) by - [kodflow](https://github.com/kodflow) -- ⊞ Fixed radio group menu items by - [@leaanthony](https://github.com/leaanthony) -- Fix error on building runnable .app on MacOS when 'name' and 'outputfilename' - are different. by @nickisworking in - [#3789](https://github.com/wailsapp/wails/pull/3789) - -## v3.0.0-alpha.7 - 2024-09-18 - -### Added - -- ⊞ New DIP system for Enhanced High DPI Monitor Support by - [mmghv](https://github.com/mmghv) in - [#3665](https://github.com/wailsapp/wails/pull/3665) -- ⊞ Window class name option by [windom](https://github.com/windom/) in - [#3682](https://github.com/wailsapp/wails/pull/3682) -- Services have been expanded to provide plugin functionality. By - [atterpac](https://github.com/atterpac) and - [leaanthony](https://github.com/leaanthony) in - [#3570](https://github.com/wailsapp/wails/pull/3570) - -### Changed - -- Events API change: `On`/`Emit` -> user events, `OnApplicationEvent` -> - Application Events `OnWindowEvent` -> Window Events, by - [leaanthony](https://github.com/leaanthony) -- Fix for Events API on Linux by [TheGB0077](https://github.com/TheGB0077) in - [#3734](https://github.com/wailsapp/wails/pull/3734) -- [CI] improvements to actions & enable to run actions also in forks and - branches prefixed with `v3/` or `v3-` by - [stendler](https://github.com/stendler) in - [#3747](https://github.com/wailsapp/wails/pull/3747) - -### Fixed - -- Fixed bug with usage of customEventProcessor in drag-n-drop example by - [etesam913](https://github.com/etesam913) in - [#3742](https://github.com/wailsapp/wails/pull/3742) -- 🐧 Fixed linux compile error introduced by IgnoreMouseEvents addition by - [atterpac](https://github.com/atterpac) in - [#3721](https://github.com/wailsapp/wails/pull/3721) -- ⊞ Fixed syso icon file generation bug by - [atterpac](https://github.com/atterpac) in - [#3675](https://github.com/wailsapp/wails/pull/3675) -- 🐧 Fix to run natively in wayland incorporated from - [#1811](https://github.com/wailsapp/wails/pull/1811) in - [#3614](https://github.com/wailsapp/wails/pull/3614) by - [@stendler](https://github.com/stendler) -- Do not bind internal service methods in - [#3720](https://github.com/wailsapp/wails/pull/3720) by - [leaanthony](https://github.com/leaanthony) -- ⊞ Fixed system tray startup panic in - [#3693](https://github.com/wailsapp/wails/issues/3693) by - [@DeltaLaboratory](https://github.com/DeltaLaboratory) -- Do not bind internal service methods in - [#3720](https://github.com/wailsapp/wails/pull/3720) by - [leaanthony](https://github.com/leaanthony) -- ⊞ Fixed system tray startup panic in - [#3693](https://github.com/wailsapp/wails/issues/3693) by - [@DeltaLaboratory](https://github.com/DeltaLaboratory) -- Major menu item refactor and event handling. Mainly improves macOS for now. By - [leaanthony](https://github.com/leaanthony) -- Fix tests after plugins and event refactor in - [#3746](https://github.com/wailsapp/wails/pull/3746) by - [@stendler](https://github.com/stendler) -- ⊞ Fixed `Failed to unregister class Chrome_WidgetWin_0` warning. By - [leaanthony](https://github.com/leaanthony) - -## v3.0.0-alpha.6 - 2024-07-30 - -### Fixed - -- Module issues - -## v3.0.0-alpha.5 - 2024-07-30 - -### Added - -- 🐧 WindowDidMove / WindowDidResize events in - [#3580](https://github.com/wailsapp/wails/pull/3580) -- ⊞ WindowDidResize event in - [#3580](https://github.com/wailsapp/wails/pull/3580) --  add Event ApplicationShouldHandleReopen to be able to handle dock - icon click by @5aaee9 in [#2991](https://github.com/wailsapp/wails/pull/2991) --  add getPrimaryScreen/getScreens to impl by @tmclane in - [#2618](https://github.com/wailsapp/wails/pull/2618) --  add option for showing the toolbar in fullscreen mode on macOS by - [@fbbdev](https://github.com/fbbdev) in - [#3282](https://github.com/wailsapp/wails/pull/3282) -- 🐧 add onKeyPress logic to convert linux keypress into an accelerator - @[Atterpac](https://github.com/Atterpac) - in[#3022](https://github.com/wailsapp/wails/pull/3022]) -- 🐧 add task `run:linux` by - [@marcus-crane](https://github.com/marcus-crane) in - [#3146](https://github.com/wailsapp/wails/pull/3146) -- Export `SetIcon` method by [@almas-x](https://github.com/almas-x) in - [PR](https://github.com/wailsapp/wails/pull/3147) -- Improve `OnShutdown` by [@almas-x](https://github.com/almas-x) in - [PR](https://github.com/wailsapp/wails/pull/3189) -- Restore `ToggleMaximise` method in `Window` interface by - [@fbbdev](https://github.com/fbbdev) in - [#3281](https://github.com/wailsapp/wails/pull/3281) -- Added more information to `Environment()`. By @leaanthony in - [aba82cc](https://github.com/wailsapp/wails/commit/aba82cc52787c97fb99afa58b8b63a0004b7ff6c) - based on [PR](https://github.com/wailsapp/wails/pull/2044) by @Mai-Lapyst -- Expose the `WebviewWindow.IsFocused` method on the `Window` interface by - [@fbbdev](https://github.com/fbbdev) in - [#3295](https://github.com/wailsapp/wails/pull/3295) -- Support multiple space-separated trigger events in the WML system by - [@fbbdev](https://github.com/fbbdev) in - [#3295](https://github.com/wailsapp/wails/pull/3295) -- Add ESM exports from the bundled JS runtime script by - [@fbbdev](https://github.com/fbbdev) in - [#3295](https://github.com/wailsapp/wails/pull/3295) -- Add binding generator flag for using the bundled JS runtime script instead of - the npm package by [@fbbdev](https://github.com/fbbdev) in - [#3334](https://github.com/wailsapp/wails/pull/3334) -- Implement `setIcon` on linux by [@abichinger](https://github.com/abichinger) - in [#3354](https://github.com/wailsapp/wails/pull/3354) -- Add flag `-port` to dev command and support environment variable - `WAILS_VITE_PORT` by [@abichinger](https://github.com/abichinger) in - [#3429](https://github.com/wailsapp/wails/pull/3429) -- Add tests for bound method calls by - [@abichinger](https://github.com/abichinger) in - [#3431](https://github.com/wailsapp/wails/pull/3431) -- ⊞ add `SetIgnoreMouseEvents` for already created window by - [@bruxaodev](https://github.com/bruxaodev) in - [#3667](https://github.com/wailsapp/wails/pull/3667) --  Add ability to set a window's stacking level (order) by - [@OlegGulevskyy](https://github.com/OlegGulevskyy) in - [#3674](https://github.com/wailsapp/wails/pull/3674) - -### Fixed - -- Fixed resize event messaging by [atterpac](https://github.com/atterpac) in - [#3606](https://github.com/wailsapp/wails/pull/3606) -- 🐧Fixed theme handling error on NixOS by - [tmclane](https://github.com/tmclane) in - [#3515](https://github.com/wailsapp/wails/pull/3515) -- Fixed cross volume project install for windows by - [atterpac](https://github.com/atterac) in - [#3512](https://github.com/wailsapp/wails/pull/3512) -- Fixed react template css to show footer by - [atterpac](https://github.com/atterpac) in - [#3477](https://github.com/wailsapp/wails/pull/3477) -- Fixed zombie processes when working in devmode by updating to latest refresh - by [Atterpac](https://github.com/atterpac) in - [#3320](https://github.com/wailsapp/wails/pull/3320). -- Fixed appimage webkit file sourcing by [Atterpac](https://github.com/atterpac) - in [#3306](https://github.com/wailsapp/wails/pull/3306). -- Fixed Doctor apt package verify by [Atterpac](https://github.com/Atterpac) in - [#2972](https://github.com/wailsapp/wails/pull/2972). -- Fixed application frozen when quit (Darwin) by @5aaee9 in - [#2982](https://github.com/wailsapp/wails/pull/2982) -- Fixed background colours of examples on Windows by - [mmghv](https://github.com/mmghv) in - [#2750](https://github.com/wailsapp/wails/pull/2750). -- Fixed default context menus by [mmghv](https://github.com/mmghv) in - [#2753](https://github.com/wailsapp/wails/pull/2753). -- Fixed hex values for arrow keys on Darwin by - [jaybeecave](https://github.com/jaybeecave) in - [#3052](https://github.com/wailsapp/wails/pull/3052). -- Set drag-n-drop for windows to working. Added by - [@pylotlight](https://github.com/pylotlight) in - [PR](https://github.com/wailsapp/wails/pull/3039) -- Fixed bug for linux in doctor in the event user doesn't have proper drivers - installed. Added by [@pylotlight](https://github.com/pylotlight) in - [PR](https://github.com/wailsapp/wails/pull/3032) -- Fix dpi scaling on start up (windows). Changed by [@almas-x](https://github.com/almas-x) in - [PR](https://github.com/wailsapp/wails/pull/3145) -- Fix replace line in `go.mod` to use relative paths. Fixes Windows paths with - spaces - @leaanthony. -- Fix MacOS systray click handling when no attached window by - [thomas-senechal](https://github.com/thomas-senechal) in PR - [#3207](https://github.com/wailsapp/wails/pull/3207) -- Fix failing Windows build due to unknown option by - [thomas-senechal](https://github.com/thomas-senechal) in PR - [#3208](https://github.com/wailsapp/wails/pull/3208) -- Fix crash on windows left clicking the systray icon when not having an - attached window [tw1nk](https://github.com/tw1nk) in PR - [#3271](https://github.com/wailsapp/wails/pull/3271) -- Fix wrong baseURL when open window twice by @5aaee9 in PR - [#3273](https://github.com/wailsapp/wails/pull/3273) -- Fix ordering of if branches in `WebviewWindow.Restore` method by - [@fbbdev](https://github.com/fbbdev) in - [#3279](https://github.com/wailsapp/wails/pull/3279) -- Correctly compute `startURL` across multiple `GetStartURL` invocations when - `FRONTEND_DEVSERVER_URL` is present. - [#3299](https://github.com/wailsapp/wails/pull/3299) -- Fix the JS type of the `Screen` struct to match its Go counterpart by - [@fbbdev](https://github.com/fbbdev) in - [#3295](https://github.com/wailsapp/wails/pull/3295) -- Fix the `WML.Reload` method to ensure proper cleanup of registered event - listeners by [@fbbdev](https://github.com/fbbdev) in - [#3295](https://github.com/wailsapp/wails/pull/3295) -- Fix custom context menu closing immediately on linux by - [@abichinger](https://github.com/abichinger) in - [#3330](https://github.com/wailsapp/wails/pull/3330) -- Fix the output path and extension of model files produced by the binding - generator by [@fbbdev](https://github.com/fbbdev) in - [#3334](https://github.com/wailsapp/wails/pull/3334) -- Fix the import paths of model files in JS code produced by the binding - generator by [@fbbdev](https://github.com/fbbdev) in - [#3334](https://github.com/wailsapp/wails/pull/3334) -- Fix drag-n-drop on some linux distros by - [@abichinger](https://github.com/abichinger) in - [#3346](https://github.com/wailsapp/wails/pull/3346) -- Fix missing task for macOS when using `wails3 task dev` by - [@hfoxy](https://github.com/hfoxy) in - [#3417](https://github.com/wailsapp/wails/pull/3417) -- Fix registering events causing a nil map assignment by - [@hfoxy](https://github.com/hfoxy) in - [#3426](https://github.com/wailsapp/wails/pull/3426) -- Fix unmarshaling of bound method parameters by - [@fbbdev](https://github.com/fbbdev) in - [#3431](https://github.com/wailsapp/wails/pull/3431) -- Fix handling of multiple return values from bound methods by - [@fbbdev](https://github.com/fbbdev) in - [#3431](https://github.com/wailsapp/wails/pull/3431) -- Fix doctor detection of npm that is not installed with system package manager - by [@pekim](https://github.com/pekim) in - [#3458](https://github.com/wailsapp/wails/pull/3458) -- Fix missing MicrosoftEdgeWebview2Setup.exe. Thanks to - [@robin-samuel](https://github.com/robin-samuel). -- Fix random crash on linux due to window ID handling by @leaanthony. Based on - PR [#3466](https://github.com/wailsapp/wails/pull/3622) by - [@5aaee9](https://github.com/5aaee9). -- Fix systemTray.setIcon crashing on Linux by - [@windom](https://github.com/windom/) in - [#3636](https://github.com/wailsapp/wails/pull/3636). -- Fix Ensure Window Frame is Applied on First Call in `setFrameless` Function on - Windows by [@bruxaodev](https://github.com/bruxaodev/) in - [#3691](https://github.com/wailsapp/wails/pull/3691). - -### Changed - -- Renamed `AbsolutePosition()` to `Position()` by - [mmghv](https://github.com/mmghv) in - [#3611](https://github.com/wailsapp/wails/pull/3611) -- Update linux webkit dependency to webkit2gtk-4.1 over webkitgtk2-4.0 to - support Ubuntu 24.04 LTS by [atterpac](https://github.com/atterpac) in - [#3461](https://github.com/wailsapp/wails/pull/3461) -- The bundled JS runtime script is now an ESM module: script tags importing it - must have the `type="module"` attribute. By - [@fbbdev](https://github.com/fbbdev) in - [#3295](https://github.com/wailsapp/wails/pull/3295) -- The `@wailsio/runtime` package does not publish its API on the `window.wails` - object, and does not start the WML system. This has been done to improve - encapsulation. The WML system can be started manually if desired by calling - the new `WML.Enable` method. The bundled JS runtime script still performs both - operations automatically. By [@fbbdev](https://github.com/fbbdev) in - [#3295](https://github.com/wailsapp/wails/pull/3295) -- The Window API module `@wailsio/runtime/src/window` now exposes the containing - window object as a default export. It is not possible anymore to import - individual methods through ESM named or namespace import syntax. -- The JS window API has been updated to match the current Go `WebviewWindow` - API. Some methods have changed name or prototype, specifically: `Screen` - becomes `GetScreen`; `GetZoomLevel`/`SetZoomLevel` become `GetZoom`/`SetZoom`; - `GetZoom`, `Width` and `Height` now return values directly instead of wrapping - them within objects. By [@fbbdev](https://github.com/fbbdev) in - [#3295](https://github.com/wailsapp/wails/pull/3295) -- The binding generator now uses calls by ID by default. The `-id` CLI option - has been removed. Use the `-names` CLI option to switch back to calls by name. - By [@fbbdev](https://github.com/fbbdev) in - [#3468](https://github.com/wailsapp/wails/pull/3468) -- New binding code layout: output files were previously organised in folders - named after their containing package; now full Go import paths are used, - including the module path. By [@fbbdev](https://github.com/fbbdev) in - [#3468](https://github.com/wailsapp/wails/pull/3468) -- The struct field `application.Options.Bind` has been renamed to - `application.Options.Services`. By [@fbbdev](https://github.com/fbbdev) in - [#3468](https://github.com/wailsapp/wails/pull/3468) -- New syntax for binding services: service instances must now be wrapped in a - call to `application.NewService`. By [@fbbdev](https://github.com/fbbdev) in - [#3468](https://github.com/wailsapp/wails/pull/3468) -- Disable spinner on Non-Terminal or CI Environment by - [@DeltaLaboratory](https://github.com/DeltaLaboratory) in - [#3574](https://github.com/wailsapp/wails/pull/3574) +- Fixed redefinition error for liquid glass demo in [#4542](https://github.com/wailsapp/wails/pull/4542) by @Etesam913 + + +## v3.0.0-alpha.26 - 2025-08-24 + +## Added +- Add native Liquid Glass effect support for macOS with NSGlassEffectView (macOS 15.0+) and NSVisualEffectView fallback, including comprehensive material customization options by @leaanthony in [#4534](https://github.com/wailsapp/wails/pull/4534) + +## v3.0.0-alpha.25 - 2025-08-16 + +## Changed +- When running `wails3 update build-assets` with the `-config` parameter, values set via the `-product*` parameters are + no longer ignored, and override the config value. + +## v3.0.0-alpha.24 - 2025-08-13 + +## Added +- Browser URL Sanitisation by @leaanthony in [#4500](https://github.dev/wailsapp/wails/pull/4500). Based on [#4484](https://github.com/wailsapp/wails/pull/4484) by @APShenkin. + +## v3.0.0-alpha.23 - 2025-08-11 + +## Fixed +- Fix SetBackgroundColour on Windows by @PPTGamer in [PR](https://github.com/wailsapp/wails/pull/4492) + +## v3.0.0-alpha.22 - 2025-08-10 + +## Added +- Add Content Protection on Windows/Mac by [@leaanthony](https://github.com/leaanthony) based on the original work of [@Taiterbase](https://github.com/Taiterbase) in this [PR](https://github.com/wailsapp/wails/pull/4241) +- Add support for passing CLI variables to Task commands through `wails3 build` and `wails3 package` aliases (#4422) by @leaanthony in [PR](https://github.com/wailsapp/wails/pull/4488) + +## Changed +- `window.NativeWindowHandle()` -> `window.NativeWindow()` by @leaanthony in [#4471](https://github.com/wailsapp/wails/pull/4471) +- Refactor internal window handling by @leaanthony in [#4471](https://github.com/wailsapp/wails/pull/4471) ++ Fix extra-broad Linux package dependencies, fix outdated RPM dependencies. + +## v3.0.0-alpha.21 - 2025-08-07 + +## Fixed +- Update docs to reflect changes from Manager API Refactoring by @yulesxoxo in [PR #4476](https://github.com/wailsapp/wails/pull/4476) +- Fix Linux .desktop file appicon variable in Linux taskfile [PR #4477](https://github.com/wailsapp/wails/pull/4477) + +## v3.0.0-alpha.20 - 2025-08-06 + +## Fixed +- Update docs to reflect changes from Manager API Refactoring by @yulesxoxo in [PR #4476](https://github.com/wailsapp/wails/pull/4476) + +## v3.0.0-alpha.19 - 2025-08-05 + +## Added +- Support for dropzones with event sourcing dropped element data [@atterpac](https://github.com/atterpac) in [#4318](https://github.com/wailsapp/wails/pull/4318) +- Added `AdditionalLaunchArgs` to `WindowsWindow` options to allow for additional command line arguments to be passed to the WebView2 browser. in [PR](https://github.com/wailsapp/wails/pull/4467) +- Added Run go mod tidy automatically after wails init [@triadmoko](https://github.com/triadmoko) in [PR](https://github.com/wailsapp/wails/pull/4286) +- Windows Snapassist feature by @leaanthony in [PR](https://github.dev/wailsapp/wails/pull/4463) + +## Fixed +- Fix Windows nil pointer dereference bug reported in [#4456](https://github.com/wailsapp/wails/issues/4456) by @leaanthony in [#4460](https://github.com/wailsapp/wails/pull/4460) +- Add support for `allowsBackForwardNavigationGestures` in macOS WKWebView to enable two-finger swipe navigation gestures (#1857) +- Fixes issue where onClick didn't work for menu items initially set as disabled by @leaanthony in [PR #4469](https://github.com/wailsapp/wails/pull/4469). Thanks to @IanVS for the initial investigation. +- Fix Vite server not being cleaned up when build fails (#4403) +- Fixed panic when closing or cancelling a `SaveFileDialog` on windows. Fixed in [PR](https://github.com/wailsapp/wails/pull/4284) by @hkhere +- Fixed HTML level drag and drop on Windows by [@mbaklor](https://github.com/mbaklor) in [#4259](https://github.com/wailsapp/wails/pull/4259) + +## v3.0.0-alpha.18 - 2025-08-03 + +## Added +- Added `AdditionalLaunchArgs` to `WindowsWindow` options to allow for additional command line arguments to be passed to the WebView2 browser. in [PR](https://github.com/wailsapp/wails/pull/4467) +- Added Run go mod tidy automatically after wails init [@triadmoko](https://github.com/triadmoko) in [PR](https://github.com/wailsapp/wails/pull/4286) +- Windows Snapassist feature by @leaanthony in [PR](https://github.dev/wailsapp/wails/pull/4463) + +## Fixed +- Add support for `allowsBackForwardNavigationGestures` in macOS WKWebView to enable two-finger swipe navigation gestures (#1857) +- Fixes issue where onClick didn't work for menu items initially set as disabled by @leaanthony in [PR #4469](https://github.com/wailsapp/wails/pull/4469). Thanks to @IanVS for the initial investigation. +- Fix Vite server not being cleaned up when build fails (#4403) + +## v3.0.0-alpha.17 - 2025-07-31 + +## Fixed +- Fixed notification parsing on Windows @popaprozac in [PR](https://github.com/wailsapp/wails/pull/4450) + +## v3.0.0-alpha.16 - 2025-07-25 + +## Added +- Add Windows `getAccentColor` implementation by [@almas-x](https://github.com/almas-x) in [PR](https://github.com/wailsapp/wails/pull/4427) + +## v3.0.0-alpha.15 - 2025-07-25 + +## Added +- Add Windows `getAccentColor` implementation by [@almas-x](https://github.com/almas-x) in [PR](https://github.com/wailsapp/wails/pull/4427) + +## v3.0.0-alpha.14 - 2025-07-25 + +## Added +- Windows dark theme menus + menubar. By @leaanthony in [a29b4f0861b1d0a700e9eb213c6f1076ec40efd5](https://github.com/wailsapp/wails/commit/a29b4f0861b1d0a700e9eb213c6f1076ec40efd5) +- Rename built-in services for clearer JS/TS bindings by @popaprozac in [PR](https://github.com/wailsapp/wails/pull/4405) + +## v3.0.0-alpha.12 - 2025-07-15 + +### Added +- `app.Env.GetAccentColor` to get the accent color of a user's system. Works on MacOS. by [@etesam913](https://github.com/etesam913) +- Add `window.ToggleFrameless()` api by [@atterpac](https://github.com/atterpac) in [#4137](https://github.com/wailsapp/wails/pull/4137) + +### Fixed +- Fixed doctor command to check for Windows SDK dependencies by [@kodumulo](https://github.com/kodumulo) in [#4390](https://github.com/wailsapp/wails/issues/4390) + + +## v3.0.0-alpha.11 - 2025-07-12 + +## Added +- Add distribution-specific build dependencies for Linux by @leaanthony in [PR](https://github.com/wailsapp/wails/pull/4345) +- Added bindings guide by @atterpac in [PR](https://github.com/wailsapp/wails/pull/4404) + +## v3.0.0-alpha.10 - 2025-07-06 + +### Breaking Changes +- **Manager API Refactoring**: Reorganized application API from flat structure to organized managers for better code organization and discoverability by [@leaanthony](https://github.com/leaanthony) in [#4359](https://github.com/wailsapp/wails/pull/4359) + - `app.NewWebviewWindow()` → `app.Window.New()` + - `app.CurrentWindow()` → `app.Window.Current()` + - `app.GetAllWindows()` → `app.Window.GetAll()` + - `app.WindowByName()` → `app.Window.GetByName()` + - `app.EmitEvent()` → `app.Event.Emit()` + - `app.OnApplicationEvent()` → `app.Event.OnApplicationEvent()` + - `app.OnWindowEvent()` → `app.Event.OnWindowEvent()` + - `app.SetApplicationMenu()` → `app.Menu.SetApplicationMenu()` + - `app.OpenFileDialog()` → `app.Dialog.OpenFile()` + - `app.SaveFileDialog()` → `app.Dialog.SaveFile()` + - `app.MessageDialog()` → `app.Dialog.Message()` + - `app.InfoDialog()` → `app.Dialog.Info()` + - `app.WarningDialog()` → `app.Dialog.Warning()` + - `app.ErrorDialog()` → `app.Dialog.Error()` + - `app.QuestionDialog()` → `app.Dialog.Question()` + - `app.NewSystemTray()` → `app.SystemTray.New()` + - `app.GetSystemTray()` → `app.SystemTray.Get()` + - `app.ShowContextMenu()` → `app.ContextMenu.Show()` + - `app.RegisterKeybinding()` → `app.KeyBinding.Register()` + - `app.UnregisterKeybinding()` → `app.KeyBinding.Unregister()` + - `app.GetPrimaryScreen()` → `app.Screen.GetPrimary()` + - `app.GetAllScreens()` → `app.Screen.GetAll()` + - `app.BrowserOpenURL()` → `app.Browser.OpenURL()` + - `app.Environment()` → `app.Env.GetAll()` + - `app.ClipboardGetText()` → `app.Clipboard.Text()` + - `app.ClipboardSetText()` → `app.Clipboard.SetText()` +- Renamed Service methods: `Name` -> `ServiceName`, `OnStartup` -> `ServiceStartup`, `OnShutdown` -> `ServiceShutdown` by [@leaanthony](https://github.com/leaanthony) +- Moved `Path` and `Paths` methods to `application` package by [@leaanthony](https://github.com/leaanthony) +- The application menu is now macOS only by [@leaanthony](https://github.com/leaanthony) + +### Added + +- **Organized Testing Infrastructure**: Moved Docker test files to dedicated `test/docker/` directory with optimized images and enhanced build reliability by [@leaanthony](https://github.com/leaanthony) in [#4359](https://github.com/wailsapp/wails/pull/4359) +- **Improved Resource Management Patterns**: Added proper event handler cleanup and context-aware goroutine management in examples by [@leaanthony](https://github.com/leaanthony) in [#4359](https://github.com/wailsapp/wails/pull/4359) +- Support aarch64 AppImage builds by [@AkshayKalose](https://github.com/AkshayKalose) in [#3981](https://github.com/wailsapp/wails/pull/3981) +- Add diagnostics section to `wails doctor` by [@leaanthony](https://github.com/leaanthony) +- Add window to context when calling a service method by [@leaanthony](https://github.com/leaanthony) +- Add `window-call` example to demonstrate how to know which window is calling a service by [@leaanthony](https://github.com/leaanthony) +- New Menu guide by [@leaanthony](https://github.com/leaanthony) +- Better panic handling by [@leaanthony](https://github.com/leaanthony) +- New Menu guide by [@leaanthony](https://github.com/leaanthony) +- Add doc comments for Service API by [@fbbdev](https://github.com/fbbdev) in [#4024](https://github.com/wailsapp/wails/pull/4024) +- Add function `application.NewServiceWithOptions` to initialise services with additional configuration by [@leaanthony](https://github.com/leaanthony) in [#4024](https://github.com/wailsapp/wails/pull/4024) +- Improved menu control by [@FalcoG](https://github.com/FalcoG) and [@leaanthony](https://github.com/leaanthony) in [#4031](https://github.com/wailsapp/wails/pull/4031) +- More documentation by [@leaanthony](https://github.com/leaanthony) +- Support cancellation of events in standard event listeners by [@leaanthony](https://github.com/leaanthony) +- Systray `Hide`, `Show` and `Destroy` support by [@leaanthony](https://github.com/leaanthony) +- Systray `SetTooltip` support by [@leaanthony](https://github.com/leaanthony). Original idea by [@lujihong](https://github.com/wailsapp/wails/issues/3487#issuecomment-2633242304) +- Report package path in binding generator warnings about unsupported types by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) +- Add binding generator support for generic aliases by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) +- Add binding generator support for `omitzero` JSON flag by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) +- Add `//wails:ignore` directive to prevent binding generation for chosen service methods by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) +- Add `//wails:internal` directive on services and models to allow for types that are exported in Go but not in JS/TS by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) +- Add binding generator support for constants of alias type to allow for weakly typed enums by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) +- Add binding generator tests for Go 1.24 features by [@fbbdev](https://github.com/fbbdev) in [#4068](https://github.com/wailsapp/wails/pull/4068) +- Add support for macOS 15 "Sequoia" to `OSInfo.Branding` for improved OS version detection in [#4065](https://github.com/wailsapp/wails/pull/4065) +- Add `PostShutdown` hook for running custom code after the shutdown process completes by [@fbbdev](https://github.com/fbbdev) in [#4066](https://github.com/wailsapp/wails/pull/4066) +- Add `FatalError` struct to support detection of fatal errors in custom error handlers by [@fbbdev](https://github.com/fbbdev) in [#4066](https://github.com/wailsapp/wails/pull/4066) +- Standardise and document service startup and shutdown order by [@fbbdev](https://github.com/fbbdev) in [#4066](https://github.com/wailsapp/wails/pull/4066) +- Add test harness for application startup/shutdown sequence and service startup/shutdown tests by [@fbbdev](https://github.com/fbbdev) in [#4066](https://github.com/wailsapp/wails/pull/4066) +- Add `RegisterService` method for registering services after the application has been created by [@fbbdev](https://github.com/fbbdev) in [#4066](https://github.com/wailsapp/wails/pull/4066) +- Add `MarshalError` field in application and service options for custom error handling in binding calls by [@fbbdev](https://github.com/fbbdev) in [#4066](https://github.com/wailsapp/wails/pull/4066) +- Add cancellable promise wrapper that propagates cancellation requests through promise chains by [@fbbdev](https://github.com/fbbdev) in [#4100](https://github.com/wailsapp/wails/pull/4100) +- Add the ability to tie binding call cancellation to an `AbortSignal` by [@fbbdev](https://github.com/fbbdev) in [#4100](https://github.com/wailsapp/wails/pull/4100) +- Support `data-wml-*` attributes for WML alongside the usual `wml-*` attributes by [@leaanthony](https://github.com/leaanthony) +- Add `Configure` method on all services for late configuration/dynamic reconfiguration by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) +- `fileserver` service sends a 503 Service Unavailable response when unconfigured by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) +- `kvstore` service provides an in-memory key-value store by default when unconfigured by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) +- Add `Load` method on `kvstore` service to reload data from file after config changes by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) +- Add `Clear` method on `kvstore` service to delete all keys by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) +- Add type `Level` in `log` service to provide JS-side log-level constants by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) +- Add `Log` method on `log` service to specify log-level dynamically by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) +- `sqlite` service provides an in-memory DB by default when unconfigured by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) +- Add method `Close` on `sqlite` service to close the DB manually by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) +- Add cancellation support for query methods on `sqlite` service by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) +- Add prepared statement support to `sqlite` service with JS bindings by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) +- Gin support by [Lea Anthony](https://github.com/leaanthony) in [PR](https://github.com/wailsapp/wails/pull/3537) based on the original work of [@AnalogJ](https://github.com/AnalogJ) in this [PR](https://github.com/wailsapp/wails/pull/3537) +- Fix auto save and password auto save always enabled by [@oSethoum](https://github.com/osethoum) in [#4134](https://github.com/wailsapp/wails/pull/4134) +- Add `SetMenu()` on window to allow for setting a menu on a window by [@leaanthony](https://github.com/leaanthony) +- Add Notification support by [@popaprozac](https://github.com/popaprozac) in [#4098](https://github.com/wailsapp/wails/pull/4098) +-  Add File Association support for mac by [@wimaha](https://github.com/wimaha) in [#4177](https://github.com/wailsapp/wails/pull/4177) +- Add `wails3 tool version` for semantic version bumping by [@leaanthony](https://github.com/leaanthony) +- Add badging support for macOS and Windows by [@popaprozac](https://github.com/popaprozac) in [#](https://github.com/wailsapp/wails/pull/4234) +- Add support for registered/strictly-typed events by [@fbbdev](https://github.com/fbbdev) and [@IanVS](https://github.com/IanVS) in [#4161](https://github.com/wailsapp/wails/pull/4161) +- Add the ability to register hooks for custom events by [@fbbdev](https://github.com/fbbdev) and [@IanVS](https://github.com/IanVS) in [#4161](https://github.com/wailsapp/wails/pull/4161) + +### Fixed + +- Fixed nil pointer dereference in processURLRequest for Mac by [@etesam913](https://github.com/etesam913) in [#4366](https://github.com/wailsapp/wails/pull/4366) +- Fixed a linux bug preventing filtered dialogs by [@bh90210](https://github.com/bh90210) in [#4287](https://github.com/wailsapp/wails/pull/4287) +- Fixed Windows+Linux Edit Menu issues by [@leaanthony](https://github.com/leaanthony) in [#3f78a3a](https://github.com/wailsapp/wails/commit/3f78a3a8ce7837e8b32242c8edbbed431c68c062) +- Updated the minimum system version in macOS .plist files from 10.13.0 to 10.15.0 by [@AkshayKalose](https://github.com/AkshayKalose) in [#3981](https://github.com/wailsapp/wails/pull/3981) +- Window ID skip issue by [@leaanthony](https://github.com/leaanthony) +- Fix nil menu issue when calling RegisterContextMenu by [@leaanthony](https://github.com/leaanthony) +- Fixed dependency cycles in binding generator output by [@fbbdev](https://github.com/fbbdev) in [#4001](https://github.com/wailsapp/wails/pull/4001) +- Fixed use-before-define errors in binding generator output by [@fbbdev](https://github.com/fbbdev) in [#4001](https://github.com/wailsapp/wails/pull/4001) +- Pass build flags to binding generator by [@fbbdev](https://github.com/fbbdev) in [#4023](https://github.com/wailsapp/wails/pull/4023) +- Change paths in windows Taskfile to forward slashes to ensure it works on non-Windows platforms by [@leaanthony](https://github.com/leaanthony) +- Mac + Mac JS events now fixed by [@leaanthony](https://github.com/leaanthony) +- Fixed event deadlock for macOS by [@leaanthony](https://github.com/leaanthony) +- Fixed a `Parameter incorrect` error in Window initialisation on Windows when HTML provided but no JS by [@leaanthony](https://github.com/leaanthony) +- Fixed size of response prefix used for content type sniffing in asset server by [@fbbdev](https://github.com/fbbdev) in [#4049](https://github.com/wailsapp/wails/pull/4049) +- Fixed handling of non-404 responses on root index path in asset server by [@fbbdev](https://github.com/fbbdev) in [#4049](https://github.com/wailsapp/wails/pull/4049) +- Fixed undefined behaviour in binding generator when testing properties of generic types by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) +- Fixed binding generator output for models when underlying type has not the same properties as named wrapper by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) +- Fixed binding generator output for map key types and preprocessing by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) +- Fixed binding generator output for structs that implement marshaler interfaces by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) +- Fixed detection of type cycles involving generic types in binding generator by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) +- Fixed invalid references to unexported models in binding generator output by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) +- Moved injected code to the end of service files by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) +- Fixed handling of errors from file close operations in binding generator by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) +- Suppressed warnings for services that define lifecycle or http methods but no other bound methods by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) +- Fixed non-React templates failing to display Hello World footer when using light system colour scheme by [@marcus-crane](https://github.com/marcus-crane) in [#4056](https://github.com/wailsapp/wails/pull/4056) +- Fixed hidden menu items on macOS by [@leaanthony](https://github.com/leaanthony) +- Fixed handling and formatting of errors in message processors by [@fbbdev](https://github.com/fbbdev) in [#4066](https://github.com/wailsapp/wails/pull/4066) +-  Fixed skipped service shutdown when quitting application by [@fbbdev](https://github.com/fbbdev) in [#4066](https://github.com/wailsapp/wails/pull/4066) +-  Ensure menu updates occur on the main thread by [@leaanthony](https://github.com/leaanthony) +- The dragging and resizing mechanism is now more robust and matches expected platform behaviour more closely by [@fbbdev](https://github.com/fbbdev) in [#4100](https://github.com/wailsapp/wails/pull/4100) +- Fixed [#4097](https://github.com/wailsapp/wails/issues/4097) Webpack/angular discards runtime init code by [@fbbdev](https://github.com/fbbdev) in [#4100](https://github.com/wailsapp/wails/pull/4100) +- Fixed initially-hidden menu items by [@IanVS](https://github.com/IanVS) in [#4116](https://github.com/wailsapp/wails/pull/4116) +- Fixed assetFileServer not serving `.html` files when non-extension request when `[request]` doesn't exist but `[request].html` does +- Fixed icon generation paths by [@robin-samuel](https://github.com/robin-samuel) in [#4125](https://github.com/wailsapp/wails/pull/4125) +- Fixed `fullscreen`, `unfullscreen`, `unminimise` and `unmaximise` events not being emitted by [@oSethoum](https://github.com/osethoum) in [#4130](https://github.com/wailsapp/wails/pull/4130) +- Fixed NSIS Error because of incorrect prefix on default version in config by [@robin-samuel](https://github.com/robin-samuel) in [#4126](https://github.com/wailsapp/wails/pull/4126) +- Fixed Dialogs runtime function returning escaped paths on Windows by [TheGB0077](https://github.com/TheGB0077) in [#4188](https://github.com/wailsapp/wails/pull/4188) +- Fixed Webview2 detection path in HKCU by [@leaanthony](https://github.com/leaanthony). +- Fixed input issue with macOS by [@leaanthony](https://github.com/leaanthony). +- Fixed Windows icon generation task file name by [@yulesxoxo](https://github.com/yulesxoxo) in [#4219](https://github.com/wailsapp/wails/pull/4219). +- Fixed transparency issue for frameless windows by [@leaanthony](https://github.com/leaanthony) based on work by @kron. +- Fixed focus calls when window is disabled or minimised by [@leaanthony](https://github.com/leaanthony) based on work by @kron. +- Fixed system trays not showing after taskbar restarts by [@leaanthony](https://github.com/leaanthony) based on work by @kron. +- Fixed fallbackResponseWriter not implementing Flush() in [#4245](https://github.com/wailsapp/wails/pull/4245) +- Fixed fallbackResponseWriter not implementing Flush() by [@superDingda] in [#4236](https://github.com/wailsapp/wails/issues/4236) +- Fixed macOS window close with pending async Go-bound function call crashes by [@joshhardy](https://github.com/joshhardy) in [#4354](https://github.com/wailsapp/wails/pull/4354) +- Fixed Windows Efficiency mode startup race condition by [@leaanthony](https://github.com/leaanthony) +- Fixed Windows icon handle cleanup by [@leaanthony](https://github.com/leaanthony). +- Fixed `OpenFileManager` on Windows by [@PPTGamer](https://github.com/PPTGamer) in [#4375](https://github.com/wailsapp/wails/pull/4375). + +### Changed + +- Removed `application.WindowIDKey` and `application.WindowNameKey` (replaced by `application.WindowKey`) by [@leaanthony](https://github.com/leaanthony) +- ContextMenuData now returns a string instead of any by [@leaanthony](https://github.com/leaanthony) +- In JS/TS bindings, class fields of fixed-length array types are now initialized with their expected length instead of being empty by [@fbbdev](https://github.com/fbbdev) in [#4001](https://github.com/wailsapp/wails/pull/4001) +- ContextMenuData now returns a string instead of any by [@leaanthony](https://github.com/leaanthony) +- `application.NewService` does not accept options as an optional parameter anymore (use `application.NewServiceWithOptions` instead) by [@leaanthony](https://github.com/leaanthony) in [#4024](https://github.com/wailsapp/wails/pull/4024) +- Removed `nanoid` dependency by [@leaanthony](https://github.com/leaanthony) +- Updated Window example for mica/acrylic/tabbed window styles by [@leaanthony](https://github.com/leaanthony) +- In JS/TS bindings, `internal.js/ts` model files have been removed; all models can now be found in `models.js/ts` by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) +- In JS/TS bindings, named types are never rendered as aliases for other named types; the old behaviour is now restricted to aliases by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) +- In JS/TS bindings, in class mode, struct fields whose type is a type parameter are marked optional and never initialised automatically by [@fbbdev](https://github.com/fbbdev) in [#4045](https://github.com/wailsapp/wails/pull/4045) +- Remove ESLint from templates by by [@IanVS](https://github.com/IanVS) in [#4059](https://github.com/wailsapp/wails/pull/4059) +- Update copyright date to 2025 by [@IanVS](https://github.com/IanVS) in [#4037](https://github.com/wailsapp/wails/pull/4037) +- Add docs for event.Sender by [@IanVS](https://github.com/IanVS) in [#4075](https://github.com/wailsapp/wails/pull/4075) +- Go 1.24 support by [@leaanthony](https://github.com/leaanthony) +- `ServiceStartup` hooks are now invoked when `App.Run` is called, not in `application.New` by [@fbbdev](https://github.com/fbbdev) in [#4066](https://github.com/wailsapp/wails/pull/4066) +- `ServiceStartup` errors are now returned from `App.Run` instead of terminating the process by [@fbbdev](https://github.com/fbbdev) in [#4066](https://github.com/wailsapp/wails/pull/4066) +- Binding and dialog calls from JS now reject with error objects instead of strings by [@fbbdev](https://github.com/fbbdev) in [#4066](https://github.com/wailsapp/wails/pull/4066) +- Improved systray menu positioning on Windows by [@leaanthony](https://github.com/leaanthony) +- The JS runtime has been ported to TypeScript by [@fbbdev](https://github.com/fbbdev) in [#4100](https://github.com/wailsapp/wails/pull/4100) +- The runtime initialises as soon as it is imported, no need to wait for the window to load by [@fbbdev](https://github.com/fbbdev) in [#4100](https://github.com/wailsapp/wails/pull/4100) +- The runtime does not export an init method anymore. A side effects import can be used to initialise it by [@fbbdev](https://github.com/fbbdev) in [#4100](https://github.com/wailsapp/wails/pull/4100) +- Bound methods now return a `CancellablePromise` that rejects with a `CancelError` if cancelled. The actual result of the call is discarded by [@fbbdev](https://github.com/fbbdev) in [#4100](https://github.com/wailsapp/wails/pull/4100) +- Built-in service types are now consistently called `Service` by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) +- Built-in service creation functions with options are now consistently called `NewWithConfig` by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) +- `Select` method on `sqlite` service is now named `Query` for consistency with Go APIs by [@fbbdev](https://github.com/fbbdev) in [#4067](https://github.com/wailsapp/wails/pull/4067) +- Templates: moved runtime to "dependencies", organized package.json files by [@IanVS](https://github.com/IanVS) in [#4133](https://github.com/wailsapp/wails/pull/4133) +- Creates and ad-hoc signs app bundles in dev to enable certain macOS APIs by [@popaprozac](https://github.com/popaprozac) in [#4171](https://github.com/wailsapp/wails/pull/4171) + +## v3.0.0-alpha.9 - 2025-01-13 + +### Added + +- `app.OpenFileManager(path string, selectFile bool)` to open the system file manager to the path `path` with optional highlighting via `selectFile` by [@Krzysztofz01](https://github.com/Krzysztofz01) [@rcalixte](https://github.com/rcalixte) +- New `-git` flag for `wails3 init` command by [@leaanthony](https://github.com/leaanthony) +- New `wails3 generate webview2bootstrapper` command by [@leaanthony](https://github.com/leaanthony) +- Added `init()` method in runtime to allow manual initialisation of the runtime by [@leaanthony](https://github.com/leaanthony) +- Added `WindowDidMoveDebounceMS` option to Window's WindowOptions by [@leaanthony](https://github.com/leaanthony) +- Added Single Instance feature by [@leaanthony](https://github.com/leaanthony). Based on the [v2 PR](https://github.com/wailsapp/wails/pull/2951) by @APshenkin. +- `wails3 generate template` command by [@leaanthony](https://github.com/leaanthony) +- `wails3 releasenotes` command by [@leaanthony](https://github.com/leaanthony) +- `wails3 update cli` command by [@leaanthony](https://github.com/leaanthony) +- `-clean` option for `wails3 generate bindings` command by [@leaanthony](https://github.com/leaanthony) +- Allow for aarch64 (arm64) AppImage Linux builds by [@AkshayKalose](https://github.com/AkshayKalose) in [#3981](https://github.com/wailsapp/wails/pull/3981) + +### Fixed + +- Fixed min/max width options for linux by @atterpac in [#3979](https://github.com/wailsapp/wails/pull/3979) +- Typescript templates types definitions via npm version bump by @atterpac in [#3966](https://github.com/wailsapp/wails/pull/3966) +- Fix Sveltekit template CSS referance by @atterpac in [#3945](https://github.com/wailsapp/wails/pull/3945) +- Ensure key callbacks in window run() are called on the main thread by [@leaanthony](https://github.com/leaanthony) +- Fix dialog directory chooser examples by [@leaanthony](https://github.com/leaanthony) +- Created new Chinese error page when index.html is missing by [@leaanthony](https://github.com/leaanthony) +-  Ensure `windowDidBecomeKey` callback is running on main thread by [@leaanthony](https://github.com/leaanthony) +-  Support fullscreen for frameless windows by [@leaanthony](https://github.com/leaanthony) +-  Improved window destroying logic by [@leaanthony](https://github.com/leaanthony) +-  Fix window position logic when attached to system trays by [@leaanthony](https://github.com/leaanthony) +-  Support fullscreen for frameless windows by [@leaanthony](https://github.com/leaanthony) +- Fix event handling by [@leaanthony](https://github.com/leaanthony) +- Fixed window shutdown logic by [@leaanthony](https://github.com/leaanthony) +- Common taskfile now defaults to generating Typescript bindings for Typescript templates by [@leaanthony](https://github.com/leaanthony) +- Fix Close application on WM_CLOSE message when no windows are open/systray only by [@mmalcek](https://github.com/mmalcek) in [#3990](https://github.com/wailsapp/wails/pull/3990) +- Fixed garble build by @5aaee9 in [#3192](https://github.com/wailsapp/wails/pull/3192) +- Fixed windows nsis builds by [@leaanthony](https://github.com/leaanthony) + +### Changed + +- Moved build assets to platform specific directories by [@leaanthony](https://github.com/leaanthony) +- Moved and renamed Taskfiles to platform specific directories by [@leaanthony](https://github.com/leaanthony) +- Created a much better experience when `index.html` is missing by [@leaanthony](https://github.com/leaanthony) +- [Windows] Improved performance of minimise and restore by [@leaanthony](https://github.com/leaanthony). Based on original [PR](https://github.com/wailsapp/wails/pull/3955) by [562589540](https://github.com/562589540) +- Removed `ShouldClose` option (Register a hook for events.Common.WindowClosing instead) by [@leaanthony](https://github.com/leaanthony) +- [Windows] Reduced flicker when opening a window by [@leaanthony](https://github.com/leaanthony) +- Removed `Window.Destroy` as this was intended to be an internal function by [@leaanthony](https://github.com/leaanthony) +- Renamed `WindowClose` events to `WindowClosing` by [@leaanthony](https://github.com/leaanthony) +- Frontend builds now use vite environment "development" or "production" depending on build type by [@leaanthony](https://github.com/leaanthony) +- Update to go-webview2 v1.19 by [@leaanthony](https://github.com/leaanthony) + +## v3.0.0-alpha.8.3 - 2024-12-07 + +### Changed + +- Ensure fork of taskfile is used by @leaanthony + +## v3.0.0-alpha.8.2 - 2024-12-07 + +### Changed + +- Update fork of Taskfile to fix version issues when installing using + `go install` by @leaanthony + +## v3.0.0-alpha.8.1 - 2024-12-07 + +### Changed + +- Using fork of Taskfile to fix version issues when installing using + `go install` by @leaanthony + +## v3.0.0-alpha.8 - 2024-12-06 + +### Added + +- Added hyperlink for sponsor by @ansxuman in [#3958](https://github.com/wailsapp/wails/pull/3958) +- Support of linux packaging of deb,rpm, and arch linux packager builds by + @atterpac in [#3909](https://github.com/wailsapp/wails/3909) +- Added Support for darwin universal builds and packages by + [ansxuman](https://github.com/ansxuman) in + [#3902](https://github.com/wailsapp/wails/pull/3902) +- Events documentation to the website by + [atterpac](https://github.com/atterpac) in + [#3867](https://github.com/wailsapp/wails/pull/3867) +- Templates for sveltekit and sveltekit-ts that are set for non-SSR development + by [atterpac](https://github.com/atterpac) in + [#3829](https://github.com/wailsapp/wails/pull/3829) +- Update build assets using new `wails3 update build-assets` command by + [leaanthony](https://github.com/leaanthony) +- Example to test the HTML Drag and Drop API by + [FerroO2000](https://github.com/FerroO2000) in + [#3856](https://github.com/wailsapp/wails/pull/3856) +- File Association support by [leaanthony](https://github.com/leaanthony) in + [#3873](https://github.com/wailsapp/wails/pull/3873) +- New `wails3 generate runtime` command by + [leaanthony](https://github.com/leaanthony) +- New `InitialPosition` option to specify if the window should be centered or + positioned at the given X/Y location by + [leaanthony](https://github.com/leaanthony) in + [#3885](https://github.com/wailsapp/wails/pull/3885) +- Add `Path` & `Paths` methods to `application` package by + [ansxuman](https://github.com/ansxuman) and + [leaanthony](https://github.com/leaanthony) in + [#3823](https://github.com/wailsapp/wails/pull/3823) +- Added `GeneralAutofillEnabled` and `PasswordAutosaveEnabled` Windows options + by [leaanthony](https://github.com/leaanthony) in + [#3766](https://github.com/wailsapp/wails/pull/3766) +- Added the ability to retrieve the window calling a service method by + [leaanthony](https://github.com/leaanthony) in + [#3888](https://github.com/wailsapp/wails/pull/3888) +- Added `EnabledFeatures` and `DisabledFeatures` options for Webview2 by + [leaanthony](https://github.com/leaanthony). +- + +### Changed + +- `service.OnStartup` now shutdowns the application on error and runs + `service.OnShutdown`for any prior services that started by @atterpac in + [#3920](https://github.com/wailsapp/wails/pull/3920) +- Refactored systray click messaging to better align with user interactions by + @atterpac in [#3907](https://github.com/wailsapp/wails/pull/3907) +- Asset embed to include `all:frontend/dist` to support frameworks that generate + subfolders by @atterpac in + [#3887](https://github.com/wailsapp/wails/pull/3887) +- Taskfile refactor by [leaanthony](https://github.com/leaanthony) in + [#3748](https://github.com/wailsapp/wails/pull/3748) +- Upgrade to `go-webview2` v1.0.16 by + [leaanthony](https://github.com/leaanthony) +- Fixed `Screen` type to include `ID` not `Id` by + [etesam913](https://github.com/etesam913) in + [#3778](https://github.com/wailsapp/wails/pull/3778) +- Update `go.mod.tmpl` wails version to support `application.ServiceOptions` by + [northes](https://github.com/northes) in + [#3836](https://github.com/wailsapp/wails/pull/3836) +- Fixed service name determination by [windom](https://github.com/windom/) in + [#3827](https://github.com/wailsapp/wails/pull/3827) +- mkdocs serve now uses docker by [leaanthony](https://github.com/leaanthony) +- Consolidated dev config into `config.yml` by + [leaanthony](https://github.com/leaanthony) +- Systray dialog now defaults to the application icon if available (Windows) by + [@leaanthony](https://github.com/leaanthony) +- Better reporting of GPU + Memory for macOS by + [@leaanthony](https://github.com/leaanthony) +- Removed `WebviewGpuIsDisabled` and `EnableFraudulentWebsiteWarnings` + (superseded by `EnabledFeatures` and `DisabledFeatures` options) by + [leaanthony](https://github.com/leaanthony) + +### Fixed + +- Fixed deadlock in Linux dialog for multiple selections caused by unclosed + channel variable by @michael-freling in + [#3925](https://github.com/wailsapp/wails/pull/3925) +- Fixed cross-platform cleanup for .syso files during Windows build by + [ansxuman](https://github.com/ansxuman) in + [#3924](https://github.com/wailsapp/wails/pull/3924) +- Fixed amd64 appimage compile by @atterpac in + [#3898](https://github.com/wailsapp/wails/pull/3898) +- Fixed build assets update by @ansxuman in + [#3901](https://github.com/wailsapp/wails/pull/3901) +- Fixed Linux systray `OnClick` and `OnRightClick` implementation by @atterpac + in [#3886](https://github.com/wailsapp/wails/pull/3886) +- Fixed `AlwaysOnTop` not working on Mac by + [leaanthony](https://github.com/leaanthony) in + [#3841](https://github.com/wailsapp/wails/pull/3841) +-  Fixed `application.NewEditMenu` including a duplicate + `PasteAndMatchStyle` role in the edit menu on Darwin by + [johnmccabe](https://github.com/johnmccabe) in + [#3839](https://github.com/wailsapp/wails/pull/3839) +- 🐧 Fixed aarch64 compilation + [#3840](https://github.com/wailsapp/wails/issues/3840) in + [#3854](https://github.com/wailsapp/wails/pull/3854) by + [kodflow](https://github.com/kodflow) +- ⊞ Fixed radio group menu items by + [@leaanthony](https://github.com/leaanthony) +- Fix error on building runnable .app on MacOS when 'name' and 'outputfilename' + are different. by @nickisworking in + [#3789](https://github.com/wailsapp/wails/pull/3789) + +## v3.0.0-alpha.7 - 2024-09-18 + +### Added + +- ⊞ New DIP system for Enhanced High DPI Monitor Support by + [mmghv](https://github.com/mmghv) in + [#3665](https://github.com/wailsapp/wails/pull/3665) +- ⊞ Window class name option by [windom](https://github.com/windom/) in + [#3682](https://github.com/wailsapp/wails/pull/3682) +- Services have been expanded to provide plugin functionality. By + [atterpac](https://github.com/atterpac) and + [leaanthony](https://github.com/leaanthony) in + [#3570](https://github.com/wailsapp/wails/pull/3570) + +### Changed + +- Events API change: `On`/`Emit` -> user events, `OnApplicationEvent` -> + Application Events `OnWindowEvent` -> Window Events, by + [leaanthony](https://github.com/leaanthony) +- Fix for Events API on Linux by [TheGB0077](https://github.com/TheGB0077) in + [#3734](https://github.com/wailsapp/wails/pull/3734) +- [CI] improvements to actions & enable to run actions also in forks and + branches prefixed with `v3/` or `v3-` by + [stendler](https://github.com/stendler) in + [#3747](https://github.com/wailsapp/wails/pull/3747) + +### Fixed + +- Fixed bug with usage of customEventProcessor in drag-n-drop example by + [etesam913](https://github.com/etesam913) in + [#3742](https://github.com/wailsapp/wails/pull/3742) +- 🐧 Fixed linux compile error introduced by IgnoreMouseEvents addition by + [atterpac](https://github.com/atterpac) in + [#3721](https://github.com/wailsapp/wails/pull/3721) +- ⊞ Fixed syso icon file generation bug by + [atterpac](https://github.com/atterpac) in + [#3675](https://github.com/wailsapp/wails/pull/3675) +- 🐧 Fix to run natively in wayland incorporated from + [#1811](https://github.com/wailsapp/wails/pull/1811) in + [#3614](https://github.com/wailsapp/wails/pull/3614) by + [@stendler](https://github.com/stendler) +- Do not bind internal service methods in + [#3720](https://github.com/wailsapp/wails/pull/3720) by + [leaanthony](https://github.com/leaanthony) +- ⊞ Fixed system tray startup panic in + [#3693](https://github.com/wailsapp/wails/issues/3693) by + [@DeltaLaboratory](https://github.com/DeltaLaboratory) +- Do not bind internal service methods in + [#3720](https://github.com/wailsapp/wails/pull/3720) by + [leaanthony](https://github.com/leaanthony) +- ⊞ Fixed system tray startup panic in + [#3693](https://github.com/wailsapp/wails/issues/3693) by + [@DeltaLaboratory](https://github.com/DeltaLaboratory) +- Major menu item refactor and event handling. Mainly improves macOS for now. By + [leaanthony](https://github.com/leaanthony) +- Fix tests after plugins and event refactor in + [#3746](https://github.com/wailsapp/wails/pull/3746) by + [@stendler](https://github.com/stendler) +- ⊞ Fixed `Failed to unregister class Chrome_WidgetWin_0` warning. By + [leaanthony](https://github.com/leaanthony) + +## v3.0.0-alpha.6 - 2024-07-30 + +### Fixed + +- Module issues + +## v3.0.0-alpha.5 - 2024-07-30 + +### Added + +- 🐧 WindowDidMove / WindowDidResize events in + [#3580](https://github.com/wailsapp/wails/pull/3580) +- ⊞ WindowDidResize event in + [#3580](https://github.com/wailsapp/wails/pull/3580) +-  add Event ApplicationShouldHandleReopen to be able to handle dock + icon click by @5aaee9 in [#2991](https://github.com/wailsapp/wails/pull/2991) +-  add getPrimaryScreen/getScreens to impl by @tmclane in + [#2618](https://github.com/wailsapp/wails/pull/2618) +-  add option for showing the toolbar in fullscreen mode on macOS by + [@fbbdev](https://github.com/fbbdev) in + [#3282](https://github.com/wailsapp/wails/pull/3282) +- 🐧 add onKeyPress logic to convert linux keypress into an accelerator + @[Atterpac](https://github.com/Atterpac) + in[#3022](https://github.com/wailsapp/wails/pull/3022]) +- 🐧 add task `run:linux` by + [@marcus-crane](https://github.com/marcus-crane) in + [#3146](https://github.com/wailsapp/wails/pull/3146) +- Export `SetIcon` method by [@almas-x](https://github.com/almas-x) in + [PR](https://github.com/wailsapp/wails/pull/3147) +- Improve `OnShutdown` by [@almas-x](https://github.com/almas-x) in + [PR](https://github.com/wailsapp/wails/pull/3189) +- Restore `ToggleMaximise` method in `Window` interface by + [@fbbdev](https://github.com/fbbdev) in + [#3281](https://github.com/wailsapp/wails/pull/3281) +- Added more information to `Environment()`. By @leaanthony in + [aba82cc](https://github.com/wailsapp/wails/commit/aba82cc52787c97fb99afa58b8b63a0004b7ff6c) + based on [PR](https://github.com/wailsapp/wails/pull/2044) by @Mai-Lapyst +- Expose the `WebviewWindow.IsFocused` method on the `Window` interface by + [@fbbdev](https://github.com/fbbdev) in + [#3295](https://github.com/wailsapp/wails/pull/3295) +- Support multiple space-separated trigger events in the WML system by + [@fbbdev](https://github.com/fbbdev) in + [#3295](https://github.com/wailsapp/wails/pull/3295) +- Add ESM exports from the bundled JS runtime script by + [@fbbdev](https://github.com/fbbdev) in + [#3295](https://github.com/wailsapp/wails/pull/3295) +- Add binding generator flag for using the bundled JS runtime script instead of + the npm package by [@fbbdev](https://github.com/fbbdev) in + [#3334](https://github.com/wailsapp/wails/pull/3334) +- Implement `setIcon` on linux by [@abichinger](https://github.com/abichinger) + in [#3354](https://github.com/wailsapp/wails/pull/3354) +- Add flag `-port` to dev command and support environment variable + `WAILS_VITE_PORT` by [@abichinger](https://github.com/abichinger) in + [#3429](https://github.com/wailsapp/wails/pull/3429) +- Add tests for bound method calls by + [@abichinger](https://github.com/abichinger) in + [#3431](https://github.com/wailsapp/wails/pull/3431) +- ⊞ add `SetIgnoreMouseEvents` for already created window by + [@bruxaodev](https://github.com/bruxaodev) in + [#3667](https://github.com/wailsapp/wails/pull/3667) +-  Add ability to set a window's stacking level (order) by + [@OlegGulevskyy](https://github.com/OlegGulevskyy) in + [#3674](https://github.com/wailsapp/wails/pull/3674) + +### Fixed + +- Fixed resize event messaging by [atterpac](https://github.com/atterpac) in + [#3606](https://github.com/wailsapp/wails/pull/3606) +- 🐧Fixed theme handling error on NixOS by + [tmclane](https://github.com/tmclane) in + [#3515](https://github.com/wailsapp/wails/pull/3515) +- Fixed cross volume project install for windows by + [atterpac](https://github.com/atterac) in + [#3512](https://github.com/wailsapp/wails/pull/3512) +- Fixed react template css to show footer by + [atterpac](https://github.com/atterpac) in + [#3477](https://github.com/wailsapp/wails/pull/3477) +- Fixed zombie processes when working in devmode by updating to latest refresh + by [Atterpac](https://github.com/atterpac) in + [#3320](https://github.com/wailsapp/wails/pull/3320). +- Fixed appimage webkit file sourcing by [Atterpac](https://github.com/atterpac) + in [#3306](https://github.com/wailsapp/wails/pull/3306). +- Fixed Doctor apt package verify by [Atterpac](https://github.com/Atterpac) in + [#2972](https://github.com/wailsapp/wails/pull/2972). +- Fixed application frozen when quit (Darwin) by @5aaee9 in + [#2982](https://github.com/wailsapp/wails/pull/2982) +- Fixed background colours of examples on Windows by + [mmghv](https://github.com/mmghv) in + [#2750](https://github.com/wailsapp/wails/pull/2750). +- Fixed default context menus by [mmghv](https://github.com/mmghv) in + [#2753](https://github.com/wailsapp/wails/pull/2753). +- Fixed hex values for arrow keys on Darwin by + [jaybeecave](https://github.com/jaybeecave) in + [#3052](https://github.com/wailsapp/wails/pull/3052). +- Set drag-n-drop for windows to working. Added by + [@pylotlight](https://github.com/pylotlight) in + [PR](https://github.com/wailsapp/wails/pull/3039) +- Fixed bug for linux in doctor in the event user doesn't have proper drivers + installed. Added by [@pylotlight](https://github.com/pylotlight) in + [PR](https://github.com/wailsapp/wails/pull/3032) +- Fix dpi scaling on start up (windows). Changed by [@almas-x](https://github.com/almas-x) in + [PR](https://github.com/wailsapp/wails/pull/3145) +- Fix replace line in `go.mod` to use relative paths. Fixes Windows paths with + spaces - @leaanthony. +- Fix MacOS systray click handling when no attached window by + [thomas-senechal](https://github.com/thomas-senechal) in PR + [#3207](https://github.com/wailsapp/wails/pull/3207) +- Fix failing Windows build due to unknown option by + [thomas-senechal](https://github.com/thomas-senechal) in PR + [#3208](https://github.com/wailsapp/wails/pull/3208) +- Fix crash on windows left clicking the systray icon when not having an + attached window [tw1nk](https://github.com/tw1nk) in PR + [#3271](https://github.com/wailsapp/wails/pull/3271) +- Fix wrong baseURL when open window twice by @5aaee9 in PR + [#3273](https://github.com/wailsapp/wails/pull/3273) +- Fix ordering of if branches in `WebviewWindow.Restore` method by + [@fbbdev](https://github.com/fbbdev) in + [#3279](https://github.com/wailsapp/wails/pull/3279) +- Correctly compute `startURL` across multiple `GetStartURL` invocations when + `FRONTEND_DEVSERVER_URL` is present. + [#3299](https://github.com/wailsapp/wails/pull/3299) +- Fix the JS type of the `Screen` struct to match its Go counterpart by + [@fbbdev](https://github.com/fbbdev) in + [#3295](https://github.com/wailsapp/wails/pull/3295) +- Fix the `WML.Reload` method to ensure proper cleanup of registered event + listeners by [@fbbdev](https://github.com/fbbdev) in + [#3295](https://github.com/wailsapp/wails/pull/3295) +- Fix custom context menu closing immediately on linux by + [@abichinger](https://github.com/abichinger) in + [#3330](https://github.com/wailsapp/wails/pull/3330) +- Fix the output path and extension of model files produced by the binding + generator by [@fbbdev](https://github.com/fbbdev) in + [#3334](https://github.com/wailsapp/wails/pull/3334) +- Fix the import paths of model files in JS code produced by the binding + generator by [@fbbdev](https://github.com/fbbdev) in + [#3334](https://github.com/wailsapp/wails/pull/3334) +- Fix drag-n-drop on some linux distros by + [@abichinger](https://github.com/abichinger) in + [#3346](https://github.com/wailsapp/wails/pull/3346) +- Fix missing task for macOS when using `wails3 task dev` by + [@hfoxy](https://github.com/hfoxy) in + [#3417](https://github.com/wailsapp/wails/pull/3417) +- Fix registering events causing a nil map assignment by + [@hfoxy](https://github.com/hfoxy) in + [#3426](https://github.com/wailsapp/wails/pull/3426) +- Fix unmarshaling of bound method parameters by + [@fbbdev](https://github.com/fbbdev) in + [#3431](https://github.com/wailsapp/wails/pull/3431) +- Fix handling of multiple return values from bound methods by + [@fbbdev](https://github.com/fbbdev) in + [#3431](https://github.com/wailsapp/wails/pull/3431) +- Fix doctor detection of npm that is not installed with system package manager + by [@pekim](https://github.com/pekim) in + [#3458](https://github.com/wailsapp/wails/pull/3458) +- Fix missing MicrosoftEdgeWebview2Setup.exe. Thanks to + [@robin-samuel](https://github.com/robin-samuel). +- Fix random crash on linux due to window ID handling by @leaanthony. Based on + PR [#3466](https://github.com/wailsapp/wails/pull/3622) by + [@5aaee9](https://github.com/5aaee9). +- Fix systemTray.setIcon crashing on Linux by + [@windom](https://github.com/windom/) in + [#3636](https://github.com/wailsapp/wails/pull/3636). +- Fix Ensure Window Frame is Applied on First Call in `setFrameless` Function on + Windows by [@bruxaodev](https://github.com/bruxaodev/) in + [#3691](https://github.com/wailsapp/wails/pull/3691). + +### Changed + +- Renamed `AbsolutePosition()` to `Position()` by + [mmghv](https://github.com/mmghv) in + [#3611](https://github.com/wailsapp/wails/pull/3611) +- Update linux webkit dependency to webkit2gtk-4.1 over webkitgtk2-4.0 to + support Ubuntu 24.04 LTS by [atterpac](https://github.com/atterpac) in + [#3461](https://github.com/wailsapp/wails/pull/3461) +- The bundled JS runtime script is now an ESM module: script tags importing it + must have the `type="module"` attribute. By + [@fbbdev](https://github.com/fbbdev) in + [#3295](https://github.com/wailsapp/wails/pull/3295) +- The `@wailsio/runtime` package does not publish its API on the `window.wails` + object, and does not start the WML system. This has been done to improve + encapsulation. The WML system can be started manually if desired by calling + the new `WML.Enable` method. The bundled JS runtime script still performs both + operations automatically. By [@fbbdev](https://github.com/fbbdev) in + [#3295](https://github.com/wailsapp/wails/pull/3295) +- The Window API module `@wailsio/runtime/src/window` now exposes the containing + window object as a default export. It is not possible anymore to import + individual methods through ESM named or namespace import syntax. +- The JS window API has been updated to match the current Go `WebviewWindow` + API. Some methods have changed name or prototype, specifically: `Screen` + becomes `GetScreen`; `GetZoomLevel`/`SetZoomLevel` become `GetZoom`/`SetZoom`; + `GetZoom`, `Width` and `Height` now return values directly instead of wrapping + them within objects. By [@fbbdev](https://github.com/fbbdev) in + [#3295](https://github.com/wailsapp/wails/pull/3295) +- The binding generator now uses calls by ID by default. The `-id` CLI option + has been removed. Use the `-names` CLI option to switch back to calls by name. + By [@fbbdev](https://github.com/fbbdev) in + [#3468](https://github.com/wailsapp/wails/pull/3468) +- New binding code layout: output files were previously organised in folders + named after their containing package; now full Go import paths are used, + including the module path. By [@fbbdev](https://github.com/fbbdev) in + [#3468](https://github.com/wailsapp/wails/pull/3468) +- The struct field `application.Options.Bind` has been renamed to + `application.Options.Services`. By [@fbbdev](https://github.com/fbbdev) in + [#3468](https://github.com/wailsapp/wails/pull/3468) +- New syntax for binding services: service instances must now be wrapped in a + call to `application.NewService`. By [@fbbdev](https://github.com/fbbdev) in + [#3468](https://github.com/wailsapp/wails/pull/3468) +- Disable spinner on Non-Terminal or CI Environment by + [@DeltaLaboratory](https://github.com/DeltaLaboratory) in + [#3574](https://github.com/wailsapp/wails/pull/3574) diff --git a/docs/src/content/docs/guides/events-reference.mdx b/docs/src/content/docs/guides/events-reference.mdx index 7f4028120..569534495 100644 --- a/docs/src/content/docs/guides/events-reference.mdx +++ b/docs/src/content/docs/guides/events-reference.mdx @@ -77,21 +77,38 @@ func (s *Service) UpdateData() { // Notify the frontend app := application.Get() - app.Event.EmitEvent(&application.CustomEvent{ - Name: "my-app:data-updated", - Data: map[string]interface{}{ + app.Event.Emit("my-app:data-updated", + map[string]interface{}{ "timestamp": time.Now(), "count": 42, }, - }) + ) } ``` +### Emitting Events (Frontend) + +While not as commonly used, you can also emit events from your frontend that your Go code can listen to: + +```javascript +import { Events } from '@wailsio/runtime'; + +// Event without data +Events.Emit('myapp:close-window') + +// Event with data +Events.Emit('myapp:disconnect-requested', 'id-123') +``` + +If you are using typescript in your frontend and [application.RegisterEvent](/learn/events#custom-event-registration) in your Go code, you will get event name autocomplete / checking and data type checking. + ### Removing Event Listeners Always clean up your event listeners when they're no longer needed: ```javascript +import { Events } from '@wailsio/runtime'; + // Store the handler reference const focusHandler = () => { console.log('Window focused'); @@ -114,6 +131,8 @@ Events.Off('common:WindowFocus'); Many applications need to pause certain activities when the window loses focus: ```javascript +import { Events } from '@wailsio/runtime'; + let animationRunning = true; Events.On('common:WindowLostFocus', () => { @@ -132,6 +151,8 @@ Events.On('common:WindowFocus', () => { Keep your app in sync with the system theme: ```javascript +import { Events } from '@wailsio/runtime'; + Events.On('common:ThemeChanged', (event) => { const isDarkMode = event.data.isDark; @@ -150,6 +171,8 @@ Events.On('common:ThemeChanged', (event) => { Make your app accept dragged files: ```javascript +import { Events } from '@wailsio/runtime'; + Events.On('common:WindowFilesDropped', (event) => { const files = event.data.files; @@ -166,6 +189,8 @@ Events.On('common:WindowFilesDropped', (event) => { Respond to window state changes: ```javascript +import { Events } from '@wailsio/runtime'; + Events.On('common:WindowClosing', () => { // Save user data before closing saveApplicationState(); @@ -190,6 +215,8 @@ Events.On('common:WindowRestore', () => { Handle platform-specific events when needed: ```javascript +import { Events } from '@wailsio/runtime'; + // Windows-specific power management Events.On('windows:APMSuspend', () => { console.log('System is going to sleep'); @@ -210,7 +237,7 @@ Events.On('mac:ApplicationWillTerminate', () => { ## Creating Custom Events -You can create your own events for application-specific needs: +You can create your own events for application-specific needs. See [application.RegisterEvent](/learn/events#custom-event-registration) to learn how to register these events and enable type checking of event data. ### Backend (Go) @@ -222,14 +249,13 @@ func (s *Service) ProcessUserData(userData UserData) error { app := application.Get() // Notify all listeners - app.Event.EmitEvent(&application.CustomEvent{ - Name: "user:data-processed", - Data: map[string]interface{}{ + app.Event.Emit("user:data-processed", + map[string]interface{}{ "userId": userData.ID, "status": "completed", "timestamp": time.Now(), }, - }) + ) return nil } @@ -250,6 +276,8 @@ func (s *Service) StartMonitoring() { ### Frontend (JavaScript) ```javascript +import { Events } from '@wailsio/runtime'; + // Listen for your custom events Events.On('user:data-processed', (event) => { const { userId, status, timestamp } = event.data; @@ -341,6 +369,8 @@ Events.Emit('update'); Always remove event listeners when components unmount: ```javascript +import { Events } from '@wailsio/runtime'; + // React example useEffect(() => { const handler = (event) => { @@ -361,7 +391,7 @@ useEffect(() => { Check platform availability when using platform-specific events: ```javascript -import { Platform } from '@wailsio/runtime'; +import { Platform, Events } from '@wailsio/runtime'; if (Platform.isWindows) { Events.On('windows:APMSuspend', handleSuspend); @@ -382,6 +412,8 @@ While events are powerful, don't use them for everything: To debug event issues: ```javascript +import { Events } from '@wailsio/runtime'; + // Log all events (development only) if (isDevelopment) { const originalOn = Events.On; diff --git a/docs/src/content/docs/guides/gin-services.mdx b/docs/src/content/docs/guides/gin-services.mdx index 89c4b68f5..123f876eb 100644 --- a/docs/src/content/docs/guides/gin-services.mdx +++ b/docs/src/content/docs/guides/gin-services.mdx @@ -127,13 +127,12 @@ func (s *GinService) ServiceStartup(ctx context.Context, options application.Ser s.app.Logger.Info("Received event from frontend", "data", event.Data) // Emit an event back to the frontend - s.app.Event.EmitEvent(&application.CustomEvent{ - Name: "gin-api-response", - Data: map[string]interface{}{ + s.app.Event.Emit("gin-api-response", + map[string]interface{}{ "message": "Response from Gin API Service", "time": time.Now().Format(time.RFC3339), }, - }) + ) }) return nil @@ -316,13 +315,12 @@ s.app.Event.On("gin-api-event", func(event *application.CustomEvent) { s.app.Logger.Info("Received event from frontend", "data", event.Data) // Emit an event back to the frontend - s.app.Event.EmitEvent(&application.CustomEvent{ - Name: "gin-api-response", - Data: map[string]interface{}{ + s.app.Event.Emit("gin-api-response", + map[string]interface{}{ "message": "Response from Gin API Service", "time": time.Now().Format(time.RFC3339), }, - }) + ) }) ``` @@ -349,10 +347,7 @@ Then use it in your code: import * as wails from '@wailsio/runtime'; // Event emission -wails.Events.Emit({ - name: 'gin-api-event', - data: eventData, -}); +wails.Events.Emit('gin-api-event', eventData); ``` Here's an example of how to set up frontend integration: @@ -528,7 +523,7 @@ Here's an example of how to set up frontend integration: message: "Hello from the frontend!", timestamp: new Date().toISOString() }; - wails.Events.Emit({name: 'gin-api-event', data: eventData}); + wails.Events.Emit('gin-api-event', eventData); }); // Set up event listener for responses from the backend diff --git a/docs/src/content/docs/learn/events.mdx b/docs/src/content/docs/learn/events.mdx index fbdaabef9..394d1e03e 100644 --- a/docs/src/content/docs/learn/events.mdx +++ b/docs/src/content/docs/learn/events.mdx @@ -313,7 +313,7 @@ win.OnWindowEvent(events.Common.WindowDropZoneFilesDropped, func(event *applicat "dropY": details.Y, "attributes": details.Attributes, } - application.Get().EmitEvent("frontend:FileDropInfo", payload) // Emits globally + application.Get().Event.Emit("frontend:FileDropInfo", payload) // Emits globally // or win.EmitEvent("frontend:FileDropInfoForWindow", payload) // Emits to this specific window } else { log.Println("Drop occurred, but DropZoneDetails were nil.") @@ -565,6 +565,9 @@ You can emit custom events from anywhere in your application: // NEW: Using the Event Manager (recommended) app.Event.Emit("myevent", "hello") +// Emit an event without data +app.Event.Emit("datalessevent") + // Emit from a specific window window.EmitEvent("windowevent", "window specific data") ``` @@ -574,8 +577,7 @@ window.EmitEvent("windowevent", "window specific data") // Traditional API (no longer works) app.EmitEvent("myevent", "hello") -// Emit from a specific window -window.EmitEvent("windowevent", "window specific data") + ``` @@ -633,6 +635,90 @@ app.OnMultipleEvent("myevent", func(e *application.CustomEvent) { +You can also register a hook that will run synchronously when the event is emitted. +Hooks are useful [to cancel custom events and stop their propagation early](#event-cancellation): + +```go +app.Event.RegisterHook("myevent", func(e *application.CustomEvent) { + // Do something. +}) +``` + +### Custom Event Registration + +You can call the `application.RegisterEvent` function at init time to register custom event names: + +```go +type MyEventData struct { + Num int + Text string +} + +func init() { + application.RegisterEvent[MyEventData]("myevent") +} +``` + +:::caution +Because this function is meant to be called at init time, it will panic when the arguments are not valid +or the same event name is registered twice with two distinct data types. +::: + +:::note +It is safe to register the same event multiple times as long as the data type is always the same. +This might be useful to ensure a certain event is registered as soon as any one of many packages is loaded. +::: + +Once the event is registered, data arguments passed to the `Event.Emit` method will be checked against the specified type. +In case of a mismatch, an error will be emitted and either logged or passed on to the registered error handled, if any. +The offending event will not be propagated. Thanks to this mechanism, it is safe to assume that the data field +of registered custom events will always be assignable to the declared type. + +:::tip[Strict mode] +If you use the `strictevents` build tag, using unregistered events will trigger a warning message in development mode. +The runtime emits at most one warning per event name, to avoid spamming the log. +::: + +### Binding generator support + +The binding generator outputs TypeScript definitions and internal glue code +to provide transparent support for registered events on the frontend. +The specified data type will be rendered to TypeScript +and the data field will be typed by the corresponding model: + +```js +import { Events } from "@wailsio/runtime"; + +Events.On("myevent", (ev) => { + ev.data; // Has type MyEventData + ev.data.Text; // Has type string +}) +``` + +:::caution +Static typing of event data on the frontend will only be available when the event name +is specified by a constant expression, as shown above. +::: + +When using the `Events.On*/Events.Off*` family of runtime methods or the `WailsEvent` constructor, +IDEs with TypeScript support will offer autocompletion for registered event names. + +You can look at built-in application templates +for an example of how to configure your project for typed events. + +### Events without data + +The `application.Void` interface can be used to register events without associated data: + +```go +func init() { + application.RegisterEvent[application.Void]("dataless") +} +``` + +On the Go side, the runtime will check that the data field for the `"dataless"` event is always `nil`. +On the frontend, the binding generator will translate `application.Void` as the TypeScript `void` type. + ## Event Cancellation Events can be cancelled to prevent their default behaviour or stop propagation to other listeners. This is particularly useful for hooks that need to control window closing, menu actions, or other system events. @@ -646,8 +732,17 @@ window.RegisterHook(events.Common.WindowClosing, func(e *application.WindowEvent // Prevent the window from closing e.Cancel() }) + +// For custom events +app.RegisterHook("myevent", func(e *application.CustomEvent) { + e.Cancel() +}) ``` +:::tip[Pro Tip] +Remember that event cancellation in hooks affects all subsequent hooks and listeners, whilst cancellation in standard listeners only affects listeners that haven't yet been called. +::: + ### Checking Event Cancellation You can check if an event has been cancelled using the `IsCancelled()` method: @@ -671,6 +766,13 @@ app.Event.On("myevent", func(e *application.CustomEvent) { }) ``` -:::tip[Pro Tip] -Remember that event cancellation in hooks affects all subsequent hooks and listeners, whilst cancellation in standard listeners only affects listeners that haven't yet been called. -::: \ No newline at end of file +When emitting a custom event, you can also check the value returned by the `Event.Emit` method (for the app and windows): + +```go +if app.Event.Emit("myevent") { + app.Logger.Info("Event was cancelled") + return +} +``` + +The returned value will take into account all hooks, but may or may not take into account cancellations that happen asynchronously in listeners. diff --git a/v3/UNRELEASED_CHANGELOG.md b/v3/UNRELEASED_CHANGELOG.md index 8e4648038..5da8e9366 100644 --- a/v3/UNRELEASED_CHANGELOG.md +++ b/v3/UNRELEASED_CHANGELOG.md @@ -17,9 +17,11 @@ After processing, the content will be moved to the main changelog and this file ## Added +- Typed Events by @fbbdev and @ianvs in [#4633](https://github.com/wailsapp/wails/pull/4633) ## Changed +- When emitting a custom event with zero or one data argument, the data value will be assigned directly to the Data field without wrapping it in a slice by [@fbbdev](https://github.com/fbbdev) in [#4633](https://github.com/wailsapp/wails/pull/4633) ## Fixed diff --git a/v3/examples/badge-custom/frontend/src/main.ts b/v3/examples/badge-custom/frontend/src/main.ts index 862185f3f..cbb4cd842 100644 --- a/v3/examples/badge-custom/frontend/src/main.ts +++ b/v3/examples/badge-custom/frontend/src/main.ts @@ -43,14 +43,11 @@ removeButton.addEventListener('click', () => { setButtonUsingGo.addEventListener('click', () => { let label = (labelElement as HTMLInputElement).value - void Events.Emit({ - name: "set:badge", - data: label, - }) + void Events.Emit("set:badge", label); }) removeButtonUsingGo.addEventListener('click', () => { - void Events.Emit({name:"remove:badge", data: null}) + void Events.Emit("remove:badge"); }) Events.On('time', (time: {data: any}) => { diff --git a/v3/examples/badge/frontend/src/main.ts b/v3/examples/badge/frontend/src/main.ts index 7f4ba9bfb..222564848 100644 --- a/v3/examples/badge/frontend/src/main.ts +++ b/v3/examples/badge/frontend/src/main.ts @@ -19,14 +19,11 @@ removeButton.addEventListener('click', () => { setButtonUsingGo.addEventListener('click', () => { let label = (labelElement as HTMLInputElement).value - void Events.Emit({ - name: "set:badge", - data: label, - }) + void Events.Emit("set:badge", label) }) removeButtonUsingGo.addEventListener('click', () => { - void Events.Emit({name:"remove:badge", data: null}) + void Events.Emit("remove:badge") }) Events.On('time', (time: {data: any}) => { diff --git a/v3/examples/custom-protocol-example/frontend/package.json b/v3/examples/custom-protocol-example/frontend/package.json index 64d7435a8..09086988e 100644 --- a/v3/examples/custom-protocol-example/frontend/package.json +++ b/v3/examples/custom-protocol-example/frontend/package.json @@ -12,6 +12,6 @@ "vite": "^6.3.5" }, "dependencies": { - "@wailsio/runtime": "^3.0.0-alpha.66" + "@wailsio/runtime": "latest" } } diff --git a/v3/examples/dev/frontend/jsconfig.json b/v3/examples/dev/frontend/tsconfig.json similarity index 90% rename from v3/examples/dev/frontend/jsconfig.json rename to v3/examples/dev/frontend/tsconfig.json index e596c5823..b3e8a23aa 100644 --- a/v3/examples/dev/frontend/jsconfig.json +++ b/v3/examples/dev/frontend/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "allowJs": true, "moduleResolution": "Node", "target": "ESNext", "module": "ESNext", @@ -29,5 +30,5 @@ * Use global.d.ts instead of compilerOptions.types * to avoid limiting type declarations. */ - "include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte"] + "include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte", "bindings"] } diff --git a/v3/examples/gin-service/assets/index.html b/v3/examples/gin-service/assets/index.html index 34324b89f..66aea00eb 100644 --- a/v3/examples/gin-service/assets/index.html +++ b/v3/examples/gin-service/assets/index.html @@ -223,7 +223,7 @@ message: "Hello from the frontend!", timestamp: new Date().toISOString() }; - wails.Events.Emit({name: 'gin-api-event', data: eventData}); + wails.Events.Emit('gin-api-event', eventData); }); // Set up event listener for responses from the backend diff --git a/v3/internal/commands/bindings.go b/v3/internal/commands/bindings.go index bd3277ec9..9c4720593 100644 --- a/v3/internal/commands/bindings.go +++ b/v3/internal/commands/bindings.go @@ -62,12 +62,13 @@ func GenerateBindings(options *flags.GenerateBindingsOptions, patterns []string) // Stop spinner and print summary. term.StopSpinner(spinner) term.Infof( - "Processed: %s, %s, %s, %s, %s in %s.", + "Processed: %s, %s, %s, %s, %s, %s in %s.", pluralise(stats.NumPackages, "Package"), pluralise(stats.NumServices, "Service"), pluralise(stats.NumMethods, "Method"), pluralise(stats.NumEnums, "Enum"), pluralise(stats.NumModels, "Model"), + pluralise(stats.NumEvents, "Event"), stats.Elapsed().String(), ) diff --git a/v3/internal/commands/build_assets/Taskfile.tmpl.yml b/v3/internal/commands/build_assets/Taskfile.tmpl.yml index 34f0659e7..c72601659 100644 --- a/v3/internal/commands/build_assets/Taskfile.tmpl.yml +++ b/v3/internal/commands/build_assets/Taskfile.tmpl.yml @@ -14,7 +14,7 @@ tasks: - package.json - package-lock.json generates: - - node_modules/* + - node_modules preconditions: - sh: npm version msg: "Looks like npm isn't installed. Npm is part of the Node installer: https://nodejs.org/en/download/" diff --git a/v3/internal/commands/build_assets/config.yml b/v3/internal/commands/build_assets/config.yml index aaa3240fb..92c3d6d6e 100644 --- a/v3/internal/commands/build_assets/config.yml +++ b/v3/internal/commands/build_assets/config.yml @@ -30,16 +30,14 @@ dev_mode: - .gitkeep watched_extension: - "*.go" + - "*.js" # Watch for changes to JS/TS files included using the //wails:include directive. + - "*.ts" # The frontend directory will be excluded entirely by the setting above. git_ignore: true executes: - - cmd: wails3 task common:install:frontend:deps - type: once - - cmd: wails3 task common:dev:frontend - type: background - - cmd: go mod tidy - type: blocking - cmd: wails3 task build type: blocking + - cmd: wails3 task common:dev:frontend + type: background - cmd: wails3 task run type: primary diff --git a/v3/internal/commands/init.go b/v3/internal/commands/init.go index 8a346f888..5ca45a0db 100644 --- a/v3/internal/commands/init.go +++ b/v3/internal/commands/init.go @@ -1,14 +1,17 @@ package commands import ( + "errors" "fmt" - "github.com/go-git/go-git/v5/config" - "github.com/wailsapp/wails/v3/internal/term" + "net/url" "os" "path/filepath" "regexp" "strings" + "github.com/go-git/go-git/v5/config" + "github.com/wailsapp/wails/v3/internal/term" + "github.com/go-git/go-git/v5" "github.com/pterm/pterm" "github.com/wailsapp/wails/v3/internal/flags" @@ -17,36 +20,52 @@ import ( var DisableFooter bool -// GitURLToModuleName converts a git URL to a Go module name by removing common prefixes +// See https://github.com/git/git/blob/master/Documentation/urls.adoc +var ( + gitProtocolFormat = regexp.MustCompile(`^(?:ssh|git|https?|ftps?|file)://`) + gitScpLikeGuard = regexp.MustCompile(`^[^/:]+:`) + gitScpLikeFormat = regexp.MustCompile(`^(?:([^@/:]+)@)?([^@/:]+):([^\\].*)$`) +) + +// gitURLToModulePath converts a git URL to a Go module name by removing common prefixes // and suffixes. It handles HTTPS, SSH, Git protocol, and filesystem URLs. -func GitURLToModuleName(gitURL string) string { - moduleName := gitURL - if strings.HasSuffix(moduleName, ".git") { - moduleName = moduleName[:len(moduleName)-4] - } - // Handle various URL schemes - for _, prefix := range []string{ - "https://", - "http://", - "git://", - "ssh://", - "file://", - } { - if strings.HasPrefix(moduleName, prefix) { - moduleName = moduleName[len(prefix):] - break +func gitURLToModulePath(gitURL string) string { + var path string + + if gitProtocolFormat.MatchString(gitURL) { + // Standard URL + parsed, err := url.Parse(gitURL) + if err != nil { + term.Warningf("invalid Git repository URL: %s; module path will default to 'changeme'", err) + return "changeme" + } + + path = parsed.Host + parsed.Path + } else if gitScpLikeGuard.MatchString(gitURL) { + // SCP-like URL + match := gitScpLikeFormat.FindStringSubmatch(gitURL) + if match != nil { + sep := "" + if !strings.HasPrefix(match[3], "/") { + // Add slash between host and path if missing + sep = "/" + } + + path = match[2] + sep + match[3] } } - // Handle SSH URLs (git@github.com:username/project.git) - if strings.HasPrefix(moduleName, "git@") { - // Remove the 'git@' prefix - moduleName = moduleName[4:] - // Replace ':' with '/' for proper module path - moduleName = strings.Replace(moduleName, ":", "/", 1) + + if path == "" { + // Filesystem path + path = gitURL } + + if strings.HasSuffix(path, ".git") { + path = path[:len(path)-4] + } + // Remove leading forward slash for file system paths - moduleName = strings.TrimPrefix(moduleName, "/") - return moduleName + return strings.TrimPrefix(path, "/") } func initGitRepository(projectDir string, gitURL string) error { @@ -65,28 +84,6 @@ func initGitRepository(projectDir string, gitURL string) error { return fmt.Errorf("failed to create git remote: %w", err) } - // Update go.mod with the module name - moduleName := GitURLToModuleName(gitURL) - - goModPath := filepath.Join(projectDir, "go.mod") - content, err := os.ReadFile(goModPath) - if err != nil { - return fmt.Errorf("failed to read go.mod: %w", err) - } - - // Replace module name - lines := strings.Split(string(content), "\n") - if len(lines) == 0 { - return fmt.Errorf("go.mod is empty") - } - lines[0] = fmt.Sprintf("module %s", moduleName) - newContent := strings.Join(lines, "\n") - - err = os.WriteFile(goModPath, []byte(newContent), 0644) - if err != nil { - return fmt.Errorf("failed to write go.mod: %w", err) - } - // Stage all files worktree, err := repo.Worktree() if err != nil { @@ -102,7 +99,6 @@ func initGitRepository(projectDir string, gitURL string) error { } func Init(options *flags.Init) error { - if options.List { term.Header("Available templates") return printTemplates() @@ -120,11 +116,19 @@ func Init(options *flags.Init) error { } if options.ProjectName == "" { - return fmt.Errorf("please use the -n flag to specify a project name") + return errors.New("please use the -n flag to specify a project name") } options.ProjectName = sanitizeFileName(options.ProjectName) + if options.ModulePath == "" { + if options.Git == "" { + options.ModulePath = "changeme" + } else { + options.ModulePath = gitURLToModulePath(options.Git) + } + } + err := templates.Install(options) if err != nil { return err diff --git a/v3/internal/commands/init_test.go b/v3/internal/commands/init_test.go index 791a318f9..cb1b30d48 100644 --- a/v3/internal/commands/init_test.go +++ b/v3/internal/commands/init_test.go @@ -1,8 +1,10 @@ package commands -import "testing" +import ( + "testing" +) -func Test_GitURLToModuleName(t *testing.T) { +func TestGitURLToModulePath(t *testing.T) { tests := []struct { name string gitURL string @@ -106,8 +108,8 @@ func Test_GitURLToModuleName(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := GitURLToModuleName(tt.gitURL); got != tt.want { - t.Errorf("GitURLToModuleName() = %v, want %v", got, tt.want) + if got := gitURLToModulePath(tt.gitURL); got != tt.want { + t.Errorf("gitURLToModulePath() = %v, want %v", got, tt.want) } }) } diff --git a/v3/internal/flags/bindings.go b/v3/internal/flags/bindings.go index acef15006..a95566af6 100644 --- a/v3/internal/flags/bindings.go +++ b/v3/internal/flags/bindings.go @@ -16,6 +16,7 @@ type GenerateBindingsOptions struct { UseInterfaces bool `name:"i" description:"Generate Typescript interfaces instead of classes"` UseBundledRuntime bool `name:"b" description:"Use the bundled runtime instead of importing the npm package"` UseNames bool `name:"names" description:"Use names instead of IDs for the binding calls"` + NoEvents bool `name:"noevents" description:"Do not generate types for registered custom events"` NoIndex bool `name:"noindex" description:"Do not generate JS/TS index files"` DryRun bool `name:"dry" description:"Do not write output files"` Silent bool `name:"silent" description:"Silent mode"` diff --git a/v3/internal/flags/init.go b/v3/internal/flags/init.go index df6baa56c..ec108b91d 100644 --- a/v3/internal/flags/init.go +++ b/v3/internal/flags/init.go @@ -11,6 +11,7 @@ type Init struct { List bool `name:"l" description:"List templates"` SkipGoModTidy bool `name:"skipgomodtidy" description:"Skip running go mod tidy"` Git string `name:"git" description:"Git repository URL to initialize (e.g. github.com/username/project)"` + ModulePath string `name:"mod" description:"The Go module path for the project. Will be computed from the Git URL if unspecified."` ProductName string `description:"The name of the product" default:"My Product"` ProductDescription string `description:"The description of the product" default:"My Product Description"` ProductVersion string `description:"The version of the product" default:"0.1.0"` diff --git a/v3/internal/generator/analyse.go b/v3/internal/generator/analyse.go index 411e6ff4f..e3f664496 100644 --- a/v3/internal/generator/analyse.go +++ b/v3/internal/generator/analyse.go @@ -15,12 +15,10 @@ import ( // // Whenever one is found and the type of its unique argument // is a valid service type, the corresponding named type object -// is passed to yield. +// is fed into the returned iterator. // -// Results are deduplicated, i.e. yield is called at most once per object. -// -// If yield returns false, FindBoundTypes returns immediately. -func FindServices(pkgs []*packages.Package, systemPaths *config.SystemPaths, logger config.Logger) (iter.Seq[*types.TypeName], error) { +// Results are deduplicated, i.e. the iterator yields any given object at most once. +func FindServices(pkgs []*packages.Package, systemPaths *config.SystemPaths, logger config.Logger) (iter.Seq[*types.TypeName], types.Object, error) { type instanceInfo struct { args *types.TypeList pos token.Position @@ -47,6 +45,9 @@ func FindServices(pkgs []*packages.Package, systemPaths *config.SystemPaths, log // for deduplication. scheduled := make(map[target]bool) + // registerEvent holds the `application.RegisterEvent` function if found. + var registerEvent types.Object + // next lists type parameter objects that have yet to be analysed. var next []targetInfo @@ -102,29 +103,46 @@ func FindServices(pkgs []*packages.Package, systemPaths *config.SystemPaths, log } } - if len(next) > 0 { - // application.NewService has been found already. - continue - } + // Detect application.RegisterEvent + if registerEvent == nil && obj.Name() == "RegisterEvent" && obj.Pkg().Path() == systemPaths.ApplicationPackage { + fn, ok := obj.(*types.Func) + if !ok { + return nil, nil, ErrBadApplicationPackage + } - fn, ok := obj.(*types.Func) - if !ok { + signature := fn.Type().(*types.Signature) + if signature.Params().Len() != 1 || signature.Results().Len() != 0 || signature.TypeParams().Len() != 1 { + logger.Warningf("application.RegisterService params: %d, results: %d, typeparams: %d", signature.Params().Len(), signature.Results().Len(), signature.TypeParams().Len()) + return nil, nil, ErrBadApplicationPackage + } + + if !types.Identical(signature.Params().At(0).Type(), types.Universe.Lookup("string").Type()) { + logger.Warningf("application.RegisterService parameter type: %v", signature.Params().At(0).Type()) + return nil, nil, ErrBadApplicationPackage + } + + registerEvent = obj continue } // Detect application.NewService - if fn.Name() == "NewService" && fn.Pkg().Path() == systemPaths.ApplicationPackage { - // Check signature. + if len(next) == 0 && obj.Name() == "NewService" && obj.Pkg().Path() == systemPaths.ApplicationPackage { + fn, ok := obj.(*types.Func) + if !ok { + return nil, nil, ErrBadApplicationPackage + } + signature := fn.Type().(*types.Signature) - if signature.Params().Len() > 2 || signature.Results().Len() != 1 || tp.Len() != 1 || tp.At(0).Obj() == nil { - logger.Warningf("Param Len: %d, Results Len: %d, tp.Len: %d, tp.At(0).Obj(): %v", signature.Params().Len(), signature.Results().Len(), tp.Len(), tp.At(0).Obj()) - return nil, ErrBadApplicationPackage + if signature.Params().Len() != 1 || signature.Results().Len() != 1 || tp.Len() != 1 { + logger.Warningf("application.NewService params: %d, results: %d, typeparams: %d", signature.Params().Len(), signature.Results().Len(), tp.Len()) + return nil, nil, ErrBadApplicationPackage } // Schedule unique type param for analysis. tgt := target{obj, 0} scheduled[tgt] = true next = append(next, targetInfo{target: tgt}) + continue } } } @@ -185,7 +203,7 @@ func FindServices(pkgs []*packages.Package, systemPaths *config.SystemPaths, log logger.Warningf("%s: ignoring interface service type %s%s", instance.pos, named, indirectMsg) continue } else if named.TypeParams() != nil { - logger.Warningf("%s: ignoring generic service type %s", instance.pos, named, indirectMsg) + logger.Warningf("%s: ignoring generic service type %s%s", instance.pos, named, indirectMsg) continue } @@ -198,5 +216,5 @@ func FindServices(pkgs []*packages.Package, systemPaths *config.SystemPaths, log } } } - }, nil + }, registerEvent, nil } diff --git a/v3/internal/generator/analyse_test.go b/v3/internal/generator/analyse_test.go index 576e56f6f..06c593901 100644 --- a/v3/internal/generator/analyse_test.go +++ b/v3/internal/generator/analyse_test.go @@ -17,8 +17,9 @@ import ( func TestAnalyser(t *testing.T) { type testParams struct { - name string - want []string + name string + want []string + events bool } // Gather tests from cases directory. @@ -57,6 +58,19 @@ func TestAnalyser(t *testing.T) { } slices.Sort(test.want) + events, err := os.Open(filepath.Join("testcases", entry.Name(), "events.json")) + if err != nil { + if !errors.Is(err, os.ErrNotExist) { + t.Fatal(err) + } + } else { + err = json.NewDecoder(events).Decode(&test.events) + events.Close() + if err != nil { + t.Fatal(err) + } + } + tests = append(tests, test) } @@ -68,6 +82,7 @@ func TestAnalyser(t *testing.T) { for _, test := range tests { all.want = append(all.want, test.want...) + all.events = all.events || test.events } slices.Sort(all.want) @@ -97,7 +112,7 @@ func TestAnalyser(t *testing.T) { got := make([]string, 0) - services, err := FindServices(pkgs, systemPaths, config.DefaultPtermLogger(nil)) + services, registerService, err := FindServices(pkgs, systemPaths, config.DefaultPtermLogger(nil)) if err != nil { t.Error(err) } @@ -111,6 +126,10 @@ func TestAnalyser(t *testing.T) { if diff := cmp.Diff(test.want, got); diff != "" { t.Errorf("Found services mismatch (-want +got):\n%s", diff) } + + if test.events != (registerService != nil) { + t.Errorf("Found events mismatch: wanted=%t, got=%t", test.events, registerService != nil) + } }) } } diff --git a/v3/internal/generator/collect/collector.go b/v3/internal/generator/collect/collector.go index e4acd53e8..da0a9d546 100644 --- a/v3/internal/generator/collect/collector.go +++ b/v3/internal/generator/collect/collector.go @@ -40,6 +40,9 @@ type Collector struct { // and declaration groups. Elements are [Info] instances. cache sync.Map + // events holds collected information about registered custom events. + events *EventMap + systemPaths *config.SystemPaths options *flags.GenerateBindingsOptions scheduler Scheduler @@ -47,7 +50,7 @@ type Collector struct { } // NewCollector initialises a new Collector instance for the given package set. -func NewCollector(pkgs []*packages.Package, systemPaths *config.SystemPaths, options *flags.GenerateBindingsOptions, scheduler Scheduler, logger config.Logger) *Collector { +func NewCollector(pkgs []*packages.Package, registerEvent types.Object, systemPaths *config.SystemPaths, options *flags.GenerateBindingsOptions, scheduler Scheduler, logger config.Logger) *Collector { collector := &Collector{ pkgs: make(map[*types.Package]*PackageInfo, len(pkgs)), @@ -62,6 +65,11 @@ func NewCollector(pkgs []*packages.Package, systemPaths *config.SystemPaths, opt collector.pkgs[pkg.Types] = newPackageInfo(pkg, collector) } + // Initialise event map. + if !options.NoEvents { + collector.events = newEventMap(collector, registerEvent) + } + return collector } diff --git a/v3/internal/generator/collect/declaration.go b/v3/internal/generator/collect/declaration.go index e592b5b1a..7f2ccc989 100644 --- a/v3/internal/generator/collect/declaration.go +++ b/v3/internal/generator/collect/declaration.go @@ -39,25 +39,11 @@ func (collector *Collector) findDeclaration(obj types.Object) (path []ast.Node) return nil } - // Perform a binary search to find the file enclosing the node. - // We can't use findEnclosingNode here because it is less accurate and less efficient with files. - fileIndex, exact := slices.BinarySearchFunc(pkg.Files, obj.Pos(), func(f *ast.File, p token.Pos) int { - return cmp.Compare(f.FileStart, p) - }) - - // If exact is true, pkg.Files[fileIndex] is the file we are looking for; - // otherwise, it is the first file whose start position is _after_ obj.Pos(). - if !exact { - fileIndex-- - } - - // When exact is false, the position might lie within an empty segment in between two files. - if fileIndex < 0 || pkg.Files[fileIndex].FileEnd <= obj.Pos() { + file := findEnclosingFile(pkg.Files, obj.Pos()) + if file == nil { return nil } - file := pkg.Files[fileIndex] - // Find enclosing declaration. decl := findEnclosingNode(file.Decls, obj.Pos()) if decl == nil { @@ -212,6 +198,28 @@ func (collector *Collector) findDeclaration(obj types.Object) (path []ast.Node) } } +// findEnclosingFile finds the unique file in files, if any, that encloses the given position. +func findEnclosingFile(files []*ast.File, pos token.Pos) *ast.File { + // Perform a binary search to find the file enclosing the node. + // We can't use findEnclosingNode here because it is less accurate and less efficient with files. + fileIndex, exact := slices.BinarySearchFunc(files, pos, func(f *ast.File, p token.Pos) int { + return cmp.Compare(f.FileStart, p) + }) + + // If exact is true, pkg.Files[fileIndex] is the file we are looking for; + // otherwise, it is the first file whose start position is _after_ obj.Pos(). + if !exact { + fileIndex-- + } + + // When exact is false, the position might lie within an empty segment in between two files. + if fileIndex < 0 || files[fileIndex].FileEnd <= pos { + return nil + } + + return files[fileIndex] +} + // findEnclosingNode finds the unique node in nodes, if any, // that encloses the given position. // diff --git a/v3/internal/generator/collect/events.go b/v3/internal/generator/collect/events.go new file mode 100644 index 000000000..21e7cd7a9 --- /dev/null +++ b/v3/internal/generator/collect/events.go @@ -0,0 +1,283 @@ +package collect + +import ( + _ "embed" + "go/ast" + "go/constant" + "go/token" + "go/types" + "slices" + "strings" + "sync" + + "golang.org/x/tools/go/ast/astutil" +) + +type ( + // EventMap holds information about a set of custom events + // and their associated data types. + // + // Read accesses to any public field are only safe + // if a call to [EventMap.Collect] has completed before the access, + // for example by calling it in the accessing goroutine + // or before spawning the accessing goroutine. + EventMap struct { + Imports *ImportMap + Defs []*EventInfo + + registerEvent types.Object + collector *Collector + once sync.Once + } + + // EventInfo holds information about a single event definition. + EventInfo struct { + // Name is the name of the event. + Name string + + // Data is the data type the event has been registered with. + // It may be nil in case of conflicting definitions. + Data types.Type + + // Pos records the position + // of the first discovered definition for this event. + Pos token.Position + } +) + +func newEventMap(collector *Collector, registerEvent types.Object) *EventMap { + return &EventMap{ + registerEvent: registerEvent, + collector: collector, + } +} + +// EventMap returns the unique event map associated with the given collector, +// or nil if event collection is disabled. +func (collector *Collector) EventMap() *EventMap { + return collector.events +} + +// Stats returns statistics for this event map. +// It is an error to call stats before a call to [EventMap.Collect] has completed. +func (em *EventMap) Stats() *Stats { + return &Stats{ + NumEvents: len(em.Defs), + } +} + +// Collect gathers information for the event map described by its receiver. +// It can be called concurrently by multiple goroutines; +// the computation will be performed just once. +// +// Collect returns the receiver for chaining. +// It is safe to call Collect with nil receiver. +// +// After Collect returns, the calling goroutine and all goroutines +// it might spawn afterwards are free to access +// the receiver's fields indefinitely. +func (em *EventMap) Collect() *EventMap { + if em == nil { + return nil + } + + em.once.Do(func() { + // XXX: initialise the import map with a fake package. + // At present this works fine; let's hope it doesn't come back and haunt us later. + em.Imports = NewImportMap(&PackageInfo{ + Path: em.collector.systemPaths.InternalPackage, + collector: em.collector, + }) + + if em.registerEvent == nil { + return + } + + var ( + wg sync.WaitGroup + defs sync.Map + ) + + for pkg := range em.collector.Iterate { + if !pkg.IsOrImportsApp { + // Packages that are not, and do not import, the Wails application package + // cannot define any events. + continue + } + + wg.Add(1) + + // Process packages in parallel. + em.collector.scheduler.Schedule(func() { + em.collectEventsInPackage(pkg, &defs) + wg.Done() + }) + } + + wg.Wait() + + // Collect valid events. + em.Defs = slices.Collect(func(yield func(*EventInfo) bool) { + for _, v := range defs.Range { + event := v.(*EventInfo) + if event.Data != nil && !IsParametric(event.Data) { + if !yield(event) { + break + } + } + } + }) + + // Sort by name, ascending. + slices.SortFunc(em.Defs, func(a, b *EventInfo) int { + return strings.Compare(a.Name, b.Name) + }) + + // Record required types. + // This must be done at the end because: + // - [ImportMap.AddType] does not support concurrent calls, and + // - we only know the set of valid events after inspecting all definitions. + for _, def := range em.Defs { + em.Imports.AddType(def.Data) + } + }) + + return em +} + +func (em *EventMap) collectEventsInPackage(pkg *PackageInfo, defs *sync.Map) { + for ident, inst := range pkg.TypesInfo.Instances { + if pkg.TypesInfo.Uses[ident] != em.registerEvent { + continue + } + + file := findEnclosingFile(pkg.Collect().Files, ident.Pos()) + if file == nil { + em.collector.logger.Warningf( + "package %s: found event declaration with no associated source file", + pkg.Path, + ) + continue + } + + path, _ := astutil.PathEnclosingInterval(file, ident.Pos(), ident.End()) + if path[0] != ident { + em.collector.logger.Warningf( + "%v: event declaration not found in source file", + pkg.Fset.Position(ident.Pos()), + ) + continue + } + + // Walk up the path: *ast.Ident -> *ast.SelectorExpr? -> (*ast.IndexExpr | *ast.IndexListExpr)? -> *ast.CallExpr? + path = path[1:] + + if _, ok := path[0].(*ast.SelectorExpr); ok { + path = path[1:] + } + + if _, ok := path[0].(*ast.IndexExpr); ok { + path = path[1:] + } else if _, ok := path[0].(*ast.IndexListExpr); ok { + path = path[1:] + } + + call, ok := path[0].(*ast.CallExpr) + if !ok { + em.collector.logger.Warningf( + "%v: `application.RegisterEvent` is instantiated here but not called", + pkg.Fset.Position(path[0].Pos()), + ) + em.collector.logger.Warningf("events registered through indirect calls are not discoverable by the binding generator: it is recommended to invoke `application.RegisterEvent` directly") + continue + } + + if len(call.Args) == 0 { + // Invalid calls result in compile-time failures and can be ignored safely. + continue + } + + eventName, ok := pkg.TypesInfo.Types[call.Args[0]] + if !ok || !types.AssignableTo(eventName.Type, types.Universe.Lookup("string").Type()) { + // Mistyped calls result in compile-time failures and can be ignored safely. + continue + } + + if eventName.Value == nil { + em.collector.logger.Warningf( + "%v: `application.RegisterEvent` called here with non-constant event name", + pkg.Fset.Position(call.Pos()), + ) + em.collector.logger.Warningf("dynamically registered event names are not discoverable by the binding generator: it is recommended to invoke `application.RegisterEvent` with constant arguments only") + continue + } + + event := &EventInfo{ + Data: inst.TypeArgs.At(0), + Pos: pkg.Fset.Position(call.Pos()), + } + if eventName.Value.Kind() == constant.String { + event.Name = constant.StringVal(eventName.Value) + } else { + event.Name = eventName.Value.ExactString() + } + + if IsKnownEvent(event.Name) { + em.collector.logger.Warningf( + "%v: event '%s' is a known system event and cannot be overridden; this call to `application.RegisterEvent` will panic", + event.Pos, + event.Name, + ) + continue + } + + if v, ok := defs.LoadOrStore(event.Name, event); ok { + prev := v.(*EventInfo) + if prev.Data != nil && !types.Identical(event.Data, prev.Data) { + next := &EventInfo{ + Name: prev.Name, + Pos: prev.Pos, + } + + if defs.CompareAndSwap(prev.Name, prev, next) { + em.collector.logger.Warningf("event '%s' has multiple conflicting definitions and will be ignored", event.Name) + em.collector.logger.Warningf( + "%v: event '%s' has one of multiple definitions here with data type %s", + prev.Pos, + prev.Name, + prev.Data, + ) + } + + prev = next + } + if prev.Data == nil { + em.collector.logger.Warningf( + "%v: event '%s' has one of multiple definitions here with data type %s", + event.Pos, + event.Name, + event.Data, + ) + } + continue + } + + // Emit unsupported type warnings only for first definition + if IsParametric(event.Data) { + em.collector.logger.Warningf( + "%v: data type %s for event '%s' contains unresolved type parameters and will be ignored`", + event.Pos, + event.Data, + event.Name, + ) + em.collector.logger.Warningf("generic wrappers for calls to `application.RegisterEvent` are not analysable by the binding generator: it is recommended to call `application.RegisterEvent` with concrete types only") + } else if types.IsInterface(event.Data) && !types.Identical(event.Data.Underlying(), typeAny) && !em.collector.IsVoidAlias(event.Data) { + em.collector.logger.Warningf( + "%v: data type %s for event '%s' is a non-empty interface: emitting events from the frontend with data other than `null` is not supported by encoding/json and will likely result in runtime errors", + event.Pos, + event.Data, + event.Name, + ) + } + } +} diff --git a/v3/internal/generator/collect/imports.go b/v3/internal/generator/collect/imports.go index b62e53963..349ef68af 100644 --- a/v3/internal/generator/collect/imports.go +++ b/v3/internal/generator/collect/imports.go @@ -147,6 +147,11 @@ func (imports *ImportMap) addTypeImpl(typ types.Type, visited *typeutil.Map) { return } + // Special case: application.Void will render as TS void hence no dependencies and no model + if collector.IsVoidAlias(obj) { + return + } + if obj.Pkg().Path() == imports.Self { imports.ImportModels = true } @@ -260,7 +265,7 @@ func (imports *ImportMap) addTypeImpl(typ types.Type, visited *typeutil.Map) { return default: - collector.logger.Warningf("package %s: unknown type %s: please report this to Wails maintainers", imports.Self, typ) + collector.logger.Warningf("package %s: unknown or unexpected type %s: please report this to Wails maintainers", imports.Self, typ) return } } diff --git a/v3/internal/generator/collect/known_events.go b/v3/internal/generator/collect/known_events.go new file mode 100644 index 000000000..d65476a51 --- /dev/null +++ b/v3/internal/generator/collect/known_events.go @@ -0,0 +1,220 @@ +package collect + +func IsKnownEvent(name string) bool { + _, ok := knownEvents[name] + return ok +} + +var knownEvents = map[string]struct{}{ + "common:ApplicationOpenedWithFile": {}, + "common:ApplicationStarted": {}, + "common:ApplicationLaunchedWithUrl": {}, + "common:ThemeChanged": {}, + "common:WindowClosing": {}, + "common:WindowDidMove": {}, + "common:WindowDidResize": {}, + "common:WindowDPIChanged": {}, + "common:WindowFilesDropped": {}, + "common:WindowFocus": {}, + "common:WindowFullscreen": {}, + "common:WindowHide": {}, + "common:WindowLostFocus": {}, + "common:WindowMaximise": {}, + "common:WindowMinimise": {}, + "common:WindowToggleFrameless": {}, + "common:WindowRestore": {}, + "common:WindowRuntimeReady": {}, + "common:WindowShow": {}, + "common:WindowUnFullscreen": {}, + "common:WindowUnMaximise": {}, + "common:WindowUnMinimise": {}, + "common:WindowZoom": {}, + "common:WindowZoomIn": {}, + "common:WindowZoomOut": {}, + "common:WindowZoomReset": {}, + "common:WindowDropZoneFilesDropped": {}, + "linux:ApplicationStartup": {}, + "linux:SystemThemeChanged": {}, + "linux:WindowDeleteEvent": {}, + "linux:WindowDidMove": {}, + "linux:WindowDidResize": {}, + "linux:WindowFocusIn": {}, + "linux:WindowFocusOut": {}, + "linux:WindowLoadChanged": {}, + "mac:ApplicationDidBecomeActive": {}, + "mac:ApplicationDidChangeBackingProperties": {}, + "mac:ApplicationDidChangeEffectiveAppearance": {}, + "mac:ApplicationDidChangeIcon": {}, + "mac:ApplicationDidChangeOcclusionState": {}, + "mac:ApplicationDidChangeScreenParameters": {}, + "mac:ApplicationDidChangeStatusBarFrame": {}, + "mac:ApplicationDidChangeStatusBarOrientation": {}, + "mac:ApplicationDidChangeTheme!": {}, + "mac:ApplicationDidFinishLaunching": {}, + "mac:ApplicationDidHide": {}, + "mac:ApplicationDidResignActive": {}, + "mac:ApplicationDidUnhide": {}, + "mac:ApplicationDidUpdate": {}, + "mac:ApplicationShouldHandleReopen!": {}, + "mac:ApplicationWillBecomeActive": {}, + "mac:ApplicationWillFinishLaunching": {}, + "mac:ApplicationWillHide": {}, + "mac:ApplicationWillResignActive": {}, + "mac:ApplicationWillTerminate": {}, + "mac:ApplicationWillUnhide": {}, + "mac:ApplicationWillUpdate": {}, + "mac:MenuDidAddItem": {}, + "mac:MenuDidBeginTracking": {}, + "mac:MenuDidClose": {}, + "mac:MenuDidDisplayItem": {}, + "mac:MenuDidEndTracking": {}, + "mac:MenuDidHighlightItem": {}, + "mac:MenuDidOpen": {}, + "mac:MenuDidPopUp": {}, + "mac:MenuDidRemoveItem": {}, + "mac:MenuDidSendAction": {}, + "mac:MenuDidSendActionToItem": {}, + "mac:MenuDidUpdate": {}, + "mac:MenuWillAddItem": {}, + "mac:MenuWillBeginTracking": {}, + "mac:MenuWillDisplayItem": {}, + "mac:MenuWillEndTracking": {}, + "mac:MenuWillHighlightItem": {}, + "mac:MenuWillOpen": {}, + "mac:MenuWillPopUp": {}, + "mac:MenuWillRemoveItem": {}, + "mac:MenuWillSendAction": {}, + "mac:MenuWillSendActionToItem": {}, + "mac:MenuWillUpdate": {}, + "mac:WebViewDidCommitNavigation": {}, + "mac:WebViewDidFinishNavigation": {}, + "mac:WebViewDidReceiveServerRedirectForProvisionalNavigation": {}, + "mac:WebViewDidStartProvisionalNavigation": {}, + "mac:WindowDidBecomeKey": {}, + "mac:WindowDidBecomeMain": {}, + "mac:WindowDidBeginSheet": {}, + "mac:WindowDidChangeAlpha": {}, + "mac:WindowDidChangeBackingLocation": {}, + "mac:WindowDidChangeBackingProperties": {}, + "mac:WindowDidChangeCollectionBehavior": {}, + "mac:WindowDidChangeEffectiveAppearance": {}, + "mac:WindowDidChangeOcclusionState": {}, + "mac:WindowDidChangeOrderingMode": {}, + "mac:WindowDidChangeScreen": {}, + "mac:WindowDidChangeScreenParameters": {}, + "mac:WindowDidChangeScreenProfile": {}, + "mac:WindowDidChangeScreenSpace": {}, + "mac:WindowDidChangeScreenSpaceProperties": {}, + "mac:WindowDidChangeSharingType": {}, + "mac:WindowDidChangeSpace": {}, + "mac:WindowDidChangeSpaceOrderingMode": {}, + "mac:WindowDidChangeTitle": {}, + "mac:WindowDidChangeToolbar": {}, + "mac:WindowDidDeminiaturize": {}, + "mac:WindowDidEndSheet": {}, + "mac:WindowDidEnterFullScreen": {}, + "mac:WindowDidEnterVersionBrowser": {}, + "mac:WindowDidExitFullScreen": {}, + "mac:WindowDidExitVersionBrowser": {}, + "mac:WindowDidExpose": {}, + "mac:WindowDidFocus": {}, + "mac:WindowDidMiniaturize": {}, + "mac:WindowDidMove": {}, + "mac:WindowDidOrderOffScreen": {}, + "mac:WindowDidOrderOnScreen": {}, + "mac:WindowDidResignKey": {}, + "mac:WindowDidResignMain": {}, + "mac:WindowDidResize": {}, + "mac:WindowDidUpdate": {}, + "mac:WindowDidUpdateAlpha": {}, + "mac:WindowDidUpdateCollectionBehavior": {}, + "mac:WindowDidUpdateCollectionProperties": {}, + "mac:WindowDidUpdateShadow": {}, + "mac:WindowDidUpdateTitle": {}, + "mac:WindowDidUpdateToolbar": {}, + "mac:WindowDidZoom!": {}, + "mac:WindowFileDraggingEntered": {}, + "mac:WindowFileDraggingExited": {}, + "mac:WindowFileDraggingPerformed": {}, + "mac:WindowHide": {}, + "mac:WindowMaximise!": {}, + "mac:WindowUnMaximise!": {}, + "mac:WindowMinimise!": {}, + "mac:WindowUnMinimise!": {}, + "mac:WindowShouldClose!": {}, + "mac:WindowShow": {}, + "mac:WindowWillBecomeKey": {}, + "mac:WindowWillBecomeMain": {}, + "mac:WindowWillBeginSheet": {}, + "mac:WindowWillChangeOrderingMode": {}, + "mac:WindowWillClose": {}, + "mac:WindowWillDeminiaturize": {}, + "mac:WindowWillEnterFullScreen": {}, + "mac:WindowWillEnterVersionBrowser": {}, + "mac:WindowWillExitFullScreen": {}, + "mac:WindowWillExitVersionBrowser": {}, + "mac:WindowWillFocus": {}, + "mac:WindowWillMiniaturize": {}, + "mac:WindowWillMove": {}, + "mac:WindowWillOrderOffScreen": {}, + "mac:WindowWillOrderOnScreen": {}, + "mac:WindowWillResignMain": {}, + "mac:WindowWillResize": {}, + "mac:WindowWillUnfocus": {}, + "mac:WindowWillUpdate": {}, + "mac:WindowWillUpdateAlpha": {}, + "mac:WindowWillUpdateCollectionBehavior": {}, + "mac:WindowWillUpdateCollectionProperties": {}, + "mac:WindowWillUpdateShadow": {}, + "mac:WindowWillUpdateTitle": {}, + "mac:WindowWillUpdateToolbar": {}, + "mac:WindowWillUpdateVisibility": {}, + "mac:WindowWillUseStandardFrame": {}, + "mac:WindowZoomIn!": {}, + "mac:WindowZoomOut!": {}, + "mac:WindowZoomReset!": {}, + "windows:APMPowerSettingChange": {}, + "windows:APMPowerStatusChange": {}, + "windows:APMResumeAutomatic": {}, + "windows:APMResumeSuspend": {}, + "windows:APMSuspend": {}, + "windows:ApplicationStarted": {}, + "windows:SystemThemeChanged": {}, + "windows:WebViewNavigationCompleted": {}, + "windows:WindowActive": {}, + "windows:WindowBackgroundErase": {}, + "windows:WindowClickActive": {}, + "windows:WindowClosing": {}, + "windows:WindowDidMove": {}, + "windows:WindowDidResize": {}, + "windows:WindowDPIChanged": {}, + "windows:WindowDragDrop": {}, + "windows:WindowDragEnter": {}, + "windows:WindowDragLeave": {}, + "windows:WindowDragOver": {}, + "windows:WindowEndMove": {}, + "windows:WindowEndResize": {}, + "windows:WindowFullscreen": {}, + "windows:WindowHide": {}, + "windows:WindowInactive": {}, + "windows:WindowKeyDown": {}, + "windows:WindowKeyUp": {}, + "windows:WindowKillFocus": {}, + "windows:WindowNonClientHit": {}, + "windows:WindowNonClientMouseDown": {}, + "windows:WindowNonClientMouseLeave": {}, + "windows:WindowNonClientMouseMove": {}, + "windows:WindowNonClientMouseUp": {}, + "windows:WindowPaint": {}, + "windows:WindowRestore": {}, + "windows:WindowSetFocus": {}, + "windows:WindowShow": {}, + "windows:WindowStartMove": {}, + "windows:WindowStartResize": {}, + "windows:WindowUnFullscreen": {}, + "windows:WindowZOrderChanged": {}, + "windows:WindowMinimise": {}, + "windows:WindowUnMinimise": {}, + "windows:WindowMaximise": {}, + "windows:WindowUnMaximise": {}, +} diff --git a/v3/internal/generator/collect/package.go b/v3/internal/generator/collect/package.go index b03d5e577..1d4a9414b 100644 --- a/v3/internal/generator/collect/package.go +++ b/v3/internal/generator/collect/package.go @@ -16,7 +16,7 @@ import ( // PackageInfo records information about a package. // -// Read accesses to fields Path, Name, Types, TypesInfo, Fset +// Read accesses to fields Path, Name, IsOrImportsApp, Types, TypesInfo, Fset, // are safe at any time without any synchronisation. // // Read accesses to all other fields are only safe @@ -32,6 +32,9 @@ type PackageInfo struct { // Name holds the import name of the described package. Name string + // IsOrImportsApp is true if this package is, or depends upon, the Wails application package. + IsOrImportsApp bool + // Types and TypesInfo hold type information for this package. Types *types.Package TypesInfo *types.Info @@ -73,10 +76,14 @@ type PackageInfo struct { } func newPackageInfo(pkg *packages.Package, collector *Collector) *PackageInfo { + _, importsApp := pkg.Imports[collector.systemPaths.ApplicationPackage] + return &PackageInfo{ Path: pkg.PkgPath, Name: pkg.Name, + IsOrImportsApp: importsApp || pkg.PkgPath == collector.systemPaths.ApplicationPackage, + Types: pkg.Types, TypesInfo: pkg.TypesInfo, @@ -87,7 +94,7 @@ func newPackageInfo(pkg *packages.Package, collector *Collector) *PackageInfo { } } -// Package retrieves the the unique [PackageInfo] instance, if any, +// Package retrieves the unique [PackageInfo] instance, if any, // associated to the given package object within a Collector. // // Package is safe for concurrent use. diff --git a/v3/internal/generator/collect/predicates.go b/v3/internal/generator/collect/predicates.go index bcb910186..8a4b3197c 100644 --- a/v3/internal/generator/collect/predicates.go +++ b/v3/internal/generator/collect/predicates.go @@ -476,3 +476,123 @@ func IsAny(typ types.Type) bool { return true } + +// IsParametric returns true if the given type +// contains unresolved type parameters. +func IsParametric(typ types.Type) bool { + for { // Avoid recursion where possible + switch t := typ.(type) { + case *types.Alias, *types.Named: + tp := t.(interface{ TypeParams() *types.TypeParamList }).TypeParams() + ta := t.(interface{ TypeArgs() *types.TypeList }).TypeArgs() + + if tp.Len() == 0 { + // Not a generic alias/named type. + return false + } + + if ta.Len() == 0 { + // Uninstantiated generic. + return true + } + + for i := range ta.Len() - 1 { + if IsParametric(ta.At(i)) { + return true + } + } + + typ = ta.At(ta.Len() - 1) + + case *types.Basic: + return false + + case *types.Array, *types.Pointer, *types.Slice, *types.Chan: + typ = typ.(interface{ Elem() types.Type }).Elem() + + case *types.Map: + if IsParametric(t.Key()) { + return true + } + + typ = t.Elem() + + case *types.Signature: + if IsParametric(t.Params()) { + return true + } + + typ = t.Results() + + case *types.Struct: + if t.NumFields() == 0 { + // No more subtypes to check. + return false + } + + for i := range t.NumFields() - 1 { + if IsParametric(t.Field(i).Type()) { + return true + } + } + + typ = t.Field(t.NumFields() - 1).Type() + + case *types.Interface: + for m := range t.ExplicitMethods() { + if IsParametric(m.Type()) { + return true + } + } + + if t.NumEmbeddeds() == 0 { + // No more subtypes to check. + return false + } + + for i := range t.NumEmbeddeds() - 1 { + if IsParametric(t.EmbeddedType(i)) { + return true + } + } + + typ = t.EmbeddedType(t.NumEmbeddeds() - 1) + + case *types.Tuple: + if t.Len() == 0 { + // No more subtypes to check. + return false + } + + for i := range t.Len() - 1 { + if IsParametric(t.At(i).Type()) { + return true + } + } + + typ = t.At(t.Len() - 1).Type() + + case *types.TypeParam: + return true + + case *types.Union: + if t.Len() == 0 { + // No more subtypes to check. + return false + } + + for i := range t.Len() - 1 { + if IsParametric(t.Term(i).Type()) { + return true + } + } + + typ = t.Term(t.Len() - 1).Type() + + default: + // Unknown new type. + // This is wrong but [ImportMap.AddType] will take care of reporting it eventually. + return false + } + } +} diff --git a/v3/internal/generator/collect/service.go b/v3/internal/generator/collect/service.go index ba486cc37..56f500f79 100644 --- a/v3/internal/generator/collect/service.go +++ b/v3/internal/generator/collect/service.go @@ -282,14 +282,14 @@ func (info *ServiceInfo) collectMethod(method *types.Func) *ServiceMethodInfo { } } - if types.IsInterface(param.Type()) && !types.Identical(param.Type(), typeAny) { + if types.IsInterface(param.Type()) && !types.Identical(param.Type().Underlying(), typeAny) { paramName := param.Name() if paramName == "" || paramName == "_" { paramName = fmt.Sprintf("#%d", i+1) } collector.logger.Warningf( - "%s: parameter %s has non-empty interface type %s: this is not supported by encoding/json and will likely result in runtime errors", + "%s: parameter %s has non-empty interface type %s: passing values other than `null` is not supported by encoding/json and will likely result in runtime errors", collector.Package(method.Pkg()).Fset.Position(param.Pos()), paramName, param.Type(), diff --git a/v3/internal/generator/collect/stats.go b/v3/internal/generator/collect/stats.go index 984c7e504..9b5045565 100644 --- a/v3/internal/generator/collect/stats.go +++ b/v3/internal/generator/collect/stats.go @@ -8,6 +8,7 @@ type Stats struct { NumMethods int NumEnums int NumModels int + NumEvents int StartTime time.Time EndTime time.Time } @@ -31,4 +32,5 @@ func (stats *Stats) Add(other *Stats) { stats.NumMethods += other.NumMethods stats.NumEnums += other.NumEnums stats.NumModels += other.NumModels + stats.NumEvents += other.NumEvents } diff --git a/v3/internal/generator/collect/void.go b/v3/internal/generator/collect/void.go new file mode 100644 index 000000000..f1e328ba2 --- /dev/null +++ b/v3/internal/generator/collect/void.go @@ -0,0 +1,32 @@ +package collect + +import ( + "go/types" + "sync/atomic" +) + +// appVoidType caches the application.Void named type that stands in for the void TS type. +var appVoidType atomic.Value + +// IsVoidAlias returns true when the given type or object is the application.Void named type that stands in for the void TS type. +func (collector *Collector) IsVoidAlias(typOrObj any) bool { + var obj types.Object + switch to := typOrObj.(type) { + case types.Object: + obj = to + case interface{ Obj() *types.TypeName }: + obj = to.Obj() + default: + return false + } + + if vt := appVoidType.Load(); obj == vt { + return true + } else if vt == nil && obj.Name() == "Void" && obj.Pkg().Path() == collector.systemPaths.ApplicationPackage { // Check name before package to fail fast + // Cache void alias for faster checking + appVoidType.Store(obj) + return true + } + + return false +} diff --git a/v3/internal/generator/config/paths.go b/v3/internal/generator/config/paths.go index 84d18214c..26e1acb51 100644 --- a/v3/internal/generator/config/paths.go +++ b/v3/internal/generator/config/paths.go @@ -3,8 +3,12 @@ package config // WailsAppPkgPath is the official import path of Wails v3's application package. const WailsAppPkgPath = "github.com/wailsapp/wails/v3/pkg/application" +// WailsInternalPkgPath is the official import path of Wails v3's internal package. +const WailsInternalPkgPath = "github.com/wailsapp/wails/v3/internal" + // SystemPaths holds resolved paths of required system packages. type SystemPaths struct { ContextPackage string ApplicationPackage string + InternalPackage string } diff --git a/v3/internal/generator/errors.go b/v3/internal/generator/errors.go index cb000d1ad..1536ea9be 100644 --- a/v3/internal/generator/errors.go +++ b/v3/internal/generator/errors.go @@ -20,6 +20,11 @@ var ErrNoContextPackage = errors.New("standard context package not found at cano // did not match any actual package. var ErrNoApplicationPackage = errors.New("Wails application package not found at canonical import path ('" + config.WailsAppPkgPath + "'): is the Wails v3 module properly installed? ") +// ErrNoInternalPackage indicates that +// the canonical path for the Wails internal package +// did not match any actual package. +var ErrNoInternalPackage = errors.New("Wails internal package not found at canonical import path ('" + config.WailsInternalPkgPath + "'): is the Wails v3 module properly installed? ") + // ErrBadApplicationPackage indicates that // the Wails application package has invalid content. var ErrBadApplicationPackage = errors.New("package " + config.WailsAppPkgPath + ": function NewService has wrong signature: is the Wails v3 module properly installed? ") diff --git a/v3/internal/generator/events.go b/v3/internal/generator/events.go new file mode 100644 index 000000000..ef1ebd380 --- /dev/null +++ b/v3/internal/generator/events.go @@ -0,0 +1,53 @@ +package generator + +import ( + "path/filepath" + + "github.com/wailsapp/wails/v3/internal/generator/collect" +) + +func (generator *Generator) generateEvents(events *collect.EventMap) { + // Generate event data table. + generator.scheduler.Schedule(func() { + file, err := generator.creator.Create(filepath.Join(events.Imports.Self, generator.renderer.EventDataFile())) + if err != nil { + generator.logger.Errorf("%v", err) + generator.logger.Errorf("event data table generation failed") + return + } + defer func() { + if err := file.Close(); err != nil { + generator.logger.Errorf("%v", err) + generator.logger.Errorf("event data table generation failed") + } + }() + + err = generator.renderer.EventData(file, events) + if err != nil { + generator.logger.Errorf("%v", err) + generator.logger.Errorf("event data table generation failed") + } + }) + + // Generate event creation code. + generator.scheduler.Schedule(func() { + file, err := generator.creator.Create(filepath.Join(events.Imports.Self, generator.renderer.EventCreateFile())) + if err != nil { + generator.logger.Errorf("%v", err) + generator.logger.Errorf("event creation code generation failed") + return + } + defer func() { + if err := file.Close(); err != nil { + generator.logger.Errorf("%v", err) + generator.logger.Errorf("event creation code generation failed") + } + }() + + err = generator.renderer.EventCreate(file, events) + if err != nil { + generator.logger.Errorf("%v", err) + generator.logger.Errorf("event creation code generation failed") + } + }) +} diff --git a/v3/internal/generator/generate.go b/v3/internal/generator/generate.go index a3162ea8a..2885cdd3c 100644 --- a/v3/internal/generator/generate.go +++ b/v3/internal/generator/generate.go @@ -132,16 +132,20 @@ func (generator *Generator) Generate(patterns ...string) (stats *collect.Stats, panic("Generate() must not be called more than once on the same receiver") } - // Initialise subcomponents. - generator.collector = collect.NewCollector(pkgs, systemPaths, generator.options, &generator.scheduler, generator.logger) - generator.renderer = render.NewRenderer(generator.options, generator.collector) - // Update status. - generator.logger.Statusf("Looking for services...") - serviceFound := sync.OnceFunc(func() { generator.logger.Statusf("Generating service bindings...") }) + if generator.options.NoEvents { + generator.logger.Statusf("Looking for services...") + } else { + generator.logger.Statusf("Looking for services and events...") + } + serviceOrEventFound := sync.OnceFunc(func() { generator.logger.Statusf("Generating bindings...") }) // Run static analysis. - services, err := FindServices(pkgs, systemPaths, generator.logger) + services, registerEvent, err := FindServices(pkgs, systemPaths, generator.logger) + + // Initialise subcomponents. + generator.collector = collect.NewCollector(pkgs, registerEvent, systemPaths, generator.options, &generator.scheduler, generator.logger) + generator.renderer = render.NewRenderer(generator.collector, generator.options) // Check for analyser errors. if err != nil { @@ -151,9 +155,23 @@ func (generator *Generator) Generate(patterns ...string) (stats *collect.Stats, // Discard unneeded data. pkgs = nil + // Schedule collection and code generation for event data types. + if !generator.options.NoEvents { + generator.scheduler.Schedule(func() { + events := generator.collector.EventMap().Collect() + if len(events.Defs) > 0 { + serviceOrEventFound() + // Not a data race because we wait for this scheduled task + // to complete before accessing stats again. + stats.Add(events.Stats()) + } + generator.generateEvents(events) + }) + } + // Schedule code generation for each found service. for obj := range services { - serviceFound() + serviceOrEventFound() generator.scheduler.Schedule(func() { generator.generateService(obj) }) @@ -175,9 +193,9 @@ func (generator *Generator) Generate(patterns ...string) (stats *collect.Stats, } // Schedule models, index and included files generation for each package. - for info := range generator.collector.Iterate { + for pkg := range generator.collector.Iterate { generator.scheduler.Schedule(func() { - generator.generateModelsIndexIncludes(info) + generator.generateModelsIndexIncludes(pkg) }) } @@ -201,15 +219,15 @@ func (generator *Generator) Generate(patterns ...string) (stats *collect.Stats, // generateModelsIndexIncludes schedules generation of public/private model files, // included files and, if allowed by the options, // of an index file for the given package. -func (generator *Generator) generateModelsIndexIncludes(info *collect.PackageInfo) { - index := info.Index(generator.options.TS) +func (generator *Generator) generateModelsIndexIncludes(pkg *collect.PackageInfo) { + index := pkg.Index(generator.options.TS) // info.Index implies info.Collect: goroutines spawned below // can access package information freely. if len(index.Models) > 0 { generator.scheduler.Schedule(func() { - generator.generateModels(info, index.Models) + generator.generateModels(pkg, index.Models) }) } diff --git a/v3/internal/generator/generate_test.go b/v3/internal/generator/generate_test.go index 0e05cb6cb..98b61e66f 100644 --- a/v3/internal/generator/generate_test.go +++ b/v3/internal/generator/generate_test.go @@ -3,7 +3,6 @@ package generator import ( "errors" "fmt" - "github.com/wailsapp/wails/v3/internal/generator/render" "io" "io/fs" "os" @@ -17,6 +16,7 @@ import ( "github.com/pterm/pterm" "github.com/wailsapp/wails/v3/internal/flags" "github.com/wailsapp/wails/v3/internal/generator/config" + "github.com/wailsapp/wails/v3/internal/generator/render" ) const testcases = "github.com/wailsapp/wails/v3/internal/generator/testcases/..." @@ -73,7 +73,7 @@ func TestGenerator(t *testing.T) { } // Skip got files. - if strings.HasSuffix(d.Name(), ".got.js") || strings.HasSuffix(d.Name(), ".got.ts") { + if strings.HasSuffix(d.Name(), ".got.js") || strings.HasSuffix(d.Name(), ".got.ts") || strings.HasSuffix(d.Name(), ".got.log") { return nil } @@ -116,6 +116,35 @@ func TestGenerator(t *testing.T) { warnings := report.Warnings() slices.Sort(warnings) + // Normalize paths in warnings to be relative to the testcases directory + // This ensures consistent output across different development environments and CI + for i, msg := range warnings { + // Handle both Unix and Windows path separators + msg = strings.ReplaceAll(msg, "\\", "/") + + // Check if this is a file path (contains line:column position) + // File paths look like: /path/to/file.go:123:45: message + // Package paths look like: package github.com/...: message + if strings.HasPrefix(msg, "package ") { + // Keep package warnings as-is + warnings[i] = msg + } else if idx := strings.Index(msg, "testcases/"); idx >= 0 { + // Check if it's a file path by looking for :line:column pattern after testcases/ + testcasesEnd := idx + len("testcases/") + colonIdx := strings.Index(msg[testcasesEnd:], ":") + if colonIdx > 0 { + // This looks like a file path, normalize it + warnings[i] = "/testcases/" + msg[testcasesEnd:] + } else { + // Not a file path, keep as-is + warnings[i] = msg + } + } else { + // Keep other warnings as-is + warnings[i] = msg + } + } + for _, msg := range warnings { fmt.Fprint(log, msg, render.Newline) } diff --git a/v3/internal/generator/load.go b/v3/internal/generator/load.go index a0d6f5f6b..da09ff76f 100644 --- a/v3/internal/generator/load.go +++ b/v3/internal/generator/load.go @@ -9,7 +9,7 @@ import ( "golang.org/x/tools/go/packages" ) -// ResolveSystemPaths resolves paths for the Wails system +// ResolveSystemPaths resolves paths for stdlib and Wails packages. func ResolveSystemPaths(buildFlags []string) (paths *config.SystemPaths, err error) { // Resolve context pkg path. contextPkgPaths, err := ResolvePatterns(buildFlags, "context") @@ -35,9 +35,22 @@ func ResolveSystemPaths(buildFlags []string) (paths *config.SystemPaths, err err panic("wails application package path matched multiple packages") } + // Resolve wails internal pkg path. + wailsInternalPkgPaths, err := ResolvePatterns(buildFlags, config.WailsInternalPkgPath) + if err != nil { + return + } else if len(wailsInternalPkgPaths) < 1 { + err = ErrNoInternalPackage + return + } else if len(wailsInternalPkgPaths) > 1 { + // This should never happen... + panic("wails internal package path matched multiple packages") + } + paths = &config.SystemPaths{ ContextPackage: contextPkgPaths[0], ApplicationPackage: wailsAppPkgPaths[0], + InternalPackage: wailsInternalPkgPaths[0], } return } diff --git a/v3/internal/generator/render/create.go b/v3/internal/generator/render/create.go index 1332345d1..4b0f3484e 100644 --- a/v3/internal/generator/render/create.go +++ b/v3/internal/generator/render/create.go @@ -30,6 +30,10 @@ func (m *module) NeedsCreate(typ types.Type) bool { func (m *module) needsCreateImpl(typ types.Type, visited *typeutil.Map) bool { switch t := typ.(type) { case *types.Alias: + if m.collector.IsVoidAlias(t.Obj()) { + return false + } + return m.needsCreateImpl(types.Unalias(typ), visited) case *types.Named: @@ -46,6 +50,10 @@ func (m *module) needsCreateImpl(typ types.Type, visited *typeutil.Map) bool { return m.needsCreateImpl(t.Underlying(), visited) } + if m.collector.IsVoidAlias(t.Obj()) { + return false + } + if collect.IsAny(typ) || collect.IsStringAlias(typ) { break } else if collect.IsClass(typ) { @@ -97,13 +105,17 @@ func (m *module) JSCreate(typ types.Type) string { // JSCreateWithParams's output may be incorrect // if m.Imports.AddType has not been called for the given type. func (m *module) JSCreateWithParams(typ types.Type, params string) string { - if len(params) > 0 && !m.hasTypeParams(typ) { + if len(params) > 0 && !collect.IsParametric(typ) { // Forget params for non-generic types. params = "" } switch t := typ.(type) { case *types.Alias: + if m.collector.IsVoidAlias(t.Obj()) { + return "$Create.Any" + } + return m.JSCreateWithParams(types.Unalias(typ), params) case *types.Array, *types.Pointer: @@ -135,6 +147,10 @@ func (m *module) JSCreateWithParams(typ types.Type, params string) string { return m.JSCreateWithParams(t.Underlying(), params) } + if m.collector.IsVoidAlias(t.Obj()) { + return "$Create.Any" + } + if !m.NeedsCreate(typ) { break } @@ -341,51 +357,3 @@ type postponed struct { index int params string } - -// hasTypeParams returns true if the given type depends upon type parameters. -func (m *module) hasTypeParams(typ types.Type) bool { - switch t := typ.(type) { - case *types.Alias: - if t.Obj().Pkg() == nil { - // Builtin alias: these are never rendered as templates. - return false - } - - return m.hasTypeParams(types.Unalias(typ)) - - case *types.Array, *types.Pointer, *types.Slice: - return m.hasTypeParams(typ.(interface{ Elem() types.Type }).Elem()) - - case *types.Map: - return m.hasTypeParams(t.Key()) || m.hasTypeParams(t.Elem()) - - case *types.Named: - if t.Obj().Pkg() == nil { - // Builtin named type: these are never rendered as templates. - return false - } - - if targs := t.TypeArgs(); targs != nil { - for i := range targs.Len() { - if m.hasTypeParams(targs.At(i)) { - return true - } - } - } - - case *types.Struct: - info := m.collector.Struct(t) - info.Collect() - - for _, field := range info.Fields { - if m.hasTypeParams(field.Type) { - return true - } - } - - case *types.TypeParam: - return true - } - - return false -} diff --git a/v3/internal/generator/render/renderer.go b/v3/internal/generator/render/renderer.go index 5ddee85c2..81a6f5871 100644 --- a/v3/internal/generator/render/renderer.go +++ b/v3/internal/generator/render/renderer.go @@ -14,31 +14,31 @@ import ( // Renderer holds the template set for a given configuration. // It provides methods for rendering various output modules. type Renderer struct { - options *flags.GenerateBindingsOptions collector *collect.Collector + options *flags.GenerateBindingsOptions ext string - service *template.Template - typedefs *template.Template + service *template.Template + models *template.Template } // NewRenderer initialises a code renderer // for the given configuration and data collector. -func NewRenderer(options *flags.GenerateBindingsOptions, collector *collect.Collector) *Renderer { +func NewRenderer(collector *collect.Collector, options *flags.GenerateBindingsOptions) *Renderer { ext := ".js" if options.TS { ext = ".ts" } return &Renderer{ - options: options, collector: collector, + options: options, ext: ext, - service: tmplService[tmplLanguage(options.TS)], - typedefs: tmplModels[tmplLanguage(options.TS)], + service: tmplService[tmplLanguage(options.TS)], + models: tmplModels[tmplLanguage(options.TS)], } } @@ -54,6 +54,18 @@ func (renderer *Renderer) ModelsFile() string { return renderer.options.ModelsFilename + renderer.ext } +// EventDataFile returns the standard name of the event data definitions file +// with the appropriate extension. +func (renderer *Renderer) EventDataFile() string { + return "eventdata.d.ts" +} + +// EventCreateFile returns the standard name of the event data creation file +// with the appropriate extension. +func (renderer *Renderer) EventCreateFile() string { + return "eventcreate" + renderer.ext +} + // IndexFile returns the standard name of a package index file // with the appropriate extension. func (renderer *Renderer) IndexFile() string { @@ -75,7 +87,7 @@ func (renderer *Renderer) Service(w io.Writer, info *collect.ServiceInfo) error }) } -// Typedefs renders type definitions for the given list of models. +// Models renders type definitions for the given list of models. func (renderer *Renderer) Models(w io.Writer, imports *collect.ImportMap, models []*collect.ModelInfo) error { if !renderer.options.UseInterfaces { // Sort class aliases after the class they alias. @@ -114,7 +126,7 @@ func (renderer *Renderer) Models(w io.Writer, imports *collect.ImportMap, models } } - return renderer.typedefs.Execute(w, &struct { + return renderer.models.Execute(w, &struct { module Models []*collect.ModelInfo }{ @@ -127,6 +139,36 @@ func (renderer *Renderer) Models(w io.Writer, imports *collect.ImportMap, models }) } +// EventData renders the given event map to w as an event data table. +func (renderer *Renderer) EventData(w io.Writer, events *collect.EventMap) error { + return tmplEventData.Execute(w, &struct { + module + Events *collect.EventMap + }{ + module{ + Renderer: renderer, + GenerateBindingsOptions: renderer.options, + Imports: events.Imports, + }, + events, + }) +} + +// EventCreate renders the given event map to w as event data creation code. +func (renderer *Renderer) EventCreate(w io.Writer, events *collect.EventMap) error { + return tmplEventCreate.Execute(w, &struct { + module + Events *collect.EventMap + }{ + module{ + Renderer: renderer, + GenerateBindingsOptions: renderer.options, + Imports: events.Imports, + }, + events, + }) +} + // Index renders the given package index to w. func (renderer *Renderer) Index(w io.Writer, index *collect.PackageIndex) error { return tmplIndex.Execute(w, &struct { diff --git a/v3/internal/generator/render/templates.go b/v3/internal/generator/render/templates.go index 5aa7398f5..5b137d665 100644 --- a/v3/internal/generator/render/templates.go +++ b/v3/internal/generator/render/templates.go @@ -23,6 +23,9 @@ var tmplModels = map[tmplLanguage]*template.Template{ tmplTS: template.Must(template.New("models.ts.tmpl").Funcs(tmplFunctions).ParseFS(templates, "templates/models.ts.tmpl")), } +var tmplEventData = template.Must(template.New("eventdata.d.ts.tmpl").Funcs(tmplFunctions).ParseFS(templates, "templates/eventdata.d.ts.tmpl")) +var tmplEventCreate = template.Must(template.New("eventcreate.js.tmpl").Funcs(tmplFunctions).ParseFS(templates, "templates/eventcreate.js.tmpl")) + var tmplIndex = template.Must(template.New("index.tmpl").Funcs(tmplFunctions).ParseFS(templates, "templates/index.tmpl")) var Newline string diff --git a/v3/internal/generator/render/templates/eventcreate.js.tmpl b/v3/internal/generator/render/templates/eventcreate.js.tmpl new file mode 100644 index 000000000..2aa8eb254 --- /dev/null +++ b/v3/internal/generator/render/templates/eventcreate.js.tmpl @@ -0,0 +1,47 @@ +{{$module := .}} +{{- $runtime := $module.Runtime}} +{{- $models := (fixext $module.ModelsFile)}} +{{- $useInterfaces := $module.UseInterfaces}} +{{- $imports := $module.Imports}} +{{- with .Events -}} +//@ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "{{js $runtime}}"; +{{if (and (not $useInterfaces) .Defs)}} +{{- range $imports.External}} +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as {{jsimport .}} from "{{js .RelPath}}/{{js $models}}"; +{{- end}}{{if $imports.External}} +{{end}} +{{- if $imports.ImportModels}} +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as $models from "./{{js $models}}"; +{{end}} +function configure() { + Object.freeze(Object.assign($Create.Events, { + {{- range .Defs}} + {{- $create := ($module.JSCreate .Data)}} + {{- if ne $create "$Create.Any"}} + "{{js .Name}}": {{$create}}, + {{- end}} + {{- end}} + })); +} +{{$postponed := $module.PostponedCreates}} +{{- if $postponed}} +// Private type creation functions +{{- range $i, $create := $postponed}} +{{if and (ge (len $create) 54) (eq (slice $create 39 54) "function $$init")}}var {{else}}const {{end -}} +$$createType{{$i}} = {{$create}}; +{{- end}} +{{end}} +configure(); +{{else}} +Object.freeze($Create.Events); +{{end}}{{end -}} diff --git a/v3/internal/generator/render/templates/eventdata.d.ts.tmpl b/v3/internal/generator/render/templates/eventdata.d.ts.tmpl new file mode 100644 index 000000000..9278a6a7c --- /dev/null +++ b/v3/internal/generator/render/templates/eventdata.d.ts.tmpl @@ -0,0 +1,32 @@ +{{$module := .}} +{{- $runtime := $module.Runtime}} +{{- $models := (fixext $module.ModelsFile)}} +{{- $imports := $module.Imports}} +{{- with .Events -}} +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT +{{if .Defs}} +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type { Events } from "{{js $runtime}}"; +{{range $imports.External}} +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as {{jsimport .}} from "{{js .RelPath}}/{{js $models}}"; +{{- end}}{{if $imports.External}} +{{end}} +{{- if $imports.ImportModels}} +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as $models from "./{{js $models}}"; +{{end}} +declare module "{{js $runtime}}" { + namespace Events { + interface CustomEvents { + {{- range .Defs}} + "{{js .Name}}": {{$module.JSType .Data}}; + {{- end}} + } + } +} +{{end}}{{end -}} diff --git a/v3/internal/generator/render/type.go b/v3/internal/generator/render/type.go index 2c880154a..f694a11c3 100644 --- a/v3/internal/generator/render/type.go +++ b/v3/internal/generator/render/type.go @@ -176,6 +176,11 @@ func (m *module) renderNamedType(typ aliasOrNamed, quoted bool) (result string, return m.renderType(typ.Underlying(), quoted) } + // Special case: application.Void renders as TS void + if m.collector.IsVoidAlias(typ.Obj()) { + return "void", false + } + if quoted { switch a := types.Unalias(typ).(type) { case *types.Basic: diff --git a/v3/internal/generator/testcases/complex_json/events.json b/v3/internal/generator/testcases/complex_json/events.json new file mode 100644 index 000000000..f32a5804e --- /dev/null +++ b/v3/internal/generator/testcases/complex_json/events.json @@ -0,0 +1 @@ +true \ No newline at end of file diff --git a/v3/internal/generator/testcases/complex_json/main.go b/v3/internal/generator/testcases/complex_json/main.go index 87e57912a..2ed78d55b 100644 --- a/v3/internal/generator/testcases/complex_json/main.go +++ b/v3/internal/generator/testcases/complex_json/main.go @@ -122,3 +122,8 @@ func main() { } } + +func init() { + application.RegisterEvent[map[string]int]("collision") + application.RegisterEvent[*struct{ Field []bool }]("overlap") +} diff --git a/v3/internal/generator/testcases/events_only/events.go b/v3/internal/generator/testcases/events_only/events.go new file mode 100644 index 000000000..dcd4c642c --- /dev/null +++ b/v3/internal/generator/testcases/events_only/events.go @@ -0,0 +1,26 @@ +package events_only + +import ( + "fmt" + + nobindingshere "github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here" + "github.com/wailsapp/wails/v3/pkg/application" +) + +// SomeClass renders as a TS class. +type SomeClass struct { + Field string + Meadow nobindingshere.HowDifferent[rune] +} + +func init() { + application.RegisterEvent[string]("events_only:string") + application.RegisterEvent[map[string][]int]("events_only:map") + application.RegisterEvent[SomeClass]("events_only:class") + application.RegisterEvent[int]("collision") + application.RegisterEvent[bool](fmt.Sprintf("events_only:%s%d", "dynamic", 3)) +} + +func init() { + application.RegisterEvent[application.Void]("events_only:nodata") +} diff --git a/v3/internal/generator/testcases/events_only/events.json b/v3/internal/generator/testcases/events_only/events.json new file mode 100644 index 000000000..f32a5804e --- /dev/null +++ b/v3/internal/generator/testcases/events_only/events.json @@ -0,0 +1 @@ +true \ No newline at end of file diff --git a/v3/internal/generator/testcases/events_only/other.go b/v3/internal/generator/testcases/events_only/other.go new file mode 100644 index 000000000..1f76b4280 --- /dev/null +++ b/v3/internal/generator/testcases/events_only/other.go @@ -0,0 +1,26 @@ +package events_only + +import ( + "github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more" + "github.com/wailsapp/wails/v3/pkg/application" +) + +const eventPrefix = "events_only" + `:` + +var registerStringEvent = application.RegisterEvent[string] + +func registerIntEvent(name string) { + application.RegisterEvent[int](name) +} + +func registerSliceEvent[T any]() { + application.RegisterEvent[[]T]("parametric") +} + +func init() { + application.RegisterEvent[[]more.StringPtr](eventPrefix + "other") + application.RegisterEvent[string]("common:ApplicationStarted") + registerStringEvent("indirect_var") + registerIntEvent("indirect_fn") + registerSliceEvent[uintptr]() +} diff --git a/v3/internal/generator/testcases/marshalers/events.json b/v3/internal/generator/testcases/marshalers/events.json new file mode 100644 index 000000000..f32a5804e --- /dev/null +++ b/v3/internal/generator/testcases/marshalers/events.json @@ -0,0 +1 @@ +true \ No newline at end of file diff --git a/v3/internal/generator/testcases/marshalers/main.go b/v3/internal/generator/testcases/marshalers/main.go index 32c934e49..95300480c 100644 --- a/v3/internal/generator/testcases/marshalers/main.go +++ b/v3/internal/generator/testcases/marshalers/main.go @@ -207,3 +207,9 @@ func main() { } } + +func init() { + application.RegisterEvent[*struct{ Field []bool }]("collision") + application.RegisterEvent[*struct{ Field []bool }]("overlap") + application.RegisterEvent[json.Marshaler]("interface") +} diff --git a/v3/internal/generator/testcases/no_bindings_here/more/more.go b/v3/internal/generator/testcases/no_bindings_here/more/more.go new file mode 100644 index 000000000..d17eff09c --- /dev/null +++ b/v3/internal/generator/testcases/no_bindings_here/more/more.go @@ -0,0 +1,4 @@ +package more + +// StringPtr is a nullable string. +type StringPtr *string diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/eventcreate.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/eventcreate.js new file mode 100644 index 000000000..9cc7781aa --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/eventcreate.js @@ -0,0 +1,39 @@ +//@ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "/wails/runtime.js"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as json$0 from "../../../../../encoding/json/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as events_only$0 from "./generator/testcases/events_only/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as more$0 from "./generator/testcases/no_bindings_here/more/models.js"; + +function configure() { + Object.freeze(Object.assign($Create.Events, { + "events_only:class": $$createType0, + "events_only:map": $$createType2, + "events_only:other": $$createType3, + "overlap": $$createType6, + })); +} + +// Private type creation functions +const $$createType0 = events_only$0.SomeClass.createFrom; +const $$createType1 = $Create.Array($Create.Any); +const $$createType2 = $Create.Map($Create.Any, $$createType1); +const $$createType3 = $Create.Array($Create.Any); +const $$createType4 = $Create.Array($Create.Any); +const $$createType5 = $Create.Struct({ + "Field": $$createType4, +}); +const $$createType6 = $Create.Nullable($$createType5); + +configure(); diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/eventdata.d.ts b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/eventdata.d.ts new file mode 100644 index 000000000..d265e3adc --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/eventdata.d.ts @@ -0,0 +1,30 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type { Events } from "/wails/runtime.js"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as json$0 from "../../../../../encoding/json/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as events_only$0 from "./generator/testcases/events_only/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as more$0 from "./generator/testcases/no_bindings_here/more/models.js"; + +declare module "/wails/runtime.js" { + namespace Events { + interface CustomEvents { + "events_only:class": events_only$0.SomeClass; + "events_only:map": { [_: string]: number[] }; + "events_only:nodata": void; + "events_only:other": more$0.StringPtr[]; + "events_only:string": string; + "interface": json$0.Marshaler; + "overlap": {"Field": boolean[]} | null; + } + } +} diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.js new file mode 100644 index 000000000..ebcbd137f --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.js @@ -0,0 +1,7 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export { + SomeClass +} from "./models.js"; diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.js new file mode 100644 index 000000000..498ff20b5 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.js @@ -0,0 +1,56 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "/wails/runtime.js"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as nobindingshere$0 from "../no_bindings_here/models.js"; + +/** + * SomeClass renders as a TS class. + */ +export class SomeClass { + /** + * Creates a new SomeClass instance. + * @param {Partial} [$$source = {}] - The source object to create the SomeClass. + */ + constructor($$source = {}) { + if (!("Field" in $$source)) { + /** + * @member + * @type {string} + */ + this["Field"] = ""; + } + if (!("Meadow" in $$source)) { + /** + * @member + * @type {nobindingshere$0.HowDifferent} + */ + this["Meadow"] = (new nobindingshere$0.HowDifferent()); + } + + Object.assign(this, $$source); + } + + /** + * Creates a new SomeClass instance from a string or object. + * @param {any} [$$source = {}] + * @returns {SomeClass} + */ + static createFrom($$source = {}) { + const $$createField1_0 = $$createType0; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("Meadow" in $$parsedSource) { + $$parsedSource["Meadow"] = $$createField1_0($$parsedSource["Meadow"]); + } + return new SomeClass(/** @type {Partial} */($$parsedSource)); + } +} + +// Private type creation functions +const $$createType0 = nobindingshere$0.HowDifferent.createFrom($Create.Any); diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.js new file mode 100644 index 000000000..c3eabd022 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.js @@ -0,0 +1,10 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +import * as $models from "./models.js"; + +/** + * StringPtr is a nullable string. + * @typedef {$models.StringPtr} StringPtr + */ diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.js new file mode 100644 index 000000000..b4fdacf8e --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.js @@ -0,0 +1,12 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "/wails/runtime.js"; + +/** + * StringPtr is a nullable string. + * @typedef {string | null} StringPtr + */ diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/warnings.log b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/warnings.log index e802b6b63..6a0cc5203 100644 --- a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/warnings.log +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=false/warnings.log @@ -1,3 +1,16 @@ +/testcases/complex_json/main.go:127:2: event 'collision' has one of multiple definitions here with data type map[string]int +/testcases/events_only/events.go:20:2: event 'collision' has one of multiple definitions here with data type int +/testcases/events_only/events.go:21:2: `application.RegisterEvent` called here with non-constant event name +/testcases/events_only/other.go:10:5: `application.RegisterEvent` is instantiated here but not called +/testcases/events_only/other.go:13:2: `application.RegisterEvent` called here with non-constant event name +/testcases/events_only/other.go:17:2: data type []T for event 'parametric' contains unresolved type parameters and will be ignored` +/testcases/events_only/other.go:22:2: event 'common:ApplicationStarted' is a known system event and cannot be overridden; this call to `application.RegisterEvent` will panic +/testcases/marshalers/main.go:212:2: event 'collision' has one of multiple definitions here with data type *struct{Field []bool} +/testcases/marshalers/main.go:214:2: data type encoding/json.Marshaler for event 'interface' is a non-empty interface: emitting events from the frontend with data other than `null` is not supported by encoding/json and will likely result in runtime errors +dynamically registered event names are not discoverable by the binding generator: it is recommended to invoke `application.RegisterEvent` with constant arguments only +event 'collision' has multiple conflicting definitions and will be ignored +events registered through indirect calls are not discoverable by the binding generator: it is recommended to invoke `application.RegisterEvent` directly +generic wrappers for calls to `application.RegisterEvent` are not analysable by the binding generator: it is recommended to call `application.RegisterEvent` with concrete types only package github.com/wailsapp/wails/v3/internal/generator/testcases/map_keys: type *R is used as a map key, but some of its instantiations might not implement encoding.TextMarshaler: this might result in runtime errors package github.com/wailsapp/wails/v3/internal/generator/testcases/map_keys: type *S is used as a map key, but some of its instantiations might not implement encoding.TextMarshaler: this might result in runtime errors package github.com/wailsapp/wails/v3/internal/generator/testcases/map_keys: type *T is used as a map key, but some of its instantiations might not implement encoding.TextMarshaler: this might result in runtime errors diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/eventcreate.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/eventcreate.js new file mode 100644 index 000000000..3d3607cf4 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/eventcreate.js @@ -0,0 +1,42 @@ +//@ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "/wails/runtime.js"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as json$0 from "../../../../../encoding/json/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as events_only$0 from "./generator/testcases/events_only/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as more$0 from "./generator/testcases/no_bindings_here/more/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as application$0 from "../pkg/application/models.js"; + +function configure() { + Object.freeze(Object.assign($Create.Events, { + "events_only:class": $$createType0, + "events_only:map": $$createType2, + "events_only:other": $$createType3, + "overlap": $$createType6, + })); +} + +// Private type creation functions +const $$createType0 = events_only$0.SomeClass.createFrom; +const $$createType1 = $Create.Array($Create.Any); +const $$createType2 = $Create.Map($Create.Any, $$createType1); +const $$createType3 = $Create.Array($Create.Any); +const $$createType4 = $Create.Array($Create.Any); +const $$createType5 = $Create.Struct({ + "Field": $$createType4, +}); +const $$createType6 = $Create.Nullable($$createType5); + +configure(); diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/eventdata.d.ts b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/eventdata.d.ts new file mode 100644 index 000000000..e45b7eb94 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/eventdata.d.ts @@ -0,0 +1,33 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type { Events } from "/wails/runtime.js"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as json$0 from "../../../../../encoding/json/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as events_only$0 from "./generator/testcases/events_only/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as more$0 from "./generator/testcases/no_bindings_here/more/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as application$0 from "../pkg/application/models.js"; + +declare module "/wails/runtime.js" { + namespace Events { + interface CustomEvents { + "events_only:class": events_only$0.SomeClass; + "events_only:map": { [_: string]: number[] }; + "events_only:nodata": application$0.Void; + "events_only:other": more$0.StringPtr[]; + "events_only:string": string; + "interface": json$0.Marshaler; + "overlap": {"Field": boolean[]} | null; + } + } +} diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.js new file mode 100644 index 000000000..ebcbd137f --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.js @@ -0,0 +1,7 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export { + SomeClass +} from "./models.js"; diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.js new file mode 100644 index 000000000..498ff20b5 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.js @@ -0,0 +1,56 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "/wails/runtime.js"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as nobindingshere$0 from "../no_bindings_here/models.js"; + +/** + * SomeClass renders as a TS class. + */ +export class SomeClass { + /** + * Creates a new SomeClass instance. + * @param {Partial} [$$source = {}] - The source object to create the SomeClass. + */ + constructor($$source = {}) { + if (!("Field" in $$source)) { + /** + * @member + * @type {string} + */ + this["Field"] = ""; + } + if (!("Meadow" in $$source)) { + /** + * @member + * @type {nobindingshere$0.HowDifferent} + */ + this["Meadow"] = (new nobindingshere$0.HowDifferent()); + } + + Object.assign(this, $$source); + } + + /** + * Creates a new SomeClass instance from a string or object. + * @param {any} [$$source = {}] + * @returns {SomeClass} + */ + static createFrom($$source = {}) { + const $$createField1_0 = $$createType0; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("Meadow" in $$parsedSource) { + $$parsedSource["Meadow"] = $$createField1_0($$parsedSource["Meadow"]); + } + return new SomeClass(/** @type {Partial} */($$parsedSource)); + } +} + +// Private type creation functions +const $$createType0 = nobindingshere$0.HowDifferent.createFrom($Create.Any); diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.js new file mode 100644 index 000000000..c3eabd022 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.js @@ -0,0 +1,10 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +import * as $models from "./models.js"; + +/** + * StringPtr is a nullable string. + * @typedef {$models.StringPtr} StringPtr + */ diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.js new file mode 100644 index 000000000..b4fdacf8e --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.js @@ -0,0 +1,12 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "/wails/runtime.js"; + +/** + * StringPtr is a nullable string. + * @typedef {string | null} StringPtr + */ diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/index.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/index.js new file mode 100644 index 000000000..7696315ce --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/index.js @@ -0,0 +1,11 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +import * as $models from "./models.js"; + +/** + * Void will be translated by the binding generator to the TypeScript type 'void'. + * It can be used as an event data type to register events that must not have any associated data. + * @typedef {$models.Void} Void + */ diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/models.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/models.js new file mode 100644 index 000000000..abb54db41 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/models.js @@ -0,0 +1,13 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "/wails/runtime.js"; + +/** + * Void will be translated by the binding generator to the TypeScript type 'void'. + * It can be used as an event data type to register events that must not have any associated data. + * @typedef {any} Void + */ diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/warnings.log b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/warnings.log index e802b6b63..3eabc7b41 100644 --- a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/warnings.log +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=false/UseNames=true/warnings.log @@ -1,3 +1,17 @@ +/testcases/complex_json/main.go:127:2: event 'collision' has one of multiple definitions here with data type map[string]int +/testcases/events_only/events.go:20:2: event 'collision' has one of multiple definitions here with data type int +/testcases/events_only/events.go:21:2: `application.RegisterEvent` called here with non-constant event name +/testcases/events_only/events.go:25:2: data type github.com/wailsapp/wails/v3/pkg/application.Void for event 'events_only:nodata' is a non-empty interface: emitting events from the frontend with data other than `null` is not supported by encoding/json and will likely result in runtime errors +/testcases/events_only/other.go:10:5: `application.RegisterEvent` is instantiated here but not called +/testcases/events_only/other.go:13:2: `application.RegisterEvent` called here with non-constant event name +/testcases/events_only/other.go:17:2: data type []T for event 'parametric' contains unresolved type parameters and will be ignored` +/testcases/events_only/other.go:22:2: event 'common:ApplicationStarted' is a known system event and cannot be overridden; this call to `application.RegisterEvent` will panic +/testcases/marshalers/main.go:212:2: event 'collision' has one of multiple definitions here with data type *struct{Field []bool} +/testcases/marshalers/main.go:214:2: data type encoding/json.Marshaler for event 'interface' is a non-empty interface: emitting events from the frontend with data other than `null` is not supported by encoding/json and will likely result in runtime errors +dynamically registered event names are not discoverable by the binding generator: it is recommended to invoke `application.RegisterEvent` with constant arguments only +event 'collision' has multiple conflicting definitions and will be ignored +events registered through indirect calls are not discoverable by the binding generator: it is recommended to invoke `application.RegisterEvent` directly +generic wrappers for calls to `application.RegisterEvent` are not analysable by the binding generator: it is recommended to call `application.RegisterEvent` with concrete types only package github.com/wailsapp/wails/v3/internal/generator/testcases/map_keys: type *R is used as a map key, but some of its instantiations might not implement encoding.TextMarshaler: this might result in runtime errors package github.com/wailsapp/wails/v3/internal/generator/testcases/map_keys: type *S is used as a map key, but some of its instantiations might not implement encoding.TextMarshaler: this might result in runtime errors package github.com/wailsapp/wails/v3/internal/generator/testcases/map_keys: type *T is used as a map key, but some of its instantiations might not implement encoding.TextMarshaler: this might result in runtime errors diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/eventcreate.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/eventcreate.js new file mode 100644 index 000000000..71a208a3d --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/eventcreate.js @@ -0,0 +1,9 @@ +//@ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "/wails/runtime.js"; + +Object.freeze($Create.Events); diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/eventdata.d.ts b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/eventdata.d.ts new file mode 100644 index 000000000..f951b9830 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/eventdata.d.ts @@ -0,0 +1,33 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type { Events } from "/wails/runtime.js"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as json$0 from "../../../../../encoding/json/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as events_only$0 from "./generator/testcases/events_only/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as more$0 from "./generator/testcases/no_bindings_here/more/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as application$0 from "../pkg/application/models.js"; + +declare module "/wails/runtime.js" { + namespace Events { + interface CustomEvents { + "events_only:class": events_only$0.SomeClass; + "events_only:map": { [_: string]: number[] | null } | null; + "events_only:nodata": application$0.Void; + "events_only:other": more$0.StringPtr[] | null; + "events_only:string": string; + "interface": json$0.Marshaler; + "overlap": {"Field": boolean[] | null} | null; + } + } +} diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.js new file mode 100644 index 000000000..14b4d5da8 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.js @@ -0,0 +1,10 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +import * as $models from "./models.js"; + +/** + * SomeClass renders as a TS class. + * @typedef {$models.SomeClass} SomeClass + */ diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.js new file mode 100644 index 000000000..b99dbf18d --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.js @@ -0,0 +1,18 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as nobindingshere$0 from "../no_bindings_here/models.js"; + +/** + * SomeClass renders as a TS class. + * @typedef {Object} SomeClass + * @property {string} Field + * @property {nobindingshere$0.HowDifferent} Meadow + */ + +// In interface mode, this file is likely to contain just comments. +// We add a dummy export statement to ensure it is recognised as an ES module. +export {}; diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.js new file mode 100644 index 000000000..c3eabd022 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.js @@ -0,0 +1,10 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +import * as $models from "./models.js"; + +/** + * StringPtr is a nullable string. + * @typedef {$models.StringPtr} StringPtr + */ diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.js new file mode 100644 index 000000000..04f4d47dd --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.js @@ -0,0 +1,12 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +/** + * StringPtr is a nullable string. + * @typedef {string | null} StringPtr + */ + +// In interface mode, this file is likely to contain just comments. +// We add a dummy export statement to ensure it is recognised as an ES module. +export {}; diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/pkg/application/index.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/pkg/application/index.js new file mode 100644 index 000000000..7696315ce --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/pkg/application/index.js @@ -0,0 +1,11 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +import * as $models from "./models.js"; + +/** + * Void will be translated by the binding generator to the TypeScript type 'void'. + * It can be used as an event data type to register events that must not have any associated data. + * @typedef {$models.Void} Void + */ diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/pkg/application/models.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/pkg/application/models.js new file mode 100644 index 000000000..f9f822da1 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/pkg/application/models.js @@ -0,0 +1,13 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +/** + * Void will be translated by the binding generator to the TypeScript type 'void'. + * It can be used as an event data type to register events that must not have any associated data. + * @typedef {any} Void + */ + +// In interface mode, this file is likely to contain just comments. +// We add a dummy export statement to ensure it is recognised as an ES module. +export {}; diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/warnings.log b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/warnings.log index e802b6b63..3eabc7b41 100644 --- a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/warnings.log +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=false/warnings.log @@ -1,3 +1,17 @@ +/testcases/complex_json/main.go:127:2: event 'collision' has one of multiple definitions here with data type map[string]int +/testcases/events_only/events.go:20:2: event 'collision' has one of multiple definitions here with data type int +/testcases/events_only/events.go:21:2: `application.RegisterEvent` called here with non-constant event name +/testcases/events_only/events.go:25:2: data type github.com/wailsapp/wails/v3/pkg/application.Void for event 'events_only:nodata' is a non-empty interface: emitting events from the frontend with data other than `null` is not supported by encoding/json and will likely result in runtime errors +/testcases/events_only/other.go:10:5: `application.RegisterEvent` is instantiated here but not called +/testcases/events_only/other.go:13:2: `application.RegisterEvent` called here with non-constant event name +/testcases/events_only/other.go:17:2: data type []T for event 'parametric' contains unresolved type parameters and will be ignored` +/testcases/events_only/other.go:22:2: event 'common:ApplicationStarted' is a known system event and cannot be overridden; this call to `application.RegisterEvent` will panic +/testcases/marshalers/main.go:212:2: event 'collision' has one of multiple definitions here with data type *struct{Field []bool} +/testcases/marshalers/main.go:214:2: data type encoding/json.Marshaler for event 'interface' is a non-empty interface: emitting events from the frontend with data other than `null` is not supported by encoding/json and will likely result in runtime errors +dynamically registered event names are not discoverable by the binding generator: it is recommended to invoke `application.RegisterEvent` with constant arguments only +event 'collision' has multiple conflicting definitions and will be ignored +events registered through indirect calls are not discoverable by the binding generator: it is recommended to invoke `application.RegisterEvent` directly +generic wrappers for calls to `application.RegisterEvent` are not analysable by the binding generator: it is recommended to call `application.RegisterEvent` with concrete types only package github.com/wailsapp/wails/v3/internal/generator/testcases/map_keys: type *R is used as a map key, but some of its instantiations might not implement encoding.TextMarshaler: this might result in runtime errors package github.com/wailsapp/wails/v3/internal/generator/testcases/map_keys: type *S is used as a map key, but some of its instantiations might not implement encoding.TextMarshaler: this might result in runtime errors package github.com/wailsapp/wails/v3/internal/generator/testcases/map_keys: type *T is used as a map key, but some of its instantiations might not implement encoding.TextMarshaler: this might result in runtime errors diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/eventcreate.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/eventcreate.js new file mode 100644 index 000000000..71a208a3d --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/eventcreate.js @@ -0,0 +1,9 @@ +//@ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "/wails/runtime.js"; + +Object.freeze($Create.Events); diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/eventdata.d.ts b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/eventdata.d.ts new file mode 100644 index 000000000..f951b9830 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/eventdata.d.ts @@ -0,0 +1,33 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type { Events } from "/wails/runtime.js"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as json$0 from "../../../../../encoding/json/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as events_only$0 from "./generator/testcases/events_only/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as more$0 from "./generator/testcases/no_bindings_here/more/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as application$0 from "../pkg/application/models.js"; + +declare module "/wails/runtime.js" { + namespace Events { + interface CustomEvents { + "events_only:class": events_only$0.SomeClass; + "events_only:map": { [_: string]: number[] | null } | null; + "events_only:nodata": application$0.Void; + "events_only:other": more$0.StringPtr[] | null; + "events_only:string": string; + "interface": json$0.Marshaler; + "overlap": {"Field": boolean[] | null} | null; + } + } +} diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.js new file mode 100644 index 000000000..14b4d5da8 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.js @@ -0,0 +1,10 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +import * as $models from "./models.js"; + +/** + * SomeClass renders as a TS class. + * @typedef {$models.SomeClass} SomeClass + */ diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.js new file mode 100644 index 000000000..b99dbf18d --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.js @@ -0,0 +1,18 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as nobindingshere$0 from "../no_bindings_here/models.js"; + +/** + * SomeClass renders as a TS class. + * @typedef {Object} SomeClass + * @property {string} Field + * @property {nobindingshere$0.HowDifferent} Meadow + */ + +// In interface mode, this file is likely to contain just comments. +// We add a dummy export statement to ensure it is recognised as an ES module. +export {}; diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.js new file mode 100644 index 000000000..c3eabd022 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.js @@ -0,0 +1,10 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +import * as $models from "./models.js"; + +/** + * StringPtr is a nullable string. + * @typedef {$models.StringPtr} StringPtr + */ diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.js new file mode 100644 index 000000000..04f4d47dd --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.js @@ -0,0 +1,12 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +/** + * StringPtr is a nullable string. + * @typedef {string | null} StringPtr + */ + +// In interface mode, this file is likely to contain just comments. +// We add a dummy export statement to ensure it is recognised as an ES module. +export {}; diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/index.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/index.js new file mode 100644 index 000000000..7696315ce --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/index.js @@ -0,0 +1,11 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +import * as $models from "./models.js"; + +/** + * Void will be translated by the binding generator to the TypeScript type 'void'. + * It can be used as an event data type to register events that must not have any associated data. + * @typedef {$models.Void} Void + */ diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/models.js b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/models.js new file mode 100644 index 000000000..f9f822da1 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/models.js @@ -0,0 +1,13 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +/** + * Void will be translated by the binding generator to the TypeScript type 'void'. + * It can be used as an event data type to register events that must not have any associated data. + * @typedef {any} Void + */ + +// In interface mode, this file is likely to contain just comments. +// We add a dummy export statement to ensure it is recognised as an ES module. +export {}; diff --git a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/warnings.log b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/warnings.log index e802b6b63..3eabc7b41 100644 --- a/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/warnings.log +++ b/v3/internal/generator/testdata/output/lang=JS/UseInterfaces=true/UseNames=true/warnings.log @@ -1,3 +1,17 @@ +/testcases/complex_json/main.go:127:2: event 'collision' has one of multiple definitions here with data type map[string]int +/testcases/events_only/events.go:20:2: event 'collision' has one of multiple definitions here with data type int +/testcases/events_only/events.go:21:2: `application.RegisterEvent` called here with non-constant event name +/testcases/events_only/events.go:25:2: data type github.com/wailsapp/wails/v3/pkg/application.Void for event 'events_only:nodata' is a non-empty interface: emitting events from the frontend with data other than `null` is not supported by encoding/json and will likely result in runtime errors +/testcases/events_only/other.go:10:5: `application.RegisterEvent` is instantiated here but not called +/testcases/events_only/other.go:13:2: `application.RegisterEvent` called here with non-constant event name +/testcases/events_only/other.go:17:2: data type []T for event 'parametric' contains unresolved type parameters and will be ignored` +/testcases/events_only/other.go:22:2: event 'common:ApplicationStarted' is a known system event and cannot be overridden; this call to `application.RegisterEvent` will panic +/testcases/marshalers/main.go:212:2: event 'collision' has one of multiple definitions here with data type *struct{Field []bool} +/testcases/marshalers/main.go:214:2: data type encoding/json.Marshaler for event 'interface' is a non-empty interface: emitting events from the frontend with data other than `null` is not supported by encoding/json and will likely result in runtime errors +dynamically registered event names are not discoverable by the binding generator: it is recommended to invoke `application.RegisterEvent` with constant arguments only +event 'collision' has multiple conflicting definitions and will be ignored +events registered through indirect calls are not discoverable by the binding generator: it is recommended to invoke `application.RegisterEvent` directly +generic wrappers for calls to `application.RegisterEvent` are not analysable by the binding generator: it is recommended to call `application.RegisterEvent` with concrete types only package github.com/wailsapp/wails/v3/internal/generator/testcases/map_keys: type *R is used as a map key, but some of its instantiations might not implement encoding.TextMarshaler: this might result in runtime errors package github.com/wailsapp/wails/v3/internal/generator/testcases/map_keys: type *S is used as a map key, but some of its instantiations might not implement encoding.TextMarshaler: this might result in runtime errors package github.com/wailsapp/wails/v3/internal/generator/testcases/map_keys: type *T is used as a map key, but some of its instantiations might not implement encoding.TextMarshaler: this might result in runtime errors diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/eventcreate.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/eventcreate.ts new file mode 100644 index 000000000..3d3607cf4 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/eventcreate.ts @@ -0,0 +1,42 @@ +//@ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "/wails/runtime.js"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as json$0 from "../../../../../encoding/json/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as events_only$0 from "./generator/testcases/events_only/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as more$0 from "./generator/testcases/no_bindings_here/more/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as application$0 from "../pkg/application/models.js"; + +function configure() { + Object.freeze(Object.assign($Create.Events, { + "events_only:class": $$createType0, + "events_only:map": $$createType2, + "events_only:other": $$createType3, + "overlap": $$createType6, + })); +} + +// Private type creation functions +const $$createType0 = events_only$0.SomeClass.createFrom; +const $$createType1 = $Create.Array($Create.Any); +const $$createType2 = $Create.Map($Create.Any, $$createType1); +const $$createType3 = $Create.Array($Create.Any); +const $$createType4 = $Create.Array($Create.Any); +const $$createType5 = $Create.Struct({ + "Field": $$createType4, +}); +const $$createType6 = $Create.Nullable($$createType5); + +configure(); diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/eventdata.d.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/eventdata.d.ts new file mode 100644 index 000000000..e45b7eb94 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/eventdata.d.ts @@ -0,0 +1,33 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type { Events } from "/wails/runtime.js"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as json$0 from "../../../../../encoding/json/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as events_only$0 from "./generator/testcases/events_only/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as more$0 from "./generator/testcases/no_bindings_here/more/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as application$0 from "../pkg/application/models.js"; + +declare module "/wails/runtime.js" { + namespace Events { + interface CustomEvents { + "events_only:class": events_only$0.SomeClass; + "events_only:map": { [_: string]: number[] }; + "events_only:nodata": application$0.Void; + "events_only:other": more$0.StringPtr[]; + "events_only:string": string; + "interface": json$0.Marshaler; + "overlap": {"Field": boolean[]} | null; + } + } +} diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.ts new file mode 100644 index 000000000..bb6e0a17f --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.ts @@ -0,0 +1,6 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export { + SomeClass +} from "./models.js"; diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.ts new file mode 100644 index 000000000..4719f61cf --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.ts @@ -0,0 +1,45 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "/wails/runtime.js"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as nobindingshere$0 from "../no_bindings_here/models.js"; + +/** + * SomeClass renders as a TS class. + */ +export class SomeClass { + "Field": string; + "Meadow": nobindingshere$0.HowDifferent; + + /** Creates a new SomeClass instance. */ + constructor($$source: Partial = {}) { + if (!("Field" in $$source)) { + this["Field"] = ""; + } + if (!("Meadow" in $$source)) { + this["Meadow"] = (new nobindingshere$0.HowDifferent()); + } + + Object.assign(this, $$source); + } + + /** + * Creates a new SomeClass instance from a string or object. + */ + static createFrom($$source: any = {}): SomeClass { + const $$createField1_0 = $$createType0; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("Meadow" in $$parsedSource) { + $$parsedSource["Meadow"] = $$createField1_0($$parsedSource["Meadow"]); + } + return new SomeClass($$parsedSource as Partial); + } +} + +// Private type creation functions +const $$createType0 = nobindingshere$0.HowDifferent.createFrom($Create.Any); diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.ts new file mode 100644 index 000000000..ac743f356 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.ts @@ -0,0 +1,6 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export type { + StringPtr +} from "./models.js"; diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.ts new file mode 100644 index 000000000..168c7fdba --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.ts @@ -0,0 +1,11 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "/wails/runtime.js"; + +/** + * StringPtr is a nullable string. + */ +export type StringPtr = string | null; diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/pkg/application/index.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/pkg/application/index.ts new file mode 100644 index 000000000..bbfb139c9 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/pkg/application/index.ts @@ -0,0 +1,6 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export type { + Void +} from "./models.js"; diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/pkg/application/models.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/pkg/application/models.ts new file mode 100644 index 000000000..f1739cabc --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/github.com/wailsapp/wails/v3/pkg/application/models.ts @@ -0,0 +1,12 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "/wails/runtime.js"; + +/** + * Void will be translated by the binding generator to the TypeScript type 'void'. + * It can be used as an event data type to register events that must not have any associated data. + */ +export type Void = any; diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/warnings.log b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/warnings.log index e802b6b63..3eabc7b41 100644 --- a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/warnings.log +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=false/warnings.log @@ -1,3 +1,17 @@ +/testcases/complex_json/main.go:127:2: event 'collision' has one of multiple definitions here with data type map[string]int +/testcases/events_only/events.go:20:2: event 'collision' has one of multiple definitions here with data type int +/testcases/events_only/events.go:21:2: `application.RegisterEvent` called here with non-constant event name +/testcases/events_only/events.go:25:2: data type github.com/wailsapp/wails/v3/pkg/application.Void for event 'events_only:nodata' is a non-empty interface: emitting events from the frontend with data other than `null` is not supported by encoding/json and will likely result in runtime errors +/testcases/events_only/other.go:10:5: `application.RegisterEvent` is instantiated here but not called +/testcases/events_only/other.go:13:2: `application.RegisterEvent` called here with non-constant event name +/testcases/events_only/other.go:17:2: data type []T for event 'parametric' contains unresolved type parameters and will be ignored` +/testcases/events_only/other.go:22:2: event 'common:ApplicationStarted' is a known system event and cannot be overridden; this call to `application.RegisterEvent` will panic +/testcases/marshalers/main.go:212:2: event 'collision' has one of multiple definitions here with data type *struct{Field []bool} +/testcases/marshalers/main.go:214:2: data type encoding/json.Marshaler for event 'interface' is a non-empty interface: emitting events from the frontend with data other than `null` is not supported by encoding/json and will likely result in runtime errors +dynamically registered event names are not discoverable by the binding generator: it is recommended to invoke `application.RegisterEvent` with constant arguments only +event 'collision' has multiple conflicting definitions and will be ignored +events registered through indirect calls are not discoverable by the binding generator: it is recommended to invoke `application.RegisterEvent` directly +generic wrappers for calls to `application.RegisterEvent` are not analysable by the binding generator: it is recommended to call `application.RegisterEvent` with concrete types only package github.com/wailsapp/wails/v3/internal/generator/testcases/map_keys: type *R is used as a map key, but some of its instantiations might not implement encoding.TextMarshaler: this might result in runtime errors package github.com/wailsapp/wails/v3/internal/generator/testcases/map_keys: type *S is used as a map key, but some of its instantiations might not implement encoding.TextMarshaler: this might result in runtime errors package github.com/wailsapp/wails/v3/internal/generator/testcases/map_keys: type *T is used as a map key, but some of its instantiations might not implement encoding.TextMarshaler: this might result in runtime errors diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/eventcreate.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/eventcreate.ts new file mode 100644 index 000000000..3d3607cf4 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/eventcreate.ts @@ -0,0 +1,42 @@ +//@ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "/wails/runtime.js"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as json$0 from "../../../../../encoding/json/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as events_only$0 from "./generator/testcases/events_only/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as more$0 from "./generator/testcases/no_bindings_here/more/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as application$0 from "../pkg/application/models.js"; + +function configure() { + Object.freeze(Object.assign($Create.Events, { + "events_only:class": $$createType0, + "events_only:map": $$createType2, + "events_only:other": $$createType3, + "overlap": $$createType6, + })); +} + +// Private type creation functions +const $$createType0 = events_only$0.SomeClass.createFrom; +const $$createType1 = $Create.Array($Create.Any); +const $$createType2 = $Create.Map($Create.Any, $$createType1); +const $$createType3 = $Create.Array($Create.Any); +const $$createType4 = $Create.Array($Create.Any); +const $$createType5 = $Create.Struct({ + "Field": $$createType4, +}); +const $$createType6 = $Create.Nullable($$createType5); + +configure(); diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/eventdata.d.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/eventdata.d.ts new file mode 100644 index 000000000..e45b7eb94 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/eventdata.d.ts @@ -0,0 +1,33 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type { Events } from "/wails/runtime.js"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as json$0 from "../../../../../encoding/json/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as events_only$0 from "./generator/testcases/events_only/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as more$0 from "./generator/testcases/no_bindings_here/more/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as application$0 from "../pkg/application/models.js"; + +declare module "/wails/runtime.js" { + namespace Events { + interface CustomEvents { + "events_only:class": events_only$0.SomeClass; + "events_only:map": { [_: string]: number[] }; + "events_only:nodata": application$0.Void; + "events_only:other": more$0.StringPtr[]; + "events_only:string": string; + "interface": json$0.Marshaler; + "overlap": {"Field": boolean[]} | null; + } + } +} diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.ts new file mode 100644 index 000000000..bb6e0a17f --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.ts @@ -0,0 +1,6 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export { + SomeClass +} from "./models.js"; diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.ts new file mode 100644 index 000000000..4719f61cf --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.ts @@ -0,0 +1,45 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "/wails/runtime.js"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as nobindingshere$0 from "../no_bindings_here/models.js"; + +/** + * SomeClass renders as a TS class. + */ +export class SomeClass { + "Field": string; + "Meadow": nobindingshere$0.HowDifferent; + + /** Creates a new SomeClass instance. */ + constructor($$source: Partial = {}) { + if (!("Field" in $$source)) { + this["Field"] = ""; + } + if (!("Meadow" in $$source)) { + this["Meadow"] = (new nobindingshere$0.HowDifferent()); + } + + Object.assign(this, $$source); + } + + /** + * Creates a new SomeClass instance from a string or object. + */ + static createFrom($$source: any = {}): SomeClass { + const $$createField1_0 = $$createType0; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("Meadow" in $$parsedSource) { + $$parsedSource["Meadow"] = $$createField1_0($$parsedSource["Meadow"]); + } + return new SomeClass($$parsedSource as Partial); + } +} + +// Private type creation functions +const $$createType0 = nobindingshere$0.HowDifferent.createFrom($Create.Any); diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.ts new file mode 100644 index 000000000..ac743f356 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.ts @@ -0,0 +1,6 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export type { + StringPtr +} from "./models.js"; diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.ts new file mode 100644 index 000000000..168c7fdba --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.ts @@ -0,0 +1,11 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "/wails/runtime.js"; + +/** + * StringPtr is a nullable string. + */ +export type StringPtr = string | null; diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/index.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/index.ts new file mode 100644 index 000000000..bbfb139c9 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/index.ts @@ -0,0 +1,6 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export type { + Void +} from "./models.js"; diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/models.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/models.ts new file mode 100644 index 000000000..f1739cabc --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/models.ts @@ -0,0 +1,12 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "/wails/runtime.js"; + +/** + * Void will be translated by the binding generator to the TypeScript type 'void'. + * It can be used as an event data type to register events that must not have any associated data. + */ +export type Void = any; diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/warnings.log b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/warnings.log index e802b6b63..3eabc7b41 100644 --- a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/warnings.log +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=false/UseNames=true/warnings.log @@ -1,3 +1,17 @@ +/testcases/complex_json/main.go:127:2: event 'collision' has one of multiple definitions here with data type map[string]int +/testcases/events_only/events.go:20:2: event 'collision' has one of multiple definitions here with data type int +/testcases/events_only/events.go:21:2: `application.RegisterEvent` called here with non-constant event name +/testcases/events_only/events.go:25:2: data type github.com/wailsapp/wails/v3/pkg/application.Void for event 'events_only:nodata' is a non-empty interface: emitting events from the frontend with data other than `null` is not supported by encoding/json and will likely result in runtime errors +/testcases/events_only/other.go:10:5: `application.RegisterEvent` is instantiated here but not called +/testcases/events_only/other.go:13:2: `application.RegisterEvent` called here with non-constant event name +/testcases/events_only/other.go:17:2: data type []T for event 'parametric' contains unresolved type parameters and will be ignored` +/testcases/events_only/other.go:22:2: event 'common:ApplicationStarted' is a known system event and cannot be overridden; this call to `application.RegisterEvent` will panic +/testcases/marshalers/main.go:212:2: event 'collision' has one of multiple definitions here with data type *struct{Field []bool} +/testcases/marshalers/main.go:214:2: data type encoding/json.Marshaler for event 'interface' is a non-empty interface: emitting events from the frontend with data other than `null` is not supported by encoding/json and will likely result in runtime errors +dynamically registered event names are not discoverable by the binding generator: it is recommended to invoke `application.RegisterEvent` with constant arguments only +event 'collision' has multiple conflicting definitions and will be ignored +events registered through indirect calls are not discoverable by the binding generator: it is recommended to invoke `application.RegisterEvent` directly +generic wrappers for calls to `application.RegisterEvent` are not analysable by the binding generator: it is recommended to call `application.RegisterEvent` with concrete types only package github.com/wailsapp/wails/v3/internal/generator/testcases/map_keys: type *R is used as a map key, but some of its instantiations might not implement encoding.TextMarshaler: this might result in runtime errors package github.com/wailsapp/wails/v3/internal/generator/testcases/map_keys: type *S is used as a map key, but some of its instantiations might not implement encoding.TextMarshaler: this might result in runtime errors package github.com/wailsapp/wails/v3/internal/generator/testcases/map_keys: type *T is used as a map key, but some of its instantiations might not implement encoding.TextMarshaler: this might result in runtime errors diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/eventcreate.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/eventcreate.ts new file mode 100644 index 000000000..71a208a3d --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/eventcreate.ts @@ -0,0 +1,9 @@ +//@ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "/wails/runtime.js"; + +Object.freeze($Create.Events); diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/eventdata.d.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/eventdata.d.ts new file mode 100644 index 000000000..f951b9830 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/eventdata.d.ts @@ -0,0 +1,33 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type { Events } from "/wails/runtime.js"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as json$0 from "../../../../../encoding/json/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as events_only$0 from "./generator/testcases/events_only/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as more$0 from "./generator/testcases/no_bindings_here/more/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as application$0 from "../pkg/application/models.js"; + +declare module "/wails/runtime.js" { + namespace Events { + interface CustomEvents { + "events_only:class": events_only$0.SomeClass; + "events_only:map": { [_: string]: number[] | null } | null; + "events_only:nodata": application$0.Void; + "events_only:other": more$0.StringPtr[] | null; + "events_only:string": string; + "interface": json$0.Marshaler; + "overlap": {"Field": boolean[] | null} | null; + } + } +} diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.ts new file mode 100644 index 000000000..03b13d1cf --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.ts @@ -0,0 +1,6 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export type { + SomeClass +} from "./models.js"; diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.ts new file mode 100644 index 000000000..316f1bd22 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.ts @@ -0,0 +1,14 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as nobindingshere$0 from "../no_bindings_here/models.js"; + +/** + * SomeClass renders as a TS class. + */ +export interface SomeClass { + "Field": string; + "Meadow": nobindingshere$0.HowDifferent; +} diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.ts new file mode 100644 index 000000000..ac743f356 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.ts @@ -0,0 +1,6 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export type { + StringPtr +} from "./models.js"; diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.ts new file mode 100644 index 000000000..6a5a12300 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.ts @@ -0,0 +1,7 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +/** + * StringPtr is a nullable string. + */ +export type StringPtr = string | null; diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/pkg/application/index.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/pkg/application/index.ts new file mode 100644 index 000000000..bbfb139c9 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/pkg/application/index.ts @@ -0,0 +1,6 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export type { + Void +} from "./models.js"; diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/pkg/application/models.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/pkg/application/models.ts new file mode 100644 index 000000000..a8b4d1499 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/github.com/wailsapp/wails/v3/pkg/application/models.ts @@ -0,0 +1,8 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +/** + * Void will be translated by the binding generator to the TypeScript type 'void'. + * It can be used as an event data type to register events that must not have any associated data. + */ +export type Void = any; diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/warnings.log b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/warnings.log index e802b6b63..3eabc7b41 100644 --- a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/warnings.log +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=false/warnings.log @@ -1,3 +1,17 @@ +/testcases/complex_json/main.go:127:2: event 'collision' has one of multiple definitions here with data type map[string]int +/testcases/events_only/events.go:20:2: event 'collision' has one of multiple definitions here with data type int +/testcases/events_only/events.go:21:2: `application.RegisterEvent` called here with non-constant event name +/testcases/events_only/events.go:25:2: data type github.com/wailsapp/wails/v3/pkg/application.Void for event 'events_only:nodata' is a non-empty interface: emitting events from the frontend with data other than `null` is not supported by encoding/json and will likely result in runtime errors +/testcases/events_only/other.go:10:5: `application.RegisterEvent` is instantiated here but not called +/testcases/events_only/other.go:13:2: `application.RegisterEvent` called here with non-constant event name +/testcases/events_only/other.go:17:2: data type []T for event 'parametric' contains unresolved type parameters and will be ignored` +/testcases/events_only/other.go:22:2: event 'common:ApplicationStarted' is a known system event and cannot be overridden; this call to `application.RegisterEvent` will panic +/testcases/marshalers/main.go:212:2: event 'collision' has one of multiple definitions here with data type *struct{Field []bool} +/testcases/marshalers/main.go:214:2: data type encoding/json.Marshaler for event 'interface' is a non-empty interface: emitting events from the frontend with data other than `null` is not supported by encoding/json and will likely result in runtime errors +dynamically registered event names are not discoverable by the binding generator: it is recommended to invoke `application.RegisterEvent` with constant arguments only +event 'collision' has multiple conflicting definitions and will be ignored +events registered through indirect calls are not discoverable by the binding generator: it is recommended to invoke `application.RegisterEvent` directly +generic wrappers for calls to `application.RegisterEvent` are not analysable by the binding generator: it is recommended to call `application.RegisterEvent` with concrete types only package github.com/wailsapp/wails/v3/internal/generator/testcases/map_keys: type *R is used as a map key, but some of its instantiations might not implement encoding.TextMarshaler: this might result in runtime errors package github.com/wailsapp/wails/v3/internal/generator/testcases/map_keys: type *S is used as a map key, but some of its instantiations might not implement encoding.TextMarshaler: this might result in runtime errors package github.com/wailsapp/wails/v3/internal/generator/testcases/map_keys: type *T is used as a map key, but some of its instantiations might not implement encoding.TextMarshaler: this might result in runtime errors diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/eventcreate.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/eventcreate.ts new file mode 100644 index 000000000..71a208a3d --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/eventcreate.ts @@ -0,0 +1,9 @@ +//@ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "/wails/runtime.js"; + +Object.freeze($Create.Events); diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/eventdata.d.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/eventdata.d.ts new file mode 100644 index 000000000..f951b9830 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/eventdata.d.ts @@ -0,0 +1,33 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type { Events } from "/wails/runtime.js"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as json$0 from "../../../../../encoding/json/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as events_only$0 from "./generator/testcases/events_only/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as more$0 from "./generator/testcases/no_bindings_here/more/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as application$0 from "../pkg/application/models.js"; + +declare module "/wails/runtime.js" { + namespace Events { + interface CustomEvents { + "events_only:class": events_only$0.SomeClass; + "events_only:map": { [_: string]: number[] | null } | null; + "events_only:nodata": application$0.Void; + "events_only:other": more$0.StringPtr[] | null; + "events_only:string": string; + "interface": json$0.Marshaler; + "overlap": {"Field": boolean[] | null} | null; + } + } +} diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.ts new file mode 100644 index 000000000..03b13d1cf --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/index.ts @@ -0,0 +1,6 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export type { + SomeClass +} from "./models.js"; diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.ts new file mode 100644 index 000000000..316f1bd22 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/events_only/models.ts @@ -0,0 +1,14 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as nobindingshere$0 from "../no_bindings_here/models.js"; + +/** + * SomeClass renders as a TS class. + */ +export interface SomeClass { + "Field": string; + "Meadow": nobindingshere$0.HowDifferent; +} diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.ts new file mode 100644 index 000000000..ac743f356 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/index.ts @@ -0,0 +1,6 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export type { + StringPtr +} from "./models.js"; diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.ts new file mode 100644 index 000000000..6a5a12300 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here/more/models.ts @@ -0,0 +1,7 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +/** + * StringPtr is a nullable string. + */ +export type StringPtr = string | null; diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/index.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/index.ts new file mode 100644 index 000000000..bbfb139c9 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/index.ts @@ -0,0 +1,6 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export type { + Void +} from "./models.js"; diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/models.ts b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/models.ts new file mode 100644 index 000000000..a8b4d1499 --- /dev/null +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/github.com/wailsapp/wails/v3/pkg/application/models.ts @@ -0,0 +1,8 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +/** + * Void will be translated by the binding generator to the TypeScript type 'void'. + * It can be used as an event data type to register events that must not have any associated data. + */ +export type Void = any; diff --git a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/warnings.log b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/warnings.log index e802b6b63..3eabc7b41 100644 --- a/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/warnings.log +++ b/v3/internal/generator/testdata/output/lang=TS/UseInterfaces=true/UseNames=true/warnings.log @@ -1,3 +1,17 @@ +/testcases/complex_json/main.go:127:2: event 'collision' has one of multiple definitions here with data type map[string]int +/testcases/events_only/events.go:20:2: event 'collision' has one of multiple definitions here with data type int +/testcases/events_only/events.go:21:2: `application.RegisterEvent` called here with non-constant event name +/testcases/events_only/events.go:25:2: data type github.com/wailsapp/wails/v3/pkg/application.Void for event 'events_only:nodata' is a non-empty interface: emitting events from the frontend with data other than `null` is not supported by encoding/json and will likely result in runtime errors +/testcases/events_only/other.go:10:5: `application.RegisterEvent` is instantiated here but not called +/testcases/events_only/other.go:13:2: `application.RegisterEvent` called here with non-constant event name +/testcases/events_only/other.go:17:2: data type []T for event 'parametric' contains unresolved type parameters and will be ignored` +/testcases/events_only/other.go:22:2: event 'common:ApplicationStarted' is a known system event and cannot be overridden; this call to `application.RegisterEvent` will panic +/testcases/marshalers/main.go:212:2: event 'collision' has one of multiple definitions here with data type *struct{Field []bool} +/testcases/marshalers/main.go:214:2: data type encoding/json.Marshaler for event 'interface' is a non-empty interface: emitting events from the frontend with data other than `null` is not supported by encoding/json and will likely result in runtime errors +dynamically registered event names are not discoverable by the binding generator: it is recommended to invoke `application.RegisterEvent` with constant arguments only +event 'collision' has multiple conflicting definitions and will be ignored +events registered through indirect calls are not discoverable by the binding generator: it is recommended to invoke `application.RegisterEvent` directly +generic wrappers for calls to `application.RegisterEvent` are not analysable by the binding generator: it is recommended to call `application.RegisterEvent` with concrete types only package github.com/wailsapp/wails/v3/internal/generator/testcases/map_keys: type *R is used as a map key, but some of its instantiations might not implement encoding.TextMarshaler: this might result in runtime errors package github.com/wailsapp/wails/v3/internal/generator/testcases/map_keys: type *S is used as a map key, but some of its instantiations might not implement encoding.TextMarshaler: this might result in runtime errors package github.com/wailsapp/wails/v3/internal/generator/testcases/map_keys: type *T is used as a map key, but some of its instantiations might not implement encoding.TextMarshaler: this might result in runtime errors diff --git a/v3/internal/generator/testdata/tsconfig.json b/v3/internal/generator/testdata/tsconfig.json index aa4939e6a..20c5ee1e0 100644 --- a/v3/internal/generator/testdata/tsconfig.json +++ b/v3/internal/generator/testdata/tsconfig.json @@ -1,6 +1,12 @@ { - "include": ["output/**/*.js", "output/**/*.ts"], - "exclude": ["output/**/*.got.?s"], + "include": [ + "output/**/*.js", + "output/**/*.ts" + ], + "exclude": [ + "output/**/*.d.ts", + "output/**/*.got.?s" + ], "references": [ { "path": "../../runtime/desktop/@wailsio/runtime" } ], @@ -8,7 +14,7 @@ "allowJs": true, "noEmit": true, - "skipLibCheck": true, + "skipLibCheck": false, "target": "ES2015", "module": "ES2015", @@ -29,7 +35,7 @@ "noFallthroughCasesInSwitch": true, "paths": { - "/wails/runtime.js": ["../../runtime/desktop/@wailsio/runtime/src/index.ts"] + "/wails/runtime.js": ["../../runtime/desktop/@wailsio/runtime"] } } } diff --git a/v3/internal/runtime/desktop/@wailsio/runtime/package-lock.json b/v3/internal/runtime/desktop/@wailsio/runtime/package-lock.json index 28268f252..b3152e7ad 100644 --- a/v3/internal/runtime/desktop/@wailsio/runtime/package-lock.json +++ b/v3/internal/runtime/desktop/@wailsio/runtime/package-lock.json @@ -17,13 +17,14 @@ "typedoc-plugin-mdn-links": "^4.0.13", "typedoc-plugin-missing-exports": "^3.1.0", "typescript": "^5.7.3", + "vite": "^5.2.0", "vitest": "^3.0.6" } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", - "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", "cpu": [ "ppc64" ], @@ -34,13 +35,13 @@ "aix" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/android-arm": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz", - "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", "cpu": [ "arm" ], @@ -51,13 +52,13 @@ "android" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", - "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", "cpu": [ "arm64" ], @@ -68,13 +69,13 @@ "android" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/android-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz", - "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", "cpu": [ "x64" ], @@ -85,13 +86,13 @@ "android" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", - "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "cpu": [ "arm64" ], @@ -102,13 +103,13 @@ "darwin" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", - "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", "cpu": [ "x64" ], @@ -119,13 +120,13 @@ "darwin" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", - "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", "cpu": [ "arm64" ], @@ -136,13 +137,13 @@ "freebsd" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", - "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", "cpu": [ "x64" ], @@ -153,13 +154,13 @@ "freebsd" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", - "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", "cpu": [ "arm" ], @@ -170,13 +171,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", - "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", "cpu": [ "arm64" ], @@ -187,13 +188,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", - "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", "cpu": [ "ia32" ], @@ -204,13 +205,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", - "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", "cpu": [ "loong64" ], @@ -221,13 +222,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", - "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", "cpu": [ "mips64el" ], @@ -238,13 +239,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", - "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", "cpu": [ "ppc64" ], @@ -255,13 +256,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", - "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", "cpu": [ "riscv64" ], @@ -272,13 +273,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", - "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", "cpu": [ "s390x" ], @@ -289,13 +290,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", - "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "cpu": [ "x64" ], @@ -306,30 +307,13 @@ "linux" ], "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", - "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", - "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", "cpu": [ "x64" ], @@ -340,30 +324,13 @@ "netbsd" ], "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", - "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", - "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", "cpu": [ "x64" ], @@ -374,13 +341,13 @@ "openbsd" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", - "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", "cpu": [ "x64" ], @@ -391,13 +358,13 @@ "sunos" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", - "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", "cpu": [ "arm64" ], @@ -408,13 +375,13 @@ "win32" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", - "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", "cpu": [ "ia32" ], @@ -425,13 +392,13 @@ "win32" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", - "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", "cpu": [ "x64" ], @@ -442,7 +409,7 @@ "win32" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@gerrit0/mini-shiki": { @@ -494,9 +461,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz", - "integrity": "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.9.tgz", + "integrity": "sha512-qZdlImWXur0CFakn2BJ2znJOdqYZKiedEPEVNTBrpfPjc/YuTGcaYZcdmNFTkUj3DU0ZM/AElcM8Ybww3xVLzA==", "cpu": [ "arm" ], @@ -508,9 +475,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.8.tgz", - "integrity": "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.9.tgz", + "integrity": "sha512-4KW7P53h6HtJf5Y608T1ISKvNIYLWRKMvfnG0c44M6In4DQVU58HZFEVhWINDZKp7FZps98G3gxwC1sb0wXUUg==", "cpu": [ "arm64" ], @@ -522,9 +489,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.8.tgz", - "integrity": "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.9.tgz", + "integrity": "sha512-0CY3/K54slrzLDjOA7TOjN1NuLKERBgk9nY5V34mhmuu673YNb+7ghaDUs6N0ujXR7fz5XaS5Aa6d2TNxZd0OQ==", "cpu": [ "arm64" ], @@ -536,9 +503,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.8.tgz", - "integrity": "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.9.tgz", + "integrity": "sha512-eOojSEAi/acnsJVYRxnMkPFqcxSMFfrw7r2iD9Q32SGkb/Q9FpUY1UlAu1DH9T7j++gZ0lHjnm4OyH2vCI7l7Q==", "cpu": [ "x64" ], @@ -550,9 +517,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.8.tgz", - "integrity": "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.9.tgz", + "integrity": "sha512-2lzjQPJbN5UnHm7bHIUKFMulGTQwdvOkouJDpPysJS+QFBGDJqcfh+CxxtG23Ik/9tEvnebQiylYoazFMAgrYw==", "cpu": [ "arm64" ], @@ -564,9 +531,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.8.tgz", - "integrity": "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.9.tgz", + "integrity": "sha512-SLl0hi2Ah2H7xQYd6Qaiu01kFPzQ+hqvdYSoOtHYg/zCIFs6t8sV95kaoqjzjFwuYQLtOI0RZre/Ke0nPaQV+g==", "cpu": [ "x64" ], @@ -578,9 +545,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.8.tgz", - "integrity": "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.9.tgz", + "integrity": "sha512-88I+D3TeKItrw+Y/2ud4Tw0+3CxQ2kLgu3QvrogZ0OfkmX/DEppehus7L3TS2Q4lpB+hYyxhkQiYPJ6Mf5/dPg==", "cpu": [ "arm" ], @@ -592,9 +559,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.8.tgz", - "integrity": "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.9.tgz", + "integrity": "sha512-3qyfWljSFHi9zH0KgtEPG4cBXHDFhwD8kwg6xLfHQ0IWuH9crp005GfoUUh/6w9/FWGBwEHg3lxK1iHRN1MFlA==", "cpu": [ "arm" ], @@ -606,9 +573,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.8.tgz", - "integrity": "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.9.tgz", + "integrity": "sha512-6TZjPHjKZUQKmVKMUowF3ewHxctrRR09eYyvT5eFv8w/fXarEra83A2mHTVJLA5xU91aCNOUnM+DWFMSbQ0Nxw==", "cpu": [ "arm64" ], @@ -620,9 +587,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.8.tgz", - "integrity": "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.9.tgz", + "integrity": "sha512-LD2fytxZJZ6xzOKnMbIpgzFOuIKlxVOpiMAXawsAZ2mHBPEYOnLRK5TTEsID6z4eM23DuO88X0Tq1mErHMVq0A==", "cpu": [ "arm64" ], @@ -634,9 +601,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.8.tgz", - "integrity": "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.9.tgz", + "integrity": "sha512-dRAgTfDsn0TE0HI6cmo13hemKpVHOEyeciGtvlBTkpx/F65kTvShtY/EVyZEIfxFkV5JJTuQ9tP5HGBS0hfxIg==", "cpu": [ "loong64" ], @@ -648,9 +615,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.8.tgz", - "integrity": "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.9.tgz", + "integrity": "sha512-PHcNOAEhkoMSQtMf+rJofwisZqaU8iQ8EaSps58f5HYll9EAY5BSErCZ8qBDMVbq88h4UxaNPlbrKqfWP8RfJA==", "cpu": [ "ppc64" ], @@ -662,9 +629,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.8.tgz", - "integrity": "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.9.tgz", + "integrity": "sha512-Z2i0Uy5G96KBYKjeQFKbbsB54xFOL5/y1P5wNBsbXB8yE+At3oh0DVMjQVzCJRJSfReiB2tX8T6HUFZ2k8iaKg==", "cpu": [ "riscv64" ], @@ -676,9 +643,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.8.tgz", - "integrity": "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.9.tgz", + "integrity": "sha512-U+5SwTMoeYXoDzJX5dhDTxRltSrIax8KWwfaaYcynuJw8mT33W7oOgz0a+AaXtGuvhzTr2tVKh5UO8GVANTxyQ==", "cpu": [ "s390x" ], @@ -690,9 +657,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.8.tgz", - "integrity": "sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.9.tgz", + "integrity": "sha512-FwBHNSOjUTQLP4MG7y6rR6qbGw4MFeQnIBrMe161QGaQoBQLqSUEKlHIiVgF3g/mb3lxlxzJOpIBhaP+C+KP2A==", "cpu": [ "x64" ], @@ -704,9 +671,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.8.tgz", - "integrity": "sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.9.tgz", + "integrity": "sha512-cYRpV4650z2I3/s6+5/LONkjIz8MBeqrk+vPXV10ORBnshpn8S32bPqQ2Utv39jCiDcO2eJTuSlPXpnvmaIgRA==", "cpu": [ "x64" ], @@ -718,9 +685,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.8.tgz", - "integrity": "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.9.tgz", + "integrity": "sha512-z4mQK9dAN6byRA/vsSgQiPeuO63wdiDxZ9yg9iyX2QTzKuQM7T4xlBoeUP/J8uiFkqxkcWndWi+W7bXdPbt27Q==", "cpu": [ "arm64" ], @@ -732,9 +699,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.8.tgz", - "integrity": "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.9.tgz", + "integrity": "sha512-KB48mPtaoHy1AwDNkAJfHXvHp24H0ryZog28spEs0V48l3H1fr4i37tiyHsgKZJnCmvxsbATdZGBpbmxTE3a9w==", "cpu": [ "ia32" ], @@ -746,9 +713,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.8.tgz", - "integrity": "sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.9.tgz", + "integrity": "sha512-AyleYRPU7+rgkMWbEh71fQlrzRfeP6SyMnRf9XX4fCdDPAJumdSBqYEcWPMzVQ4ScAl7E4oFfK0GUVn77xSwbw==", "cpu": [ "x64" ], @@ -1398,9 +1365,9 @@ "license": "MIT" }, "node_modules/esbuild": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", - "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1408,34 +1375,32 @@ "esbuild": "bin/esbuild" }, "engines": { - "node": ">=18" + "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.24.2", - "@esbuild/android-arm": "0.24.2", - "@esbuild/android-arm64": "0.24.2", - "@esbuild/android-x64": "0.24.2", - "@esbuild/darwin-arm64": "0.24.2", - "@esbuild/darwin-x64": "0.24.2", - "@esbuild/freebsd-arm64": "0.24.2", - "@esbuild/freebsd-x64": "0.24.2", - "@esbuild/linux-arm": "0.24.2", - "@esbuild/linux-arm64": "0.24.2", - "@esbuild/linux-ia32": "0.24.2", - "@esbuild/linux-loong64": "0.24.2", - "@esbuild/linux-mips64el": "0.24.2", - "@esbuild/linux-ppc64": "0.24.2", - "@esbuild/linux-riscv64": "0.24.2", - "@esbuild/linux-s390x": "0.24.2", - "@esbuild/linux-x64": "0.24.2", - "@esbuild/netbsd-arm64": "0.24.2", - "@esbuild/netbsd-x64": "0.24.2", - "@esbuild/openbsd-arm64": "0.24.2", - "@esbuild/openbsd-x64": "0.24.2", - "@esbuild/sunos-x64": "0.24.2", - "@esbuild/win32-arm64": "0.24.2", - "@esbuild/win32-ia32": "0.24.2", - "@esbuild/win32-x64": "0.24.2" + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" } }, "node_modules/escalade": { @@ -1472,9 +1437,9 @@ } }, "node_modules/expect-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.1.0.tgz", - "integrity": "sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.0.tgz", + "integrity": "sha512-80F22aiJ3GLyVnS/B3HzgR6RelZVumzj9jkL0Rhz4h0xYbNW9PjlQz5h3J/SShErbXBc295vseR4/MIbVmUbeA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1614,9 +1579,9 @@ } }, "node_modules/happy-dom": { - "version": "17.1.8", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-17.1.8.tgz", - "integrity": "sha512-Yxbq/FG79z1rhAf/iB6YM8wO2JB/JDQBy99RiLSs+2siEAi5J05x9eW1nnASHZJbpldjJE2KuFLsLZ+AzX/IxA==", + "version": "17.1.9", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-17.1.9.tgz", + "integrity": "sha512-HL26ajjMVe/wr3xlzjF0sCPCiAKaZJcIRFZHmG4yKHRJp4YAkHPG5X6GfWxCeDTpOmuHhNiOyNKUoZjjnm0tjw==", "dev": true, "license": "MIT", "dependencies": { @@ -2212,9 +2177,9 @@ } }, "node_modules/rollup": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.8.tgz", - "integrity": "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==", + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.9.tgz", + "integrity": "sha512-nF5XYqWWp9hx/LrpC8sZvvvmq0TeTjQgaZHYmAgwysT9nh8sWnZhBnM8ZyVbbJFIQBLwHDNoMqsBZBbUo4U8sQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2228,25 +2193,25 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.34.8", - "@rollup/rollup-android-arm64": "4.34.8", - "@rollup/rollup-darwin-arm64": "4.34.8", - "@rollup/rollup-darwin-x64": "4.34.8", - "@rollup/rollup-freebsd-arm64": "4.34.8", - "@rollup/rollup-freebsd-x64": "4.34.8", - "@rollup/rollup-linux-arm-gnueabihf": "4.34.8", - "@rollup/rollup-linux-arm-musleabihf": "4.34.8", - "@rollup/rollup-linux-arm64-gnu": "4.34.8", - "@rollup/rollup-linux-arm64-musl": "4.34.8", - "@rollup/rollup-linux-loongarch64-gnu": "4.34.8", - "@rollup/rollup-linux-powerpc64le-gnu": "4.34.8", - "@rollup/rollup-linux-riscv64-gnu": "4.34.8", - "@rollup/rollup-linux-s390x-gnu": "4.34.8", - "@rollup/rollup-linux-x64-gnu": "4.34.8", - "@rollup/rollup-linux-x64-musl": "4.34.8", - "@rollup/rollup-win32-arm64-msvc": "4.34.8", - "@rollup/rollup-win32-ia32-msvc": "4.34.8", - "@rollup/rollup-win32-x64-msvc": "4.34.8", + "@rollup/rollup-android-arm-eabi": "4.34.9", + "@rollup/rollup-android-arm64": "4.34.9", + "@rollup/rollup-darwin-arm64": "4.34.9", + "@rollup/rollup-darwin-x64": "4.34.9", + "@rollup/rollup-freebsd-arm64": "4.34.9", + "@rollup/rollup-freebsd-x64": "4.34.9", + "@rollup/rollup-linux-arm-gnueabihf": "4.34.9", + "@rollup/rollup-linux-arm-musleabihf": "4.34.9", + "@rollup/rollup-linux-arm64-gnu": "4.34.9", + "@rollup/rollup-linux-arm64-musl": "4.34.9", + "@rollup/rollup-linux-loongarch64-gnu": "4.34.9", + "@rollup/rollup-linux-powerpc64le-gnu": "4.34.9", + "@rollup/rollup-linux-riscv64-gnu": "4.34.9", + "@rollup/rollup-linux-s390x-gnu": "4.34.9", + "@rollup/rollup-linux-x64-gnu": "4.34.9", + "@rollup/rollup-linux-x64-musl": "4.34.9", + "@rollup/rollup-win32-arm64-msvc": "4.34.9", + "@rollup/rollup-win32-ia32-msvc": "4.34.9", + "@rollup/rollup-win32-x64-msvc": "4.34.9", "fsevents": "~2.3.2" } }, @@ -2384,9 +2349,9 @@ "license": "MIT" }, "node_modules/std-env": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.0.tgz", - "integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.1.tgz", + "integrity": "sha512-vj5lIj3Mwf9D79hBkltk5qmkFI+biIKWS2IBxEyEU3AX1tUf7AoL8nSazCOiiqQsGKIq01SClsKEzweu34uwvA==", "dev": true, "license": "MIT" }, @@ -2627,9 +2592,9 @@ } }, "node_modules/typedoc-plugin-mdn-links": { - "version": "4.0.14", - "resolved": "https://registry.npmjs.org/typedoc-plugin-mdn-links/-/typedoc-plugin-mdn-links-4.0.14.tgz", - "integrity": "sha512-IDILzJr4OzNb5uAWWRMZYny80Q6jUQerAwskdYbNMwaHMRwsB3+y8oqYYE7/PyH+kJVvJnCC4G2wnAQ3CLdgqA==", + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/typedoc-plugin-mdn-links/-/typedoc-plugin-mdn-links-4.0.15.tgz", + "integrity": "sha512-ZdZLBVMSJzHckVJt902j5xIbujza5Z8l802sXd6G38bOZS6R+ZkjB6RmSdYdKlxiEle8Yqjxn4lZ2NZIeUe2lA==", "dev": true, "license": "MIT", "peerDependencies": { @@ -2663,9 +2628,9 @@ } }, "node_modules/typescript": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", - "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", + "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -2691,21 +2656,21 @@ "license": "MIT" }, "node_modules/vite": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.1.1.tgz", - "integrity": "sha512-4GgM54XrwRfrOp297aIYspIti66k56v16ZnqHvrIM7mG+HjDlAwS7p+Srr7J6fGvEdOJ5JcQ/D9T7HhtdXDTzA==", + "version": "5.4.14", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.14.tgz", + "integrity": "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.24.2", - "postcss": "^8.5.2", - "rollup": "^4.30.1" + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + "node": "^18.0.0 || >=20.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -2714,25 +2679,19 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "jiti": ">=1.21.0", + "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" + "terser": "^5.4.0" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, - "jiti": { - "optional": true - }, "less": { "optional": true }, @@ -2753,12 +2712,6 @@ }, "terser": { "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true } } }, diff --git a/v3/internal/runtime/desktop/@wailsio/runtime/package.json b/v3/internal/runtime/desktop/@wailsio/runtime/package.json index 9579c87fc..a101c702f 100644 --- a/v3/internal/runtime/desktop/@wailsio/runtime/package.json +++ b/v3/internal/runtime/desktop/@wailsio/runtime/package.json @@ -5,8 +5,14 @@ "description": "Wails Runtime", "types": "types/index.d.ts", "exports": { - "types": "./types/index.d.ts", - "import": "./dist/index.js" + ".": { + "types": "./types/index.d.ts", + "default": "./dist/index.js" + }, + "./plugins/*": { + "types": "./types/plugins/*.d.ts", + "default": "./dist/plugins/*.js" + } }, "repository": { "type": "git", @@ -50,6 +56,7 @@ "typedoc-plugin-mdn-links": "^4.0.13", "typedoc-plugin-missing-exports": "^3.1.0", "typescript": "^5.7.3", + "vite": "^5.2.0", "vitest": "^3.0.6" }, "overrides": { diff --git a/v3/internal/runtime/desktop/@wailsio/runtime/src/cancellable.ts b/v3/internal/runtime/desktop/@wailsio/runtime/src/cancellable.ts index 5a839e211..8c16b0cd7 100644 --- a/v3/internal/runtime/desktop/@wailsio/runtime/src/cancellable.ts +++ b/v3/internal/runtime/desktop/@wailsio/runtime/src/cancellable.ts @@ -92,7 +92,7 @@ interface CancellablePromiseState { // Private field names. const barrierSym = Symbol("barrier"); const cancelImplSym = Symbol("cancelImpl"); -const species = Symbol.species ?? Symbol("speciesPolyfill"); +const species: typeof Symbol.species = Symbol.species ?? Symbol("speciesPolyfill"); /** * A promise with an attached method for cancelling long-running operations (see {@link CancellablePromise#cancel}). @@ -841,7 +841,7 @@ function rejectorFor(promise: CancellablePromiseWithResolvers, state: Canc * Returns a promise that fulfills once all cancellation procedures for the given values have settled. */ function cancelAll(parent: CancellablePromise, values: any[], cause?: any): Promise { - const results = []; + const results: Promise[] = []; for (const value of values) { let cancel: CancellablePromiseCanceller; @@ -931,4 +931,4 @@ if (promiseWithResolvers && typeof promiseWithResolvers === 'function') { const promise = new Promise((res, rej) => { resolve = res; reject = rej; }); return { promise, resolve, reject }; } -} \ No newline at end of file +} diff --git a/v3/internal/runtime/desktop/@wailsio/runtime/src/create.ts b/v3/internal/runtime/desktop/@wailsio/runtime/src/create.ts index 72965eaa6..56de58add 100644 --- a/v3/internal/runtime/desktop/@wailsio/runtime/src/create.ts +++ b/v3/internal/runtime/desktop/@wailsio/runtime/src/create.ts @@ -104,3 +104,9 @@ export function Struct(createField: Record any>): return source; }; } + +/** + * Maps known event names to creation functions for their data types. + * Will be monkey-patched by the binding generator. + */ +export const Events: Record any> = {}; diff --git a/v3/internal/runtime/desktop/@wailsio/runtime/src/event_types.ts b/v3/internal/runtime/desktop/@wailsio/runtime/src/event_types.ts index 64be98d2e..2d7427fd8 100644 --- a/v3/internal/runtime/desktop/@wailsio/runtime/src/event_types.ts +++ b/v3/internal/runtime/desktop/@wailsio/runtime/src/event_types.ts @@ -57,7 +57,7 @@ export const Types = Object.freeze({ WindowUnMinimise: "windows:WindowUnMinimise", WindowMaximise: "windows:WindowMaximise", WindowUnMaximise: "windows:WindowUnMaximise", - }), + } as const), Mac: Object.freeze({ ApplicationDidBecomeActive: "mac:ApplicationDidBecomeActive", ApplicationDidChangeBackingProperties: "mac:ApplicationDidChangeBackingProperties", @@ -191,7 +191,7 @@ export const Types = Object.freeze({ WindowZoomIn: "mac:WindowZoomIn", WindowZoomOut: "mac:WindowZoomOut", WindowZoomReset: "mac:WindowZoomReset", - }), + } as const), Linux: Object.freeze({ ApplicationStartup: "linux:ApplicationStartup", SystemThemeChanged: "linux:SystemThemeChanged", @@ -201,7 +201,7 @@ export const Types = Object.freeze({ WindowFocusIn: "linux:WindowFocusIn", WindowFocusOut: "linux:WindowFocusOut", WindowLoadChanged: "linux:WindowLoadChanged", - }), + } as const), Common: Object.freeze({ ApplicationOpenedWithFile: "common:ApplicationOpenedWithFile", ApplicationStarted: "common:ApplicationStarted", @@ -230,5 +230,10 @@ export const Types = Object.freeze({ WindowZoomOut: "common:WindowZoomOut", WindowZoomReset: "common:WindowZoomReset", WindowDropZoneFilesDropped: "common:WindowDropZoneFilesDropped", - }), -}); + } as const), +} as const); + +export const Windows = Types.Windows; +export const Mac = Types.Mac; +export const Linux = Types.Linux; +export const Common = Types.Common; diff --git a/v3/internal/runtime/desktop/@wailsio/runtime/src/events.ts b/v3/internal/runtime/desktop/@wailsio/runtime/src/events.ts index 7ad7642b6..cf6a2581d 100644 --- a/v3/internal/runtime/desktop/@wailsio/runtime/src/events.ts +++ b/v3/internal/runtime/desktop/@wailsio/runtime/src/events.ts @@ -10,6 +10,8 @@ The electron alternative for Go import { newRuntimeCaller, objectNames } from "./runtime.js"; import { eventListeners, Listener, listenerOff } from "./listener.js"; +import { Events as Create } from "./create.js"; +import { Types } from "./event_types.js"; // Setup window._wails = window._wails || {}; @@ -18,26 +20,50 @@ window._wails.dispatchWailsEvent = dispatchWailsEvent; const call = newRuntimeCaller(objectNames.Events); const EmitMethod = 0; -export { Types } from "./event_types.js"; +export * from "./event_types.js"; + +/** + * A table of data types for all known events. + * Will be monkey-patched by the binding generator. + */ +export interface CustomEvents {} + +/** + * Either a known event name or an arbitrary string. + */ +export type WailsEventName = E | (string & {}); + +/** + * Union of all known system event names. + */ +type SystemEventName = { + [K in keyof (typeof Types)]: (typeof Types)[K][keyof ((typeof Types)[K])] +} extends (infer M) ? M[keyof M] : never; + +/** + * The data type associated to a given event. + */ +export type WailsEventData = + E extends keyof CustomEvents ? CustomEvents[E] : (E extends SystemEventName ? void : any); /** * The type of handlers for a given event. */ -export type Callback = (ev: WailsEvent) => void; +export type WailsEventCallback = (ev: WailsEvent) => void; /** * Represents a system event or a custom event emitted through wails-provided facilities. */ -export class WailsEvent { +export class WailsEvent { /** * The name of the event. */ - name: string; + name: E; /** * Optional data associated with the emitted event. */ - data: any; + data: WailsEventData; /** * Name of the originating window. Omitted for application events. @@ -45,9 +71,11 @@ export class WailsEvent { */ sender?: string; - constructor(name: string, data: any = null) { + constructor(name: E, data: WailsEventData); + constructor(name: WailsEventData extends null | void ? E : never) + constructor(name: E, data?: any) { this.name = name; - this.data = data; + this.data = data ?? null; } } @@ -57,7 +85,10 @@ function dispatchWailsEvent(event: any) { return; } - let wailsEvent = new WailsEvent(event.name, event.data); + let wailsEvent = new WailsEvent( + event.name, + (event.name in Create) ? Create[event.name](event.data) : event.data + ); if ('sender' in event) { wailsEvent.sender = event.sender; } @@ -78,7 +109,7 @@ function dispatchWailsEvent(event: any) { * @param maxCallbacks - The maximum number of times the callback can be called for the event. Once the maximum number is reached, the callback will no longer be called. * @returns A function that, when called, will unregister the callback from the event. */ -export function OnMultiple(eventName: string, callback: Callback, maxCallbacks: number) { +export function OnMultiple(eventName: E, callback: WailsEventCallback, maxCallbacks: number) { let listeners = eventListeners.get(eventName) || []; const thisListener = new Listener(eventName, callback, maxCallbacks); listeners.push(thisListener); @@ -93,7 +124,7 @@ export function OnMultiple(eventName: string, callback: Callback, maxCallbacks: * @param callback - The callback function to be called when the event is triggered. * @returns A function that, when called, will unregister the callback from the event. */ -export function On(eventName: string, callback: Callback): () => void { +export function On(eventName: E, callback: WailsEventCallback): () => void { return OnMultiple(eventName, callback, -1); } @@ -104,7 +135,7 @@ export function On(eventName: string, callback: Callback): () => void { * @param callback - The callback function to be called when the event is triggered. * @returns A function that, when called, will unregister the callback from the event. */ -export function Once(eventName: string, callback: Callback): () => void { +export function Once(eventName: E, callback: WailsEventCallback): () => void { return OnMultiple(eventName, callback, 1); } @@ -113,7 +144,7 @@ export function Once(eventName: string, callback: Callback): () => void { * * @param eventNames - The name of the events to remove listeners for. */ -export function Off(...eventNames: [string, ...string[]]): void { +export function Off(...eventNames: [WailsEventName, ...WailsEventName[]]): void { eventNames.forEach(eventName => eventListeners.delete(eventName)); } @@ -125,26 +156,15 @@ export function OffAll(): void { } /** - * Emits an event using the name and data. + * Emits an event. * - * @returns A promise that will be fulfilled once the event has been emitted. - * @param name - the name of the event to emit. - * @param data - the data to be sent with the event. + * @returns A promise that will be fulfilled once the event has been emitted. Resolves to true if the event was cancelled. + * @param name - The name of the event to emit + * @param data - The data that will be sent with the event */ -export function Emit(name: string, data?: any): Promise { - let eventName: string; - let eventData: any; - - if (typeof name === 'object' && name !== null && 'name' in name && 'data' in name) { - // If name is an object with a name property, use it directly - eventName = name['name']; - eventData = name['data']; - } else { - // Otherwise use the standard parameters - eventName = name as string; - eventData = data; - } - - return call(EmitMethod, { name: eventName, data: eventData }); +export function Emit(name: E, data: WailsEventData): Promise +export function Emit(name: WailsEventData extends null | void ? E : never): Promise +export function Emit(name: WailsEventData, data?: any): Promise { + return call(EmitMethod, new WailsEvent(name, data)) } diff --git a/v3/internal/runtime/desktop/@wailsio/runtime/src/index.ts b/v3/internal/runtime/desktop/@wailsio/runtime/src/index.ts index ed0970839..b4ab67fac 100644 --- a/v3/internal/runtime/desktop/@wailsio/runtime/src/index.ts +++ b/v3/internal/runtime/desktop/@wailsio/runtime/src/index.ts @@ -46,7 +46,6 @@ export { * An internal utility consumed by the binding generator. * * @ignore - * @internal */ export { Create }; diff --git a/v3/internal/runtime/desktop/@wailsio/runtime/src/plugins/vite.ts b/v3/internal/runtime/desktop/@wailsio/runtime/src/plugins/vite.ts new file mode 100644 index 000000000..b661dce82 --- /dev/null +++ b/v3/internal/runtime/desktop/@wailsio/runtime/src/plugins/vite.ts @@ -0,0 +1,76 @@ +import type {Plugin} from 'vite'; + +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ + +const TYPED_EVENTS_MODULE = "\0wailsio_runtime_events_typed"; + +/** + * A plugin that extends the wails runtime with locally generated code + * to provide support for typed custom events. + * With the plugin installed, vite will fail to build the project + * unless wails bindings have been generated first. + * + * @param {string} [bindingsRoot] - The root import path for generated bindings + */ +export default function WailsTypedEvents(bindingsRoot: string): Plugin { + let bindingsId: string, + runtimeId: string, + eventsId: string; + + return { + name: "wails-typed-events", + async buildStart() { + const bindingsPath = `${bindingsRoot}/github.com/wailsapp/wails/v3/internal/eventcreate`; + let resolution = await this.resolve(bindingsPath); + if (!resolution || resolution.external) { + this.error(`Event bindings module not found at import specifier '${bindingsPath}'. Please verify that the wails tool is up to date and the binding generator runs successfully. If you moved the bindings to a custom location, ensure you supplied the correct root path as the first argument to \`wailsTypedEventsPlugin\``); + return; + } + bindingsId = resolution.id; + + resolution = await this.resolve("@wailsio/runtime"); + if (!resolution || resolution.external) { return; } + runtimeId = resolution.id; + + resolution = await this.resolve("./events.js", runtimeId); + if (!resolution || resolution.external) { + this.error("Could not resolve events module within @wailsio/runtime package. Please verify that the module is correctly installed and up to date."); + return; + } + + eventsId = resolution.id; + }, + resolveId: { + order: 'pre', + handler(id, importer) { + if ( + bindingsId !== null + && runtimeId !== null + && eventsId !== null + && importer === runtimeId + && id === "./events.js" + ) { + return TYPED_EVENTS_MODULE; + } + return undefined; + } + }, + load(id) { + if (id === TYPED_EVENTS_MODULE) { + return ( + `import ${JSON.stringify(bindingsId)};\n` + + `export * from ${JSON.stringify(eventsId)};` + ); + } + return undefined; + } + } +} diff --git a/v3/internal/runtime/desktop/@wailsio/runtime/tsconfig.json b/v3/internal/runtime/desktop/@wailsio/runtime/tsconfig.json index 1175a4af4..75c3db8e4 100644 --- a/v3/internal/runtime/desktop/@wailsio/runtime/tsconfig.json +++ b/v3/internal/runtime/desktop/@wailsio/runtime/tsconfig.json @@ -1,5 +1,5 @@ { - "include": ["./src/**/*"], + "include": ["src"], "exclude": ["./src/**/*.test.*"], "compilerOptions": { "composite": true, @@ -19,6 +19,7 @@ "isolatedModules": true, "verbatimModuleSyntax": true, "stripInternal": true, + "skipLibCheck": true, "lib": [ "DOM", @@ -33,4 +34,4 @@ "noImplicitReturns": true, "noFallthroughCasesInSwitch": true } -} \ No newline at end of file +} diff --git a/v3/internal/templates/_common/go.mod.tmpl b/v3/internal/templates/_common/go.mod.tmpl index bc6a656d1..f33ac683a 100644 --- a/v3/internal/templates/_common/go.mod.tmpl +++ b/v3/internal/templates/_common/go.mod.tmpl @@ -1,4 +1,4 @@ -module changeme +module {{.ModulePath}} go 1.24 diff --git a/v3/internal/templates/_common/main.go.tmpl b/v3/internal/templates/_common/main.go.tmpl index be9310930..2e81bf2fb 100644 --- a/v3/internal/templates/_common/main.go.tmpl +++ b/v3/internal/templates/_common/main.go.tmpl @@ -17,6 +17,13 @@ import ( //go:embed all:frontend/dist var assets embed.FS +func init() { + // Register a custom event whose associated data type is string. + // This is not required, but the binding generator will pick up registered events + // and provide a strongly typed JS/TS API for them. + application.RegisterEvent[string]("time") +} + // main function serves as the application's entry point. It initializes the application, creates a window, // and starts a goroutine that emits a time-based event every second. It subsequently runs the application and // logs any error that might occur. diff --git a/v3/internal/templates/vanilla/frontend/main.js b/v3/internal/templates/base/frontend/main.js.tmpl similarity index 89% rename from v3/internal/templates/vanilla/frontend/main.js rename to v3/internal/templates/base/frontend/main.js.tmpl index c24b3b1ef..98b43c825 100644 --- a/v3/internal/templates/vanilla/frontend/main.js +++ b/v3/internal/templates/base/frontend/main.js.tmpl @@ -1,5 +1,5 @@ -import {GreetService} from "./bindings/changeme"; import {Events} from "@wailsio/runtime"; +import {GreetService} from "./bindings/{{js .ModulePath}}"; const resultElement = document.getElementById('result'); const timeElement = document.getElementById('time'); diff --git a/v3/internal/templates/lit-ts/frontend/src/my-element.ts b/v3/internal/templates/lit-ts/frontend/src/my-element.ts.tmpl similarity index 98% rename from v3/internal/templates/lit-ts/frontend/src/my-element.ts rename to v3/internal/templates/lit-ts/frontend/src/my-element.ts.tmpl index 437b74cb8..2d2225e7d 100644 --- a/v3/internal/templates/lit-ts/frontend/src/my-element.ts +++ b/v3/internal/templates/lit-ts/frontend/src/my-element.ts.tmpl @@ -1,7 +1,7 @@ import {css, html, LitElement} from 'lit' import {customElement, property} from 'lit/decorators.js' -import {GreetService} from '../bindings/changeme'; import {Events} from "@wailsio/runtime"; +import {GreetService} from '../bindings/{{js .ModulePath}}'; /** * An example element. diff --git a/v3/internal/templates/lit-ts/frontend/tsconfig.json b/v3/internal/templates/lit-ts/frontend/tsconfig.json index 12a8b4eb6..6badd7348 100644 --- a/v3/internal/templates/lit-ts/frontend/tsconfig.json +++ b/v3/internal/templates/lit-ts/frontend/tsconfig.json @@ -21,5 +21,5 @@ "noImplicitAny": false, "noFallthroughCasesInSwitch": true }, - "include": ["src"] + "include": ["src", "bindings"] } diff --git a/v3/internal/templates/lit-ts/frontend/vite.config.ts b/v3/internal/templates/lit-ts/frontend/vite.config.ts new file mode 100644 index 000000000..56f2d6a8a --- /dev/null +++ b/v3/internal/templates/lit-ts/frontend/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import wails from "@wailsio/runtime/plugins/vite"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [wails("./bindings")], +}); diff --git a/v3/internal/templates/lit/frontend/src/my-element.js b/v3/internal/templates/lit/frontend/src/my-element.js.tmpl similarity index 98% rename from v3/internal/templates/lit/frontend/src/my-element.js rename to v3/internal/templates/lit/frontend/src/my-element.js.tmpl index 5c617da3b..4cca13e06 100644 --- a/v3/internal/templates/lit/frontend/src/my-element.js +++ b/v3/internal/templates/lit/frontend/src/my-element.js.tmpl @@ -1,6 +1,6 @@ import {css, html, LitElement} from 'lit' -import {GreetService} from "../bindings/changeme"; import {Events} from "@wailsio/runtime"; +import {GreetService} from "../bindings/{{js .ModulePath}}"; export class MyElement extends LitElement { static properties = { diff --git a/v3/internal/templates/lit/frontend/src/vite-env.d.ts b/v3/internal/templates/lit/frontend/src/vite-env.d.ts new file mode 100644 index 000000000..11f02fe2a --- /dev/null +++ b/v3/internal/templates/lit/frontend/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/v3/internal/templates/lit/frontend/tsconfig.json b/v3/internal/templates/lit/frontend/tsconfig.json new file mode 100644 index 000000000..f103fe3a9 --- /dev/null +++ b/v3/internal/templates/lit/frontend/tsconfig.json @@ -0,0 +1,25 @@ +/** + * This file tells your IDE where the root of your JavaScript project is, and sets some + * options that it can use to provide autocompletion and other features. + */ +{ + "compilerOptions": { + "allowJs": true, + "moduleResolution": "bundler", + /** + * The target and module can be set to ESNext to allow writing modern JavaScript, + * and Vite will compile down to the level of "build.target" specified in the vite config file. + * Builds will error if you use a feature that cannot be compiled down to the target level. + */ + "target": "ESNext", + "module": "ESNext", + "resolveJsonModule": true, + /** + * Enable checkJs if you'd like type checking in `.js` files. + */ + "checkJs": false, + "strict": true, + "skipLibCheck": true, + }, + "include": ["src", "bindings"] +} diff --git a/v3/internal/templates/lit/frontend/vite.config.js b/v3/internal/templates/lit/frontend/vite.config.js new file mode 100644 index 000000000..56f2d6a8a --- /dev/null +++ b/v3/internal/templates/lit/frontend/vite.config.js @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import wails from "@wailsio/runtime/plugins/vite"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [wails("./bindings")], +}); diff --git a/v3/internal/templates/preact-ts/frontend/src/app.tsx b/v3/internal/templates/preact-ts/frontend/src/app.tsx.tmpl similarity index 96% rename from v3/internal/templates/preact-ts/frontend/src/app.tsx rename to v3/internal/templates/preact-ts/frontend/src/app.tsx.tmpl index 93fab58d3..f8e992d34 100644 --- a/v3/internal/templates/preact-ts/frontend/src/app.tsx +++ b/v3/internal/templates/preact-ts/frontend/src/app.tsx.tmpl @@ -1,6 +1,6 @@ import {useEffect, useState} from 'preact/hooks' -import {GreetService} from "../bindings/changeme"; import {Events} from "@wailsio/runtime"; +import {GreetService} from "../bindings/{{js .ModulePath}}"; export function App() { const [name, setName] = useState(''); diff --git a/v3/internal/templates/preact-ts/frontend/tsconfig.json b/v3/internal/templates/preact-ts/frontend/tsconfig.json index 58c0ca7a7..f109102b4 100644 --- a/v3/internal/templates/preact-ts/frontend/tsconfig.json +++ b/v3/internal/templates/preact-ts/frontend/tsconfig.json @@ -26,6 +26,5 @@ "noImplicitAny": false, "noFallthroughCasesInSwitch": true }, - "include": ["src"], - "references": [{ "path": "./tsconfig.node.json" }] + "include": ["src", "bindings"], } diff --git a/v3/internal/templates/preact-ts/frontend/tsconfig.node.json b/v3/internal/templates/preact-ts/frontend/tsconfig.node.json deleted file mode 100644 index 42872c59f..000000000 --- a/v3/internal/templates/preact-ts/frontend/tsconfig.node.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler", - "allowSyntheticDefaultImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/v3/internal/templates/preact-ts/frontend/vite.config.ts b/v3/internal/templates/preact-ts/frontend/vite.config.ts index 29b326faf..51b2dce5c 100644 --- a/v3/internal/templates/preact-ts/frontend/vite.config.ts +++ b/v3/internal/templates/preact-ts/frontend/vite.config.ts @@ -1,7 +1,8 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' +import { defineConfig } from "vite"; +import preact from "@preact/preset-vite"; +import wails from "@wailsio/runtime/plugins/vite"; // https://vitejs.dev/config/ export default defineConfig({ - plugins: [preact()], -}) + plugins: [preact(), wails("./bindings")], +}); diff --git a/v3/internal/templates/preact/frontend/src/app.jsx b/v3/internal/templates/preact/frontend/src/app.jsx.tmpl similarity index 96% rename from v3/internal/templates/preact/frontend/src/app.jsx rename to v3/internal/templates/preact/frontend/src/app.jsx.tmpl index c8c71f638..45102e3ef 100644 --- a/v3/internal/templates/preact/frontend/src/app.jsx +++ b/v3/internal/templates/preact/frontend/src/app.jsx.tmpl @@ -1,6 +1,6 @@ import { useState, useEffect } from 'preact/hooks' -import {GreetService} from "../bindings/changeme"; import {Events} from "@wailsio/runtime"; +import {GreetService} from "../bindings/{{js .ModulePath}}"; export function App() { const [name, setName] = useState(''); diff --git a/v3/internal/templates/preact/frontend/src/vite-env.d.ts b/v3/internal/templates/preact/frontend/src/vite-env.d.ts new file mode 100644 index 000000000..11f02fe2a --- /dev/null +++ b/v3/internal/templates/preact/frontend/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/v3/internal/templates/preact/frontend/tsconfig.json b/v3/internal/templates/preact/frontend/tsconfig.json new file mode 100644 index 000000000..2be606f10 --- /dev/null +++ b/v3/internal/templates/preact/frontend/tsconfig.json @@ -0,0 +1,25 @@ +/** + * This file tells your IDE where the root of your JavaScript project is, and sets some + * options that it can use to provide autocompletion and other features. + */ +{ + "compilerOptions": { + "allowJs": true, + "moduleResolution": "bundler", + /** + * The target and module can be set to ESNext to allow writing modern JavaScript, + * and Vite will compile down to the level of "build.target" specified in the vite config file. + * Builds will error if you use a feature that cannot be compiled down to the target level. + */ + "target": "ESNext", + "module": "ESNext", + "resolveJsonModule": true, + /** + * Enable checkJs if you'd like type checking in `.js(x)` files. + */ + "checkJs": false, + "strict": true, + "skipLibCheck": true, + }, + "include": ["src", "bindings"] +} diff --git a/v3/internal/templates/preact/frontend/vite.config.js b/v3/internal/templates/preact/frontend/vite.config.js index 29b326faf..51b2dce5c 100644 --- a/v3/internal/templates/preact/frontend/vite.config.js +++ b/v3/internal/templates/preact/frontend/vite.config.js @@ -1,7 +1,8 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' +import { defineConfig } from "vite"; +import preact from "@preact/preset-vite"; +import wails from "@wailsio/runtime/plugins/vite"; // https://vitejs.dev/config/ export default defineConfig({ - plugins: [preact()], -}) + plugins: [preact(), wails("./bindings")], +}); diff --git a/v3/internal/templates/qwik-ts/frontend/src/app.tsx b/v3/internal/templates/qwik-ts/frontend/src/app.tsx.tmpl similarity index 96% rename from v3/internal/templates/qwik-ts/frontend/src/app.tsx rename to v3/internal/templates/qwik-ts/frontend/src/app.tsx.tmpl index 3315315c2..e64bf4c09 100644 --- a/v3/internal/templates/qwik-ts/frontend/src/app.tsx +++ b/v3/internal/templates/qwik-ts/frontend/src/app.tsx.tmpl @@ -1,6 +1,6 @@ import { component$, useSignal, useVisibleTask$ } from '@builder.io/qwik' -import {GreetService} from "../bindings/changeme"; import {Events, WML} from "@wailsio/runtime"; +import {GreetService} from "../bindings/{{js .ModulePath}}"; export const App = component$(() => { const name = useSignal(''); diff --git a/v3/internal/templates/qwik-ts/frontend/src/vite-env.d.ts b/v3/internal/templates/qwik-ts/frontend/src/vite-env.d.ts new file mode 100644 index 000000000..11f02fe2a --- /dev/null +++ b/v3/internal/templates/qwik-ts/frontend/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/v3/internal/templates/qwik-ts/frontend/tsconfig.json b/v3/internal/templates/qwik-ts/frontend/tsconfig.json index 3e575f3cc..2c7f9d75e 100644 --- a/v3/internal/templates/qwik-ts/frontend/tsconfig.json +++ b/v3/internal/templates/qwik-ts/frontend/tsconfig.json @@ -22,6 +22,5 @@ "noImplicitAny": false, "noFallthroughCasesInSwitch": true }, - "include": ["src"], - "references": [{ "path": "./tsconfig.node.json" }] + "include": ["src", "bindings"], } diff --git a/v3/internal/templates/qwik-ts/frontend/tsconfig.node.json b/v3/internal/templates/qwik-ts/frontend/tsconfig.node.json deleted file mode 100644 index 42872c59f..000000000 --- a/v3/internal/templates/qwik-ts/frontend/tsconfig.node.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler", - "allowSyntheticDefaultImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/v3/internal/templates/qwik-ts/frontend/vite.config.js b/v3/internal/templates/qwik-ts/frontend/vite.config.js deleted file mode 100644 index cabd66b01..000000000 --- a/v3/internal/templates/qwik-ts/frontend/vite.config.js +++ /dev/null @@ -1,11 +0,0 @@ -import { defineConfig } from 'vite' -import { qwikVite } from '@builder.io/qwik/optimizer' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [ - qwikVite({ - csr: true, - }), - ], -}) diff --git a/v3/internal/templates/qwik-ts/frontend/vite.config.ts b/v3/internal/templates/qwik-ts/frontend/vite.config.ts new file mode 100644 index 000000000..3ea402c7b --- /dev/null +++ b/v3/internal/templates/qwik-ts/frontend/vite.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from "vite"; +import { qwikVite } from "@builder.io/qwik/optimizer"; +import wails from "@wailsio/runtime/plugins/vite"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + qwikVite({ + csr: true, + }), + wails("./bindings"), + ], +}); diff --git a/v3/internal/templates/qwik/frontend/src/app.jsx b/v3/internal/templates/qwik/frontend/src/app.jsx.tmpl similarity index 96% rename from v3/internal/templates/qwik/frontend/src/app.jsx rename to v3/internal/templates/qwik/frontend/src/app.jsx.tmpl index 52dcda7b3..bd56c0464 100644 --- a/v3/internal/templates/qwik/frontend/src/app.jsx +++ b/v3/internal/templates/qwik/frontend/src/app.jsx.tmpl @@ -1,6 +1,6 @@ import { component$, useSignal, useVisibleTask$ } from '@builder.io/qwik' -import {GreetService} from "../bindings/changeme"; import {Events, WML} from "@wailsio/runtime"; +import {GreetService} from "../bindings/{{js .ModulePath}}"; export const App = component$(() => { const name = useSignal(''); diff --git a/v3/internal/templates/qwik/frontend/src/main.jsx b/v3/internal/templates/qwik/frontend/src/main.jsx index 779d53be1..93884c8df 100644 --- a/v3/internal/templates/qwik/frontend/src/main.jsx +++ b/v3/internal/templates/qwik/frontend/src/main.jsx @@ -1,6 +1,6 @@ import '@builder.io/qwik/qwikloader.js' import { render } from '@builder.io/qwik' -import { App } from './app.jsx' +import { App } from './app.jsx.tmpl' render(document.getElementById('app'), ) diff --git a/v3/internal/templates/qwik/frontend/src/vite-env.d.ts b/v3/internal/templates/qwik/frontend/src/vite-env.d.ts new file mode 100644 index 000000000..11f02fe2a --- /dev/null +++ b/v3/internal/templates/qwik/frontend/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/v3/internal/templates/qwik/frontend/tsconfig.json b/v3/internal/templates/qwik/frontend/tsconfig.json new file mode 100644 index 000000000..2be606f10 --- /dev/null +++ b/v3/internal/templates/qwik/frontend/tsconfig.json @@ -0,0 +1,25 @@ +/** + * This file tells your IDE where the root of your JavaScript project is, and sets some + * options that it can use to provide autocompletion and other features. + */ +{ + "compilerOptions": { + "allowJs": true, + "moduleResolution": "bundler", + /** + * The target and module can be set to ESNext to allow writing modern JavaScript, + * and Vite will compile down to the level of "build.target" specified in the vite config file. + * Builds will error if you use a feature that cannot be compiled down to the target level. + */ + "target": "ESNext", + "module": "ESNext", + "resolveJsonModule": true, + /** + * Enable checkJs if you'd like type checking in `.js(x)` files. + */ + "checkJs": false, + "strict": true, + "skipLibCheck": true, + }, + "include": ["src", "bindings"] +} diff --git a/v3/internal/templates/qwik/frontend/vite.config.js b/v3/internal/templates/qwik/frontend/vite.config.js index cabd66b01..3ea402c7b 100644 --- a/v3/internal/templates/qwik/frontend/vite.config.js +++ b/v3/internal/templates/qwik/frontend/vite.config.js @@ -1,5 +1,6 @@ -import { defineConfig } from 'vite' -import { qwikVite } from '@builder.io/qwik/optimizer' +import { defineConfig } from "vite"; +import { qwikVite } from "@builder.io/qwik/optimizer"; +import wails from "@wailsio/runtime/plugins/vite"; // https://vitejs.dev/config/ export default defineConfig({ @@ -7,5 +8,6 @@ export default defineConfig({ qwikVite({ csr: true, }), + wails("./bindings"), ], -}) +}); diff --git a/v3/internal/templates/react-swc-ts/frontend/src/App.tsx b/v3/internal/templates/react-swc-ts/frontend/src/App.tsx.tmpl similarity index 96% rename from v3/internal/templates/react-swc-ts/frontend/src/App.tsx rename to v3/internal/templates/react-swc-ts/frontend/src/App.tsx.tmpl index 5706ca1c4..29c9f2440 100644 --- a/v3/internal/templates/react-swc-ts/frontend/src/App.tsx +++ b/v3/internal/templates/react-swc-ts/frontend/src/App.tsx.tmpl @@ -1,6 +1,6 @@ import { useState, useEffect } from 'react' -import {GreetService} from "../bindings/changeme"; import {Events, WML} from "@wailsio/runtime"; +import {GreetService} from "../bindings/{{js .ModulePath}}"; function App() { const [name, setName] = useState(''); diff --git a/v3/internal/templates/react-swc-ts/frontend/tsconfig.json b/v3/internal/templates/react-swc-ts/frontend/tsconfig.json index 7dbf437aa..ae81ea6d5 100644 --- a/v3/internal/templates/react-swc-ts/frontend/tsconfig.json +++ b/v3/internal/templates/react-swc-ts/frontend/tsconfig.json @@ -21,6 +21,5 @@ "noImplicitAny": false, "noFallthroughCasesInSwitch": true }, - "include": ["src"], - "references": [{ "path": "./tsconfig.node.json" }] + "include": ["src", "bindings"], } diff --git a/v3/internal/templates/react-swc-ts/frontend/tsconfig.node.json b/v3/internal/templates/react-swc-ts/frontend/tsconfig.node.json deleted file mode 100644 index 42872c59f..000000000 --- a/v3/internal/templates/react-swc-ts/frontend/tsconfig.node.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler", - "allowSyntheticDefaultImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/v3/internal/templates/react-swc-ts/frontend/vite.config.ts b/v3/internal/templates/react-swc-ts/frontend/vite.config.ts index 861b04b35..cd3b2c1c4 100644 --- a/v3/internal/templates/react-swc-ts/frontend/vite.config.ts +++ b/v3/internal/templates/react-swc-ts/frontend/vite.config.ts @@ -1,7 +1,8 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react-swc' +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react-swc"; +import wails from "@wailsio/runtime/plugins/vite"; // https://vitejs.dev/config/ export default defineConfig({ - plugins: [react()], -}) + plugins: [react(), wails("./bindings")], +}); diff --git a/v3/internal/templates/react/frontend/src/App.jsx b/v3/internal/templates/react-swc/frontend/src/App.jsx.tmpl similarity index 96% rename from v3/internal/templates/react/frontend/src/App.jsx rename to v3/internal/templates/react-swc/frontend/src/App.jsx.tmpl index 52db24562..87395733d 100644 --- a/v3/internal/templates/react/frontend/src/App.jsx +++ b/v3/internal/templates/react-swc/frontend/src/App.jsx.tmpl @@ -1,6 +1,6 @@ import { useState, useEffect } from 'react' -import {GreetService} from "../bindings/changeme"; import {Events, WML} from "@wailsio/runtime"; +import {GreetService} from "../bindings/{{js .ModulePath}}"; function App() { const [name, setName] = useState(''); diff --git a/v3/internal/templates/react-swc/frontend/src/vite-env.d.ts b/v3/internal/templates/react-swc/frontend/src/vite-env.d.ts new file mode 100644 index 000000000..11f02fe2a --- /dev/null +++ b/v3/internal/templates/react-swc/frontend/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/v3/internal/templates/react-swc/frontend/tsconfig.json b/v3/internal/templates/react-swc/frontend/tsconfig.json new file mode 100644 index 000000000..2be606f10 --- /dev/null +++ b/v3/internal/templates/react-swc/frontend/tsconfig.json @@ -0,0 +1,25 @@ +/** + * This file tells your IDE where the root of your JavaScript project is, and sets some + * options that it can use to provide autocompletion and other features. + */ +{ + "compilerOptions": { + "allowJs": true, + "moduleResolution": "bundler", + /** + * The target and module can be set to ESNext to allow writing modern JavaScript, + * and Vite will compile down to the level of "build.target" specified in the vite config file. + * Builds will error if you use a feature that cannot be compiled down to the target level. + */ + "target": "ESNext", + "module": "ESNext", + "resolveJsonModule": true, + /** + * Enable checkJs if you'd like type checking in `.js(x)` files. + */ + "checkJs": false, + "strict": true, + "skipLibCheck": true, + }, + "include": ["src", "bindings"] +} diff --git a/v3/internal/templates/react-swc/frontend/vite.config.js b/v3/internal/templates/react-swc/frontend/vite.config.js index 861b04b35..cd3b2c1c4 100644 --- a/v3/internal/templates/react-swc/frontend/vite.config.js +++ b/v3/internal/templates/react-swc/frontend/vite.config.js @@ -1,7 +1,8 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react-swc' +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react-swc"; +import wails from "@wailsio/runtime/plugins/vite"; // https://vitejs.dev/config/ export default defineConfig({ - plugins: [react()], -}) + plugins: [react(), wails("./bindings")], +}); diff --git a/v3/internal/templates/react-ts/frontend/src/App.tsx b/v3/internal/templates/react-ts/frontend/src/App.tsx.tmpl similarity index 96% rename from v3/internal/templates/react-ts/frontend/src/App.tsx rename to v3/internal/templates/react-ts/frontend/src/App.tsx.tmpl index edc81f820..f6185f2a8 100644 --- a/v3/internal/templates/react-ts/frontend/src/App.tsx +++ b/v3/internal/templates/react-ts/frontend/src/App.tsx.tmpl @@ -1,6 +1,6 @@ import { useState, useEffect } from 'react' -import {GreetService} from "../bindings/changeme"; import {Events, WML} from "@wailsio/runtime"; +import {GreetService} from "../bindings/{{js .ModulePath}}"; function App() { const [name, setName] = useState(''); diff --git a/v3/internal/templates/react-ts/frontend/tsconfig.json b/v3/internal/templates/react-ts/frontend/tsconfig.json index 7dbf437aa..ae81ea6d5 100644 --- a/v3/internal/templates/react-ts/frontend/tsconfig.json +++ b/v3/internal/templates/react-ts/frontend/tsconfig.json @@ -21,6 +21,5 @@ "noImplicitAny": false, "noFallthroughCasesInSwitch": true }, - "include": ["src"], - "references": [{ "path": "./tsconfig.node.json" }] + "include": ["src", "bindings"], } diff --git a/v3/internal/templates/react-ts/frontend/tsconfig.node.json b/v3/internal/templates/react-ts/frontend/tsconfig.node.json deleted file mode 100644 index 42872c59f..000000000 --- a/v3/internal/templates/react-ts/frontend/tsconfig.node.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler", - "allowSyntheticDefaultImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/v3/internal/templates/react-ts/frontend/vite.config.ts b/v3/internal/templates/react-ts/frontend/vite.config.ts index 5a33944a9..a642bc024 100644 --- a/v3/internal/templates/react-ts/frontend/vite.config.ts +++ b/v3/internal/templates/react-ts/frontend/vite.config.ts @@ -1,7 +1,8 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; +import wails from "@wailsio/runtime/plugins/vite"; // https://vitejs.dev/config/ export default defineConfig({ - plugins: [react()], -}) + plugins: [react(), wails("./bindings")], +}); diff --git a/v3/internal/templates/react-swc/frontend/src/App.jsx b/v3/internal/templates/react/frontend/src/App.jsx.tmpl similarity index 96% rename from v3/internal/templates/react-swc/frontend/src/App.jsx rename to v3/internal/templates/react/frontend/src/App.jsx.tmpl index 52db24562..87395733d 100644 --- a/v3/internal/templates/react-swc/frontend/src/App.jsx +++ b/v3/internal/templates/react/frontend/src/App.jsx.tmpl @@ -1,6 +1,6 @@ import { useState, useEffect } from 'react' -import {GreetService} from "../bindings/changeme"; import {Events, WML} from "@wailsio/runtime"; +import {GreetService} from "../bindings/{{js .ModulePath}}"; function App() { const [name, setName] = useState(''); diff --git a/v3/internal/templates/react/frontend/src/vite-env.d.ts b/v3/internal/templates/react/frontend/src/vite-env.d.ts new file mode 100644 index 000000000..11f02fe2a --- /dev/null +++ b/v3/internal/templates/react/frontend/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/v3/internal/templates/react/frontend/tsconfig.json b/v3/internal/templates/react/frontend/tsconfig.json new file mode 100644 index 000000000..2be606f10 --- /dev/null +++ b/v3/internal/templates/react/frontend/tsconfig.json @@ -0,0 +1,25 @@ +/** + * This file tells your IDE where the root of your JavaScript project is, and sets some + * options that it can use to provide autocompletion and other features. + */ +{ + "compilerOptions": { + "allowJs": true, + "moduleResolution": "bundler", + /** + * The target and module can be set to ESNext to allow writing modern JavaScript, + * and Vite will compile down to the level of "build.target" specified in the vite config file. + * Builds will error if you use a feature that cannot be compiled down to the target level. + */ + "target": "ESNext", + "module": "ESNext", + "resolveJsonModule": true, + /** + * Enable checkJs if you'd like type checking in `.js(x)` files. + */ + "checkJs": false, + "strict": true, + "skipLibCheck": true, + }, + "include": ["src", "bindings"] +} diff --git a/v3/internal/templates/react/frontend/vite.config.js b/v3/internal/templates/react/frontend/vite.config.js index 5a33944a9..a642bc024 100644 --- a/v3/internal/templates/react/frontend/vite.config.js +++ b/v3/internal/templates/react/frontend/vite.config.js @@ -1,7 +1,8 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; +import wails from "@wailsio/runtime/plugins/vite"; // https://vitejs.dev/config/ export default defineConfig({ - plugins: [react()], -}) + plugins: [react(), wails("./bindings")], +}); diff --git a/v3/internal/templates/solid-ts/frontend/src/App.tsx b/v3/internal/templates/solid-ts/frontend/src/App.tsx.tmpl similarity index 96% rename from v3/internal/templates/solid-ts/frontend/src/App.tsx rename to v3/internal/templates/solid-ts/frontend/src/App.tsx.tmpl index 5027e8c1d..22f59f270 100644 --- a/v3/internal/templates/solid-ts/frontend/src/App.tsx +++ b/v3/internal/templates/solid-ts/frontend/src/App.tsx.tmpl @@ -1,6 +1,6 @@ import { createSignal, onMount } from 'solid-js' -import {GreetService} from "../bindings/changeme"; import {Events} from "@wailsio/runtime"; +import {GreetService} from "../bindings/{{js .ModulePath}}"; function App() { const [name, setName] = createSignal(''); diff --git a/v3/internal/templates/solid-ts/frontend/src/vite-env.d.ts b/v3/internal/templates/solid-ts/frontend/src/vite-env.d.ts new file mode 100644 index 000000000..11f02fe2a --- /dev/null +++ b/v3/internal/templates/solid-ts/frontend/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/v3/internal/templates/solid-ts/frontend/tsconfig.json b/v3/internal/templates/solid-ts/frontend/tsconfig.json index 7fa3d5d20..89492db4a 100644 --- a/v3/internal/templates/solid-ts/frontend/tsconfig.json +++ b/v3/internal/templates/solid-ts/frontend/tsconfig.json @@ -22,6 +22,5 @@ "noImplicitAny": false, "noFallthroughCasesInSwitch": true }, - "include": ["src"], - "references": [{ "path": "./tsconfig.node.json" }] + "include": ["src", "bindings"], } diff --git a/v3/internal/templates/solid-ts/frontend/tsconfig.node.json b/v3/internal/templates/solid-ts/frontend/tsconfig.node.json deleted file mode 100644 index 42872c59f..000000000 --- a/v3/internal/templates/solid-ts/frontend/tsconfig.node.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler", - "allowSyntheticDefaultImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/v3/internal/templates/solid-ts/frontend/vite.config.ts b/v3/internal/templates/solid-ts/frontend/vite.config.ts index 4095d9be5..9b9614f01 100644 --- a/v3/internal/templates/solid-ts/frontend/vite.config.ts +++ b/v3/internal/templates/solid-ts/frontend/vite.config.ts @@ -1,6 +1,7 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' +import { defineConfig } from "vite"; +import solid from "vite-plugin-solid"; +import wails from "@wailsio/runtime/plugins/vite"; export default defineConfig({ - plugins: [solid()], -}) + plugins: [solid(), wails("./bindings")], +}); diff --git a/v3/internal/templates/solid/frontend/src/App.jsx b/v3/internal/templates/solid/frontend/src/App.jsx.tmpl similarity index 96% rename from v3/internal/templates/solid/frontend/src/App.jsx rename to v3/internal/templates/solid/frontend/src/App.jsx.tmpl index 49a658928..d691909b3 100644 --- a/v3/internal/templates/solid/frontend/src/App.jsx +++ b/v3/internal/templates/solid/frontend/src/App.jsx.tmpl @@ -1,6 +1,6 @@ import { createSignal, onMount } from 'solid-js' -import {GreetService} from "../bindings/changeme"; import {Events} from "@wailsio/runtime"; +import {GreetService} from "../bindings/{{js .ModulePath}}"; function App() { const [name, setName] = createSignal(''); diff --git a/v3/internal/templates/solid/frontend/src/vite-env.d.ts b/v3/internal/templates/solid/frontend/src/vite-env.d.ts new file mode 100644 index 000000000..11f02fe2a --- /dev/null +++ b/v3/internal/templates/solid/frontend/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/v3/internal/templates/solid/frontend/tsconfig.json b/v3/internal/templates/solid/frontend/tsconfig.json new file mode 100644 index 000000000..2be606f10 --- /dev/null +++ b/v3/internal/templates/solid/frontend/tsconfig.json @@ -0,0 +1,25 @@ +/** + * This file tells your IDE where the root of your JavaScript project is, and sets some + * options that it can use to provide autocompletion and other features. + */ +{ + "compilerOptions": { + "allowJs": true, + "moduleResolution": "bundler", + /** + * The target and module can be set to ESNext to allow writing modern JavaScript, + * and Vite will compile down to the level of "build.target" specified in the vite config file. + * Builds will error if you use a feature that cannot be compiled down to the target level. + */ + "target": "ESNext", + "module": "ESNext", + "resolveJsonModule": true, + /** + * Enable checkJs if you'd like type checking in `.js(x)` files. + */ + "checkJs": false, + "strict": true, + "skipLibCheck": true, + }, + "include": ["src", "bindings"] +} diff --git a/v3/internal/templates/solid/frontend/vite.config.js b/v3/internal/templates/solid/frontend/vite.config.js index 4095d9be5..df7eac4c4 100644 --- a/v3/internal/templates/solid/frontend/vite.config.js +++ b/v3/internal/templates/solid/frontend/vite.config.js @@ -1,6 +1,8 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' +import { defineConfig } from "vite"; +import solid from "vite-plugin-solid"; +import wails from "@wailsio/runtime/plugins/vite"; +// https://vitejs.dev/config/ export default defineConfig({ - plugins: [solid()], -}) + plugins: [solid(), wails("./bindings")], +}); diff --git a/v3/internal/templates/svelte-ts/frontend/src/App.svelte b/v3/internal/templates/svelte-ts/frontend/src/App.svelte.tmpl similarity index 95% rename from v3/internal/templates/svelte-ts/frontend/src/App.svelte rename to v3/internal/templates/svelte-ts/frontend/src/App.svelte.tmpl index 2a73938b0..1a75f5968 100644 --- a/v3/internal/templates/svelte-ts/frontend/src/App.svelte +++ b/v3/internal/templates/svelte-ts/frontend/src/App.svelte.tmpl @@ -1,6 +1,6 @@ + diff --git a/v3/internal/templates/base/frontend/main.js b/v3/internal/templates/vanilla/frontend/src/main.js.tmpl similarity index 59% rename from v3/internal/templates/base/frontend/main.js rename to v3/internal/templates/vanilla/frontend/src/main.js.tmpl index c24b3b1ef..2b256789d 100644 --- a/v3/internal/templates/base/frontend/main.js +++ b/v3/internal/templates/vanilla/frontend/src/main.js.tmpl @@ -1,19 +1,19 @@ -import {GreetService} from "./bindings/changeme"; import {Events} from "@wailsio/runtime"; +import {GreetService} from "../bindings/{{js .ModulePath}}"; const resultElement = document.getElementById('result'); const timeElement = document.getElementById('time'); -window.doGreet = () => { +window.doGreet = async () => { let name = document.getElementById('name').value; if (!name) { name = 'anonymous'; } - GreetService.Greet(name).then((result) => { - resultElement.innerText = result; - }).catch((err) => { - console.log(err); - }); + try { + resultElement.innerText = await GreetService.Greet(name); + } catch (err) { + console.error(err); + } } Events.On('time', (time) => { diff --git a/v3/internal/templates/vanilla/frontend/tsconfig.json b/v3/internal/templates/vanilla/frontend/tsconfig.json new file mode 100644 index 000000000..f103fe3a9 --- /dev/null +++ b/v3/internal/templates/vanilla/frontend/tsconfig.json @@ -0,0 +1,25 @@ +/** + * This file tells your IDE where the root of your JavaScript project is, and sets some + * options that it can use to provide autocompletion and other features. + */ +{ + "compilerOptions": { + "allowJs": true, + "moduleResolution": "bundler", + /** + * The target and module can be set to ESNext to allow writing modern JavaScript, + * and Vite will compile down to the level of "build.target" specified in the vite config file. + * Builds will error if you use a feature that cannot be compiled down to the target level. + */ + "target": "ESNext", + "module": "ESNext", + "resolveJsonModule": true, + /** + * Enable checkJs if you'd like type checking in `.js` files. + */ + "checkJs": false, + "strict": true, + "skipLibCheck": true, + }, + "include": ["src", "bindings"] +} diff --git a/v3/internal/templates/vanilla/frontend/vite.config.js b/v3/internal/templates/vanilla/frontend/vite.config.js new file mode 100644 index 000000000..56f2d6a8a --- /dev/null +++ b/v3/internal/templates/vanilla/frontend/vite.config.js @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import wails from "@wailsio/runtime/plugins/vite"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [wails("./bindings")], +}); diff --git a/v3/internal/templates/vue-ts/frontend/src/components/HelloWorld.vue b/v3/internal/templates/vue-ts/frontend/src/components/HelloWorld.vue.tmpl similarity index 82% rename from v3/internal/templates/vue-ts/frontend/src/components/HelloWorld.vue rename to v3/internal/templates/vue-ts/frontend/src/components/HelloWorld.vue.tmpl index e73e33e23..77cbff595 100644 --- a/v3/internal/templates/vue-ts/frontend/src/components/HelloWorld.vue +++ b/v3/internal/templates/vue-ts/frontend/src/components/HelloWorld.vue.tmpl @@ -1,7 +1,7 @@ diff --git a/v3/internal/templates/vue-ts/frontend/tsconfig.json b/v3/internal/templates/vue-ts/frontend/tsconfig.json index 8cef1a67b..5e8658ed7 100644 --- a/v3/internal/templates/vue-ts/frontend/tsconfig.json +++ b/v3/internal/templates/vue-ts/frontend/tsconfig.json @@ -15,6 +15,5 @@ "skipLibCheck": true, "noEmit": true }, - "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], - "references": [{ "path": "./tsconfig.node.json" }] + "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "bindings"], } diff --git a/v3/internal/templates/vue-ts/frontend/tsconfig.node.json b/v3/internal/templates/vue-ts/frontend/tsconfig.node.json deleted file mode 100644 index 9d31e2aed..000000000 --- a/v3/internal/templates/vue-ts/frontend/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "module": "ESNext", - "moduleResolution": "Node", - "allowSyntheticDefaultImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/v3/internal/templates/vue-ts/frontend/vite.config.ts b/v3/internal/templates/vue-ts/frontend/vite.config.ts index 05c17402a..16127a822 100644 --- a/v3/internal/templates/vue-ts/frontend/vite.config.ts +++ b/v3/internal/templates/vue-ts/frontend/vite.config.ts @@ -1,7 +1,8 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' +import { defineConfig } from "vite"; +import vue from "@vitejs/plugin-vue"; +import wails from "@wailsio/runtime/plugins/vite"; // https://vitejs.dev/config/ export default defineConfig({ - plugins: [vue()], -}) + plugins: [vue(), wails("./bindings")], +}); diff --git a/v3/internal/templates/vue/frontend/src/components/HelloWorld.vue b/v3/internal/templates/vue/frontend/src/components/HelloWorld.vue.tmpl similarity index 81% rename from v3/internal/templates/vue/frontend/src/components/HelloWorld.vue rename to v3/internal/templates/vue/frontend/src/components/HelloWorld.vue.tmpl index 3c7c085c5..be91bd160 100644 --- a/v3/internal/templates/vue/frontend/src/components/HelloWorld.vue +++ b/v3/internal/templates/vue/frontend/src/components/HelloWorld.vue.tmpl @@ -1,7 +1,7 @@ diff --git a/v3/internal/templates/vue/frontend/src/vite-env.d.ts b/v3/internal/templates/vue/frontend/src/vite-env.d.ts new file mode 100644 index 000000000..11f02fe2a --- /dev/null +++ b/v3/internal/templates/vue/frontend/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/v3/internal/templates/vue/frontend/tsconfig.json b/v3/internal/templates/vue/frontend/tsconfig.json new file mode 100644 index 000000000..bd83d39fe --- /dev/null +++ b/v3/internal/templates/vue/frontend/tsconfig.json @@ -0,0 +1,25 @@ +/** + * This file tells your IDE where the root of your JavaScript project is, and sets some + * options that it can use to provide autocompletion and other features. + */ +{ + "compilerOptions": { + "allowJs": true, + "moduleResolution": "bundler", + /** + * The target and module can be set to ESNext to allow writing modern JavaScript, + * and Vite will compile down to the level of "build.target" specified in the vite config file. + * Builds will error if you use a feature that cannot be compiled down to the target level. + */ + "target": "ESNext", + "module": "ESNext", + "resolveJsonModule": true, + /** + * Enable checkJs if you'd like type checking in `.vue` and `.js` files. + */ + "checkJs": false, + "strict": true, + "skipLibCheck": true, + }, + "include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.jsx", "src/**/*.vue", "bindings"] +} diff --git a/v3/internal/templates/vue/frontend/vite.config.js b/v3/internal/templates/vue/frontend/vite.config.js index 05c17402a..16127a822 100644 --- a/v3/internal/templates/vue/frontend/vite.config.js +++ b/v3/internal/templates/vue/frontend/vite.config.js @@ -1,7 +1,8 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' +import { defineConfig } from "vite"; +import vue from "@vitejs/plugin-vue"; +import wails from "@wailsio/runtime/plugins/vite"; // https://vitejs.dev/config/ export default defineConfig({ - plugins: [vue()], -}) + plugins: [vue(), wails("./bindings")], +}); diff --git a/v3/pkg/application/application.go b/v3/pkg/application/application.go index f1e313a3d..022d69a6f 100644 --- a/v3/pkg/application/application.go +++ b/v3/pkg/application/application.go @@ -421,8 +421,6 @@ func (a *App) RegisterService(service Service) { a.options.Services = append(a.options.Services, service) } -// EmitEvent will emit an event - func (a *App) handleFatalError(err error) { a.handleError(&FatalError{err: err}) os.Exit(1) @@ -514,7 +512,7 @@ func (a *App) Run() error { a.starting = true a.runLock.Unlock() - // Ensure application context is canceled in case of failures. + // Ensure application context is cancelled in case of failures. defer a.cancel() // Call post-create hooks @@ -654,7 +652,7 @@ func (a *App) shutdownServices() { a.serviceShutdownLock.Lock() defer a.serviceShutdownLock.Unlock() - // Ensure app context is canceled first (duplicate calls don't hurt). + // Ensure app context is cancelled first (duplicate calls don't hurt). a.cancel() for len(a.options.Services) > 0 { diff --git a/v3/pkg/application/event_manager.go b/v3/pkg/application/event_manager.go index 1ee191e10..92dcbd0a0 100644 --- a/v3/pkg/application/event_manager.go +++ b/v3/pkg/application/event_manager.go @@ -19,17 +19,44 @@ func newEventManager(app *App) *EventManager { } } -// Emit emits a custom event -func (em *EventManager) Emit(name string, data ...any) { - em.app.customEventProcessor.Emit(&CustomEvent{ - Name: name, - Data: data, - }) +// Emit emits a custom event with the specified name and associated data. +// It returns a boolean indicating whether the event was cancelled by a hook. +// +// If no data argument is provided, Emit emits an event with nil data. +// When there is exactly one data argument, it will be used as the custom event's data field. +// When more than one argument is provided, the event's data field will be set to the argument slice. +// +// If the given event name is registered, Emit validates the data parameter +// against the expected data type. In case of a mismatch, Emit reports an error +// to the registered error handler for the application and cancels the event. +func (em *EventManager) Emit(name string, data ...any) bool { + event := &CustomEvent{Name: name} + + if len(data) == 1 { + event.Data = data[0] + } else if len(data) > 1 { + event.Data = data + } + + if err := em.app.customEventProcessor.Emit(event); err != nil { + globalApplication.handleError(err) + } + + return event.IsCancelled() } // EmitEvent emits a custom event object (internal use) -func (em *EventManager) EmitEvent(event *CustomEvent) { - em.app.customEventProcessor.Emit(event) +// It returns a boolean indicating whether the event was cancelled by a hook. +// +// If the given event name is registered, emitEvent validates the data parameter +// against the expected data type. In case of a mismatch, emitEvent reports an error +// to the registered error handler for the application and cancels the event. +func (em *EventManager) EmitEvent(event *CustomEvent) bool { + if err := em.app.customEventProcessor.Emit(event); err != nil { + globalApplication.handleError(err) + } + + return event.IsCancelled() } // On registers a listener for custom events diff --git a/v3/pkg/application/events.go b/v3/pkg/application/events.go index 973c3015c..2c5afc960 100644 --- a/v3/pkg/application/events.go +++ b/v3/pkg/application/events.go @@ -2,7 +2,10 @@ package application import ( "encoding/json" + "fmt" + "reflect" "sync" + "sync/atomic" "github.com/samber/lo" "github.com/wailsapp/wails/v3/pkg/events" @@ -11,8 +14,7 @@ import ( type ApplicationEvent struct { Id uint ctx *ApplicationEventContext - cancelled bool - lock sync.RWMutex + cancelled atomic.Bool } func (w *ApplicationEvent) Context() *ApplicationEventContext { @@ -27,15 +29,11 @@ func newApplicationEvent(id events.ApplicationEventType) *ApplicationEvent { } func (w *ApplicationEvent) Cancel() { - w.lock.Lock() - defer w.lock.Unlock() - w.cancelled = true + w.cancelled.Store(true) } func (w *ApplicationEvent) IsCancelled() bool { - w.lock.RLock() - defer w.lock.RUnlock() - return w.cancelled + return w.cancelled.Load() } var applicationEvents = make(chan *ApplicationEvent, 5) @@ -50,23 +48,22 @@ var windowEvents = make(chan *windowEvent, 5) var menuItemClicked = make(chan uint, 5) type CustomEvent struct { - Name string `json:"name"` - Data any `json:"data"` - Sender string `json:"sender"` // Name of the window sending the event, or "" if sent from application - cancelled bool - lock sync.RWMutex + Name string `json:"name"` + Data any `json:"data"` + + // Sender records the name of the window sending the event, + // or "" if sent from application. + Sender string `json:"sender,omitempty"` + + cancelled atomic.Bool } func (e *CustomEvent) Cancel() { - e.lock.Lock() - defer e.lock.Unlock() - e.cancelled = true + e.cancelled.Store(true) } func (e *CustomEvent) IsCancelled() bool { - e.lock.Lock() - defer e.lock.Unlock() - return e.cancelled + return e.cancelled.Load() } func (e *CustomEvent) ToJSON() string { @@ -131,10 +128,20 @@ func (e *EventProcessor) Once(eventName string, callback func(event *CustomEvent return e.registerListener(eventName, callback, 1) } -// Emit sends an event to all listeners -func (e *EventProcessor) Emit(thisEvent *CustomEvent) { +// Emit sends an event to all listeners. +// +// If the event is globally registered, it validates associated data +// against the expected data type. In case of mismatches, +// it cancels the event and returns an error. +func (e *EventProcessor) Emit(thisEvent *CustomEvent) error { if thisEvent == nil { - return + return nil + } + + // Validate data type; in case of mismatches cancel and report error. + if err := validateCustomEvent(thisEvent); err != nil { + thisEvent.Cancel() + return err } // If we have any hooks, run them first and check if the event was cancelled @@ -143,7 +150,7 @@ func (e *EventProcessor) Emit(thisEvent *CustomEvent) { for _, thisHook := range hooks { thisHook.callback(thisEvent) if thisEvent.IsCancelled() { - return + return nil } } } @@ -157,6 +164,8 @@ func (e *EventProcessor) Emit(thisEvent *CustomEvent) { defer handlePanic() e.dispatchEventToWindows(thisEvent) }() + + return nil } func (e *EventProcessor) Off(eventName string) { @@ -264,3 +273,93 @@ func (e *EventProcessor) dispatchEventToListeners(event *CustomEvent) { }) } } + +// Void will be translated by the binding generator to the TypeScript type 'void'. +// It can be used as an event data type to register events that must not have any associated data. +type Void interface { + sentinel() +} + +var registeredEvents sync.Map +var voidType = reflect.TypeFor[Void]() + +// RegisterEvent registers a custom event name and associated data type. +// Events may be registered at most once. +// Duplicate calls for the same event name trigger a panic. +// +// The binding generator emits typing information for all registered custom events. +// [App.EmitEvent] and [Window.EmitEvent] check the data type for registered events. +// Data types are matched exactly and no conversion is performed. +// +// It is recommended to call RegisterEvent directly, +// with constant arguments, and only from init functions. +// Indirect calls or instantiations are not discoverable by the binding generator. +func RegisterEvent[Data any](name string) { + if events.IsKnownEvent(name) { + panic(fmt.Errorf("'%s' is a known system event name", name)) + } + if typ, ok := registeredEvents.Load(name); ok { + panic(fmt.Errorf("event '%s' is already registered with data type %s", name, typ)) + } + + registeredEvents.Store(name, reflect.TypeFor[Data]()) + eventRegistered(name) +} + +func validateCustomEvent(event *CustomEvent) error { + r, ok := registeredEvents.Load(event.Name) + if !ok { + warnAboutUnregisteredEvent(event.Name) + return nil + } + + typ := r.(reflect.Type) + + if typ == voidType { + if event.Data == nil { + return nil + } + } else if typ.Kind() == reflect.Interface { + if reflect.TypeOf(event.Data).Implements(typ) { + return nil + } + } else { + if reflect.TypeOf(event.Data) == typ { + return nil + } + } + + return fmt.Errorf( + "data of type %s for event '%s' does not match registered data type %s", + reflect.TypeOf(event.Data), + event.Name, + typ, + ) +} + +func decodeEventData(name string, data []byte) (result any, err error) { + r, ok := registeredEvents.Load(name) + if !ok { + // Unregistered events unmarshal to any. + err = json.Unmarshal(data, &result) + return + } + + typ := r.(reflect.Type) + + if typ == voidType { + // When typ is voidType, perform a null check + err = json.Unmarshal(data, &result) + if err == nil && result != nil { + err = fmt.Errorf("non-null data for event '%s' does not match registered data type %s", name, typ) + } + } else { + value := reflect.New(typ.(reflect.Type)) + err = json.Unmarshal(data, value.Interface()) + if err == nil { + result = value.Elem().Interface() + } + } + + return +} diff --git a/v3/pkg/application/events_loose.go b/v3/pkg/application/events_loose.go new file mode 100644 index 000000000..f00715c51 --- /dev/null +++ b/v3/pkg/application/events_loose.go @@ -0,0 +1,7 @@ +//go:build production || !strictevents + +package application + +func eventRegistered(name string) {} + +func warnAboutUnregisteredEvent(name string) {} diff --git a/v3/pkg/application/events_strict.go b/v3/pkg/application/events_strict.go new file mode 100644 index 000000000..adc19dbd3 --- /dev/null +++ b/v3/pkg/application/events_strict.go @@ -0,0 +1,27 @@ +//go:build !production && strictevents + +package application + +import ( + "sync" +) + +var knownUnregisteredEvents sync.Map + +func eventRegistered(name string) { + knownUnregisteredEvents.Delete(name) +} + +func warnAboutUnregisteredEvent(name string) { + // Perform a load first to avoid thrashing the map with unnecessary swaps. + if _, known := knownUnregisteredEvents.Load(name); known { + return + } + + // Perform a swap to synchronize with concurrent emissions. + if _, known := knownUnregisteredEvents.Swap(name, true); known { + return + } + + globalApplication.warning("unregistered event name '%s'", name) +} diff --git a/v3/pkg/application/events_test.go b/v3/pkg/application/events_test.go index ee1c26b2f..c1e621d9c 100644 --- a/v3/pkg/application/events_test.go +++ b/v3/pkg/application/events_test.go @@ -36,7 +36,7 @@ func Test_EventsOn(t *testing.T) { counter++ wg.Done() }) - eventProcessor.Emit(&application.CustomEvent{ + _ = eventProcessor.Emit(&application.CustomEvent{ Name: "test", Data: "test payload", }) @@ -47,7 +47,7 @@ func Test_EventsOn(t *testing.T) { notifier.Reset() unregisterFn() counter = 0 - eventProcessor.Emit(&application.CustomEvent{ + _ = eventProcessor.Emit(&application.CustomEvent{ Name: "test", Data: "test payload", }) @@ -70,11 +70,11 @@ func Test_EventsOnce(t *testing.T) { counter++ wg.Done() }) - eventProcessor.Emit(&application.CustomEvent{ + _ = eventProcessor.Emit(&application.CustomEvent{ Name: "test", Data: "test payload", }) - eventProcessor.Emit(&application.CustomEvent{ + _ = eventProcessor.Emit(&application.CustomEvent{ Name: "test", Data: "test payload", }) @@ -85,7 +85,7 @@ func Test_EventsOnce(t *testing.T) { notifier.Reset() unregisterFn() counter = 0 - eventProcessor.Emit(&application.CustomEvent{ + _ = eventProcessor.Emit(&application.CustomEvent{ Name: "test", Data: "test payload", }) @@ -107,15 +107,15 @@ func Test_EventsOnMultiple(t *testing.T) { counter++ wg.Done() }, 2) - eventProcessor.Emit(&application.CustomEvent{ + _ = eventProcessor.Emit(&application.CustomEvent{ Name: "test", Data: "test payload", }) - eventProcessor.Emit(&application.CustomEvent{ + _ = eventProcessor.Emit(&application.CustomEvent{ Name: "test", Data: "test payload", }) - eventProcessor.Emit(&application.CustomEvent{ + _ = eventProcessor.Emit(&application.CustomEvent{ Name: "test", Data: "test payload", }) @@ -126,7 +126,7 @@ func Test_EventsOnMultiple(t *testing.T) { notifier.Reset() unregisterFn() counter = 0 - eventProcessor.Emit(&application.CustomEvent{ + _ = eventProcessor.Emit(&application.CustomEvent{ Name: "test", Data: "test payload", }) diff --git a/v3/pkg/application/messageprocessor_call.go b/v3/pkg/application/messageprocessor_call.go index dc25d375c..9712cc4b3 100644 --- a/v3/pkg/application/messageprocessor_call.go +++ b/v3/pkg/application/messageprocessor_call.go @@ -55,7 +55,7 @@ func (m *MessageProcessor) processCallCancelMethod(method int, rw http.ResponseW if cancel != nil { cancel() - m.Info("Binding call canceled:", "id", *callID) + m.Info("Binding call cancelled:", "id", *callID) } m.ok(rw) } diff --git a/v3/pkg/application/messageprocessor_events.go b/v3/pkg/application/messageprocessor_events.go index 93ab34064..e83214cb6 100644 --- a/v3/pkg/application/messageprocessor_events.go +++ b/v3/pkg/application/messageprocessor_events.go @@ -1,6 +1,7 @@ package application import ( + "encoding/json" "fmt" "net/http" @@ -19,20 +20,33 @@ func (m *MessageProcessor) processEventsMethod(method int, rw http.ResponseWrite switch method { case EventsEmit: var event CustomEvent - err := params.ToStruct(&event) + var options struct { + Name *string `json:"name"` + Data json.RawMessage `json:"data"` + } + + err := params.ToStruct(&options) if err != nil { m.httpError(rw, "Invalid events call:", fmt.Errorf("error parsing event: %w", err)) return } - if event.Name == "" { + if options.Name == nil { m.httpError(rw, "Invalid events call:", errors.New("missing event name")) return } + data, err := decodeEventData(*options.Name, options.Data) + if err != nil { + m.httpError(rw, "Events.Emit failed: ", fmt.Errorf("error parsing event data: %w", err)) + return + } + + event.Name = *options.Name + event.Data = data event.Sender = window.Name() globalApplication.Event.EmitEvent(&event) - m.ok(rw) + m.json(rw, event.IsCancelled()) m.Info("Runtime call:", "method", "Events."+eventsMethodNames[method], "name", event.Name, "sender", event.Sender, "data", event.Data, "cancelled", event.IsCancelled()) default: m.httpError(rw, "Invalid events call:", fmt.Errorf("unknown method: %d", method)) diff --git a/v3/pkg/application/services.go b/v3/pkg/application/services.go index 582d135b0..607e4c586 100644 --- a/v3/pkg/application/services.go +++ b/v3/pkg/application/services.go @@ -80,7 +80,7 @@ type ServiceName interface { // specified at creation time. It can be used for initialising resources. // // The context will be valid as long as the application is running, -// and will be canceled right before shutdown. +// and will be cancelled right before shutdown. // // Services are guaranteed to receive the startup notification // in the exact order in which they were either diff --git a/v3/pkg/application/webview_window.go b/v3/pkg/application/webview_window.go index 3c8cbe70e..18ba2a782 100644 --- a/v3/pkg/application/webview_window.go +++ b/v3/pkg/application/webview_window.go @@ -118,7 +118,7 @@ type ( type WindowEvent struct { ctx *WindowEventContext - Cancelled bool + cancelled atomic.Bool } func (w *WindowEvent) Context() *WindowEventContext { @@ -129,8 +129,12 @@ func NewWindowEvent() *WindowEvent { return &WindowEvent{} } +func (w *WindowEvent) IsCancelled() bool { + return w.cancelled.Load() +} + func (w *WindowEvent) Cancel() { - w.Cancelled = true + w.cancelled.Store(true) } type WindowEventListener struct { @@ -189,13 +193,26 @@ func (w *WebviewWindow) SetMenu(menu *Menu) { } } -// EmitEvent emits an event from the window -func (w *WebviewWindow) EmitEvent(name string, data ...any) { - globalApplication.Event.EmitEvent(&CustomEvent{ +// EmitEvent emits a custom event with the specified name and associated data. +// It returns a boolean indicating whether the event was cancelled by a hook. +// The [CustomEvent.Sender] field will be set to the window name. +// +// If the given event name is registered, EmitEvent validates the data parameter +// against the expected data type. In case of a mismatch, EmitEvent reports an error +// to the registered error handler for the application and cancels the event. +func (w *WebviewWindow) EmitEvent(name string, data ...any) bool { + event := &CustomEvent{ Name: name, - Data: data, Sender: w.Name(), - }) + } + + if len(data) == 1 { + event.Data = data[0] + } else if len(data) > 1 { + event.Data = data + } + + return globalApplication.Event.EmitEvent(event) } var windowID uint @@ -841,7 +858,7 @@ func (w *WebviewWindow) HandleWindowEvent(id uint) { for _, thisHook := range hooks { thisHook.callback(thisEvent) - if thisEvent.Cancelled { + if thisEvent.IsCancelled() { return } } @@ -853,6 +870,9 @@ func (w *WebviewWindow) HandleWindowEvent(id uint) { for _, listener := range tempListeners { go func() { + if thisEvent.IsCancelled() { + return + } defer handlePanic() listener.callback(thisEvent) }() diff --git a/v3/pkg/application/window.go b/v3/pkg/application/window.go index 04c508f3a..ab0d6653d 100644 --- a/v3/pkg/application/window.go +++ b/v3/pkg/application/window.go @@ -2,7 +2,7 @@ package application import ( "unsafe" - + "github.com/wailsapp/wails/v3/pkg/events" ) @@ -19,7 +19,7 @@ type Window interface { Close() DisableSizeConstraints() DispatchWailsEvent(event *CustomEvent) - EmitEvent(name string, data ...any) + EmitEvent(name string, data ...any) bool EnableSizeConstraints() Error(message string, args ...any) ExecJS(js string) diff --git a/v3/pkg/events/known_events.go b/v3/pkg/events/known_events.go new file mode 100644 index 000000000..71fe8270f --- /dev/null +++ b/v3/pkg/events/known_events.go @@ -0,0 +1,220 @@ +package events + +func IsKnownEvent(name string) bool { + _, ok := knownEvents[name] + return ok +} + +var knownEvents = map[string]struct{}{ + "common:ApplicationOpenedWithFile": {}, + "common:ApplicationStarted": {}, + "common:ApplicationLaunchedWithUrl": {}, + "common:ThemeChanged": {}, + "common:WindowClosing": {}, + "common:WindowDidMove": {}, + "common:WindowDidResize": {}, + "common:WindowDPIChanged": {}, + "common:WindowFilesDropped": {}, + "common:WindowFocus": {}, + "common:WindowFullscreen": {}, + "common:WindowHide": {}, + "common:WindowLostFocus": {}, + "common:WindowMaximise": {}, + "common:WindowMinimise": {}, + "common:WindowToggleFrameless": {}, + "common:WindowRestore": {}, + "common:WindowRuntimeReady": {}, + "common:WindowShow": {}, + "common:WindowUnFullscreen": {}, + "common:WindowUnMaximise": {}, + "common:WindowUnMinimise": {}, + "common:WindowZoom": {}, + "common:WindowZoomIn": {}, + "common:WindowZoomOut": {}, + "common:WindowZoomReset": {}, + "common:WindowDropZoneFilesDropped": {}, + "linux:ApplicationStartup": {}, + "linux:SystemThemeChanged": {}, + "linux:WindowDeleteEvent": {}, + "linux:WindowDidMove": {}, + "linux:WindowDidResize": {}, + "linux:WindowFocusIn": {}, + "linux:WindowFocusOut": {}, + "linux:WindowLoadChanged": {}, + "mac:ApplicationDidBecomeActive": {}, + "mac:ApplicationDidChangeBackingProperties": {}, + "mac:ApplicationDidChangeEffectiveAppearance": {}, + "mac:ApplicationDidChangeIcon": {}, + "mac:ApplicationDidChangeOcclusionState": {}, + "mac:ApplicationDidChangeScreenParameters": {}, + "mac:ApplicationDidChangeStatusBarFrame": {}, + "mac:ApplicationDidChangeStatusBarOrientation": {}, + "mac:ApplicationDidChangeTheme!": {}, + "mac:ApplicationDidFinishLaunching": {}, + "mac:ApplicationDidHide": {}, + "mac:ApplicationDidResignActive": {}, + "mac:ApplicationDidUnhide": {}, + "mac:ApplicationDidUpdate": {}, + "mac:ApplicationShouldHandleReopen!": {}, + "mac:ApplicationWillBecomeActive": {}, + "mac:ApplicationWillFinishLaunching": {}, + "mac:ApplicationWillHide": {}, + "mac:ApplicationWillResignActive": {}, + "mac:ApplicationWillTerminate": {}, + "mac:ApplicationWillUnhide": {}, + "mac:ApplicationWillUpdate": {}, + "mac:MenuDidAddItem": {}, + "mac:MenuDidBeginTracking": {}, + "mac:MenuDidClose": {}, + "mac:MenuDidDisplayItem": {}, + "mac:MenuDidEndTracking": {}, + "mac:MenuDidHighlightItem": {}, + "mac:MenuDidOpen": {}, + "mac:MenuDidPopUp": {}, + "mac:MenuDidRemoveItem": {}, + "mac:MenuDidSendAction": {}, + "mac:MenuDidSendActionToItem": {}, + "mac:MenuDidUpdate": {}, + "mac:MenuWillAddItem": {}, + "mac:MenuWillBeginTracking": {}, + "mac:MenuWillDisplayItem": {}, + "mac:MenuWillEndTracking": {}, + "mac:MenuWillHighlightItem": {}, + "mac:MenuWillOpen": {}, + "mac:MenuWillPopUp": {}, + "mac:MenuWillRemoveItem": {}, + "mac:MenuWillSendAction": {}, + "mac:MenuWillSendActionToItem": {}, + "mac:MenuWillUpdate": {}, + "mac:WebViewDidCommitNavigation": {}, + "mac:WebViewDidFinishNavigation": {}, + "mac:WebViewDidReceiveServerRedirectForProvisionalNavigation": {}, + "mac:WebViewDidStartProvisionalNavigation": {}, + "mac:WindowDidBecomeKey": {}, + "mac:WindowDidBecomeMain": {}, + "mac:WindowDidBeginSheet": {}, + "mac:WindowDidChangeAlpha": {}, + "mac:WindowDidChangeBackingLocation": {}, + "mac:WindowDidChangeBackingProperties": {}, + "mac:WindowDidChangeCollectionBehavior": {}, + "mac:WindowDidChangeEffectiveAppearance": {}, + "mac:WindowDidChangeOcclusionState": {}, + "mac:WindowDidChangeOrderingMode": {}, + "mac:WindowDidChangeScreen": {}, + "mac:WindowDidChangeScreenParameters": {}, + "mac:WindowDidChangeScreenProfile": {}, + "mac:WindowDidChangeScreenSpace": {}, + "mac:WindowDidChangeScreenSpaceProperties": {}, + "mac:WindowDidChangeSharingType": {}, + "mac:WindowDidChangeSpace": {}, + "mac:WindowDidChangeSpaceOrderingMode": {}, + "mac:WindowDidChangeTitle": {}, + "mac:WindowDidChangeToolbar": {}, + "mac:WindowDidDeminiaturize": {}, + "mac:WindowDidEndSheet": {}, + "mac:WindowDidEnterFullScreen": {}, + "mac:WindowDidEnterVersionBrowser": {}, + "mac:WindowDidExitFullScreen": {}, + "mac:WindowDidExitVersionBrowser": {}, + "mac:WindowDidExpose": {}, + "mac:WindowDidFocus": {}, + "mac:WindowDidMiniaturize": {}, + "mac:WindowDidMove": {}, + "mac:WindowDidOrderOffScreen": {}, + "mac:WindowDidOrderOnScreen": {}, + "mac:WindowDidResignKey": {}, + "mac:WindowDidResignMain": {}, + "mac:WindowDidResize": {}, + "mac:WindowDidUpdate": {}, + "mac:WindowDidUpdateAlpha": {}, + "mac:WindowDidUpdateCollectionBehavior": {}, + "mac:WindowDidUpdateCollectionProperties": {}, + "mac:WindowDidUpdateShadow": {}, + "mac:WindowDidUpdateTitle": {}, + "mac:WindowDidUpdateToolbar": {}, + "mac:WindowDidZoom!": {}, + "mac:WindowFileDraggingEntered": {}, + "mac:WindowFileDraggingExited": {}, + "mac:WindowFileDraggingPerformed": {}, + "mac:WindowHide": {}, + "mac:WindowMaximise!": {}, + "mac:WindowUnMaximise!": {}, + "mac:WindowMinimise!": {}, + "mac:WindowUnMinimise!": {}, + "mac:WindowShouldClose!": {}, + "mac:WindowShow": {}, + "mac:WindowWillBecomeKey": {}, + "mac:WindowWillBecomeMain": {}, + "mac:WindowWillBeginSheet": {}, + "mac:WindowWillChangeOrderingMode": {}, + "mac:WindowWillClose": {}, + "mac:WindowWillDeminiaturize": {}, + "mac:WindowWillEnterFullScreen": {}, + "mac:WindowWillEnterVersionBrowser": {}, + "mac:WindowWillExitFullScreen": {}, + "mac:WindowWillExitVersionBrowser": {}, + "mac:WindowWillFocus": {}, + "mac:WindowWillMiniaturize": {}, + "mac:WindowWillMove": {}, + "mac:WindowWillOrderOffScreen": {}, + "mac:WindowWillOrderOnScreen": {}, + "mac:WindowWillResignMain": {}, + "mac:WindowWillResize": {}, + "mac:WindowWillUnfocus": {}, + "mac:WindowWillUpdate": {}, + "mac:WindowWillUpdateAlpha": {}, + "mac:WindowWillUpdateCollectionBehavior": {}, + "mac:WindowWillUpdateCollectionProperties": {}, + "mac:WindowWillUpdateShadow": {}, + "mac:WindowWillUpdateTitle": {}, + "mac:WindowWillUpdateToolbar": {}, + "mac:WindowWillUpdateVisibility": {}, + "mac:WindowWillUseStandardFrame": {}, + "mac:WindowZoomIn!": {}, + "mac:WindowZoomOut!": {}, + "mac:WindowZoomReset!": {}, + "windows:APMPowerSettingChange": {}, + "windows:APMPowerStatusChange": {}, + "windows:APMResumeAutomatic": {}, + "windows:APMResumeSuspend": {}, + "windows:APMSuspend": {}, + "windows:ApplicationStarted": {}, + "windows:SystemThemeChanged": {}, + "windows:WebViewNavigationCompleted": {}, + "windows:WindowActive": {}, + "windows:WindowBackgroundErase": {}, + "windows:WindowClickActive": {}, + "windows:WindowClosing": {}, + "windows:WindowDidMove": {}, + "windows:WindowDidResize": {}, + "windows:WindowDPIChanged": {}, + "windows:WindowDragDrop": {}, + "windows:WindowDragEnter": {}, + "windows:WindowDragLeave": {}, + "windows:WindowDragOver": {}, + "windows:WindowEndMove": {}, + "windows:WindowEndResize": {}, + "windows:WindowFullscreen": {}, + "windows:WindowHide": {}, + "windows:WindowInactive": {}, + "windows:WindowKeyDown": {}, + "windows:WindowKeyUp": {}, + "windows:WindowKillFocus": {}, + "windows:WindowNonClientHit": {}, + "windows:WindowNonClientMouseDown": {}, + "windows:WindowNonClientMouseLeave": {}, + "windows:WindowNonClientMouseMove": {}, + "windows:WindowNonClientMouseUp": {}, + "windows:WindowPaint": {}, + "windows:WindowRestore": {}, + "windows:WindowSetFocus": {}, + "windows:WindowShow": {}, + "windows:WindowStartMove": {}, + "windows:WindowStartResize": {}, + "windows:WindowUnFullscreen": {}, + "windows:WindowZOrderChanged": {}, + "windows:WindowMinimise": {}, + "windows:WindowUnMinimise": {}, + "windows:WindowMaximise": {}, + "windows:WindowUnMaximise": {}, +} diff --git a/v3/tasks/events/generate.go b/v3/tasks/events/generate.go index 5f2ba1adb..618b23d76 100644 --- a/v3/tasks/events/generate.go +++ b/v3/tasks/events/generate.go @@ -10,7 +10,7 @@ import ( const eventsGo = `package events type ApplicationEventType uint -type WindowEventType uint +type WindowEventType uint var Common = newCommonEvents() @@ -58,7 +58,6 @@ func JSEvent(event uint) string { var eventToJS = map[uint]string{ $$EVENTTOJS} - ` const darwinEventsH = `//go:build darwin @@ -85,6 +84,17 @@ $$CHEADEREVENTS #endif` +const knownEvents = `package $$PACKAGE + +func IsKnownEvent(name string) bool { + _, ok := knownEvents[name] + return ok +} + +var knownEvents = map[string]struct{}{ +$$EVENTNAMEMAP} +` + const eventsTS = `/* _ __ _ __ | | / /___ _(_) /____ @@ -100,14 +110,19 @@ The electron alternative for Go export const Types = Object.freeze({ Windows: Object.freeze({ -$$WINDOWSJSEVENTS }), +$$WINDOWSJSEVENTS } as const), Mac: Object.freeze({ -$$MACJSEVENTS }), +$$MACJSEVENTS } as const), Linux: Object.freeze({ -$$LINUXJSEVENTS }), +$$LINUXJSEVENTS } as const), Common: Object.freeze({ -$$COMMONJSEVENTS }), -}); +$$COMMONJSEVENTS } as const), +} as const); + +export const Windows = Types.Windows; +export const Mac = Types.Mac; +export const Linux = Types.Linux; +export const Common = Types.Common; ` func main() { @@ -116,29 +131,30 @@ func main() { panic(err) } - linuxEventsDecl := bytes.NewBufferString("") - linuxEventsValues := bytes.NewBufferString("") - linuxCHeaderEvents := bytes.NewBufferString("") + var linuxEventsDecl bytes.Buffer + var linuxEventsValues bytes.Buffer + var linuxCHeaderEvents bytes.Buffer - macEventsDecl := bytes.NewBufferString("") - macEventsValues := bytes.NewBufferString("") - macCHeaderEvents := bytes.NewBufferString("") - windowDelegateEvents := bytes.NewBufferString("") - applicationDelegateEvents := bytes.NewBufferString("") - webviewDelegateEvents := bytes.NewBufferString("") + var macEventsDecl bytes.Buffer + var macEventsValues bytes.Buffer + var macCHeaderEvents bytes.Buffer + var windowDelegateEvents bytes.Buffer + var applicationDelegateEvents bytes.Buffer + var webviewDelegateEvents bytes.Buffer - windowsEventsDecl := bytes.NewBufferString("") - windowsEventsValues := bytes.NewBufferString("") + var windowsEventsDecl bytes.Buffer + var windowsEventsValues bytes.Buffer - commonEventsDecl := bytes.NewBufferString("") - commonEventsValues := bytes.NewBufferString("") + var commonEventsDecl bytes.Buffer + var commonEventsValues bytes.Buffer - linuxTSEvents := bytes.NewBufferString("") - macTSEvents := bytes.NewBufferString("") - windowsTSEvents := bytes.NewBufferString("") - commonTSEvents := bytes.NewBufferString("") + var linuxTSEvents bytes.Buffer + var macTSEvents bytes.Buffer + var windowsTSEvents bytes.Buffer + var commonTSEvents bytes.Buffer - eventToJS := bytes.NewBufferString("") + var eventNameMap bytes.Buffer + var eventToJS bytes.Buffer var id int // var maxLinuxEvents int @@ -188,6 +204,7 @@ func main() { linuxEventsDecl.WriteString("\t" + eventTitle + " " + eventType + "\n") linuxEventsValues.WriteString("\t\t" + event + ": " + strconv.Itoa(id) + ",\n") linuxTSEvents.WriteString("\t\t" + event + ": \"linux:" + event + "\",\n") + eventNameMap.WriteString("\t\"" + strings.TrimSpace(string(line)) + "\": {},\n") eventToJS.WriteString("\t" + strconv.Itoa(id) + ": \"linux:" + event + "\",\n") maxLinuxEvents = id linuxCHeaderEvents.WriteString("#define Event" + eventTitle + " " + strconv.Itoa(id) + "\n") @@ -203,6 +220,7 @@ func main() { macEventsValues.WriteString("\t\t" + event + ": " + strconv.Itoa(id) + ",\n") macTSEvents.WriteString("\t\t" + event + ": \"mac:" + event + "\",\n") macCHeaderEvents.WriteString("#define Event" + eventTitle + " " + strconv.Itoa(id) + "\n") + eventNameMap.WriteString("\t\"" + strings.TrimSpace(string(line)) + "\": {},\n") eventToJS.WriteString("\t" + strconv.Itoa(id) + ": \"mac:" + event + "\",\n") maxMacEvents = id if ignoreEvent { @@ -250,7 +268,8 @@ func main() { commonEventsDecl.WriteString("\t" + eventTitle + " " + eventType + "\n") commonEventsValues.WriteString("\t\t" + event + ": " + strconv.Itoa(id) + ",\n") commonTSEvents.WriteString("\t\t" + event + ": \"common:" + event + "\",\n") - eventToJS.WriteString("\t" + strconv.Itoa(id) + ": \"common:" + event + "\",\n") + eventNameMap.WriteString("\t\"" + strings.TrimSpace(string(line)) + "\": {},\n") + eventToJS.WriteString("\t" + strconv.Itoa(id) + ": \"common:" + event + "\",\n") case "windows": eventType := "ApplicationEventType" if strings.HasPrefix(event, "Window") { @@ -262,6 +281,7 @@ func main() { windowsEventsDecl.WriteString("\t" + eventTitle + " " + eventType + "\n") windowsEventsValues.WriteString("\t\t" + event + ": " + strconv.Itoa(id) + ",\n") windowsTSEvents.WriteString("\t\t" + event + ": \"windows:" + event + "\",\n") + eventNameMap.WriteString("\t\"" + strings.TrimSpace(string(line)) + "\": {},\n") eventToJS.WriteString("\t" + strconv.Itoa(id) + ": \"windows:" + event + "\",\n") } } @@ -285,6 +305,21 @@ func main() { panic(err) } + // Save the knownEvents template substituting the values and decls + templateToWrite = strings.ReplaceAll(knownEvents, "$$PACKAGE", "events") + templateToWrite = strings.ReplaceAll(templateToWrite, "$$EVENTNAMEMAP", eventNameMap.String()) + err = os.WriteFile("../../pkg/events/known_events.go", []byte(templateToWrite), 0644) + if err != nil { + panic(err) + } + + templateToWrite = strings.ReplaceAll(knownEvents, "$$PACKAGE", "collect") + templateToWrite = strings.ReplaceAll(templateToWrite, "$$EVENTNAMEMAP", eventNameMap.String()) + err = os.WriteFile("../../internal/generator/collect/known_events.go", []byte(templateToWrite), 0644) + if err != nil { + panic(err) + } + // Save the eventsTS template substituting the values and decls templateToWrite = strings.ReplaceAll(eventsTS, "$$MACJSEVENTS", macTSEvents.String()) templateToWrite = strings.ReplaceAll(templateToWrite, "$$WINDOWSJSEVENTS", windowsTSEvents.String())