mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-17 01:19:29 +08:00
[v3] Fix binding generator bugs and prepare for Go 1.24 (#4045)
* Rename predicates source file * Overhaul and document type predicates * Fix model collection logic for named types * Fix map key type rendering * Fix map creation code * Fix rendering of structs that implement marshaler interfaces * Fix type cycle detection to take type args into account * Fix enum and typeparam field initialisation * Improve unsupported type warnings * Remove internal models file * Deduplicate template code * Accept generic aliases in static analyser * Support new `encoding/json` flag `omitzero` * Handle special cases when rendering generic aliases * Update npm test dependencies * Test class aliases and implicit private dependencies * Test marshaler combinations * Test map key types * Remove bad map keys from unrelated tests * Test service discovery through generic aliases * Test generic aliases * Test warning messages * Disable go1.24 tests * Update changelog * Restore rendering of injected lines in index file * Test directives * Add wails:ignore directive * Fix typo * Move injections to the bottom of service files * Handle errors from closing files * Do not emit messages when services define only lifecycle methods * Add internal directive for services and models * Update changelog * Fix error in service templates * Test internal directive on services/models * Fix error in index template * Base testdata updates * Testdata for class aliases and implicit private dependencies * Testdata for marshaler combinations * Testdata for map key types * Testdata for bad map key fixes * Add weakly typed enums aka alias constants * Testdata for enum and typeparam field fixes * Testdata for generic aliases * Testdata for warning messages * Testdata for directives * Testdata for weakly typed enums * Update binding example * Update services example * Remove go1.24 testdata * Update cli doc * Fix analyser tests * Fix windows tests... hopefully * go mod tidy on examples * Update bindings guide --------- Co-authored-by: Lea Anthony <lea.anthony@gmail.com>
This commit is contained in:
parent
d4096868e3
commit
37673eb24d
@ -46,6 +46,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- 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)
|
||||
|
||||
### Fixed
|
||||
|
||||
@ -62,6 +68,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- 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)
|
||||
|
||||
### Changed
|
||||
|
||||
@ -72,6 +87,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- `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)
|
||||
|
||||
## v3.0.0-alpha.9 - 2025-01-13
|
||||
|
||||
|
@ -134,7 +134,6 @@ wails3 generate bindings [flags] [patterns...]
|
||||
| `-f` | Additional Go build flags | |
|
||||
| `-d` | Output directory | `frontend/bindings` |
|
||||
| `-models` | Models filename | `models` |
|
||||
| `-internal` | Internal filename | `internal` |
|
||||
| `-index` | Index filename | `index` |
|
||||
| `-ts` | Generate TypeScript | `false` |
|
||||
| `-i` | Use TS interfaces | `false` |
|
||||
|
@ -114,7 +114,7 @@ is used to namespace the generated files.
|
||||
The generated `greetservice.js` file contains the JavaScript code that mirrors
|
||||
the Go struct and its methods:
|
||||
|
||||
```javascript
|
||||
```javascript title="greetservice.js"
|
||||
// @ts-check
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
@ -212,7 +212,7 @@ If we run the bindings generator again, we should see the following output:
|
||||
In the `frontend/bindings/changeme` directory, you should see a new `models.js`
|
||||
file containing the following code:
|
||||
|
||||
```javascript
|
||||
```javascript title="models.js"
|
||||
// @ts-check
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
@ -270,7 +270,7 @@ Here's an example of how you can use the generated JavaScript `Person` type in
|
||||
your frontend code:
|
||||
|
||||
```javascript
|
||||
import { Greet } from "./bindings/changeme/GreetService.js";
|
||||
import { Greet } from "./bindings/changeme/greetservice.js";
|
||||
import { Person } from "./bindings/changeme/models.js";
|
||||
|
||||
const resultElement = document.getElementById("result");
|
||||
@ -291,6 +291,36 @@ the `Greet` method.
|
||||
Using bound models allows you to work with complex data structures and
|
||||
seamlessly pass them between the frontend and backend of your Wails application.
|
||||
|
||||
### Index files
|
||||
|
||||
The generator outputs an additional `index.js` file that re-exports all services and models:
|
||||
|
||||
```javascript title="index.js"
|
||||
// @ts-check
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
import * as GreetService from "./greetservice.js";
|
||||
export {
|
||||
GreetService
|
||||
};
|
||||
|
||||
export {
|
||||
Person
|
||||
} from "./models.js";
|
||||
```
|
||||
|
||||
You can take advantage of this feature
|
||||
to aggregate import statements for multiple services and models.
|
||||
If you are building your frontend with a bundler,
|
||||
which is the default for most project templates,
|
||||
you can also simplify the import path:
|
||||
|
||||
```javascript
|
||||
import { GreetService, Person } from "./bindings/changeme";
|
||||
await GreetService.Greet(new Person(/* ... */));
|
||||
```
|
||||
|
||||
### Using Typescript
|
||||
|
||||
To generate TypeScript bindings instead of JavaScript, you can use the `-ts`
|
||||
@ -382,9 +412,7 @@ The context provides several powerful features:
|
||||
frontend, which will raise an error through the Promise chain.
|
||||
|
||||
2. **Window Information**: You can determine which window made the call using
|
||||
these context keys:
|
||||
- `application.WindowNameKey` - Returns the name of the calling window
|
||||
- `application.WindowIDKey` - Returns the ID of the calling window
|
||||
the context key `application.WindowKey`.
|
||||
|
||||
Here are some examples:
|
||||
|
||||
@ -403,9 +431,8 @@ func (s *MyService) LongRunningTask(ctx context.Context, input string) (string,
|
||||
|
||||
// Getting caller window information
|
||||
func (s *MyService) WindowAwareMethod(ctx context.Context) (string, error) {
|
||||
windowName := ctx.Value(application.WindowNameKey).(string)
|
||||
windowID := ctx.Value(application.WindowIDKey).(string)
|
||||
return fmt.Sprintf("Called from window: %s (ID: %s)", windowName, windowID), nil
|
||||
window := ctx.Value(application.WindowKey).(application.Window)
|
||||
return fmt.Sprintf("Called from window: %s (ID: %s)", window.Name(), window.ID()), nil
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -2,4 +2,6 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
export * from "./models.js";
|
||||
export {
|
||||
Person
|
||||
} from "./models.js";
|
||||
|
@ -1,55 +0,0 @@
|
||||
// @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";
|
||||
|
||||
/**
|
||||
* Person holds someone's most important attributes
|
||||
*/
|
||||
export class Person {
|
||||
/**
|
||||
* Creates a new Person instance.
|
||||
* @param {Partial<Person>} [$$source = {}] - The source object to create the Person.
|
||||
*/
|
||||
constructor($$source = {}) {
|
||||
if (!("name" in $$source)) {
|
||||
/**
|
||||
* Name is the person's name
|
||||
* @member
|
||||
* @type {string}
|
||||
*/
|
||||
this["name"] = "";
|
||||
}
|
||||
if (!("counts" in $$source)) {
|
||||
/**
|
||||
* Counts tracks the number of time the person
|
||||
* has been greeted in various ways
|
||||
* @member
|
||||
* @type {number[]}
|
||||
*/
|
||||
this["counts"] = [];
|
||||
}
|
||||
|
||||
Object.assign(this, $$source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Person instance from a string or object.
|
||||
* @param {any} [$$source = {}]
|
||||
* @returns {Person}
|
||||
*/
|
||||
static createFrom($$source = {}) {
|
||||
const $$createField1_0 = $$createType0;
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
if ("counts" in $$parsedSource) {
|
||||
$$parsedSource["counts"] = $$createField1_0($$parsedSource["counts"]);
|
||||
}
|
||||
return new Person(/** @type {Partial<Person>} */($$parsedSource));
|
||||
}
|
||||
}
|
||||
|
||||
// Private type creation functions
|
||||
const $$createType0 = $Create.Array($Create.Any);
|
@ -2,6 +2,54 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
export {
|
||||
Person
|
||||
} from "./internal.js";
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import {Create as $Create} from "/wails/runtime.js";
|
||||
|
||||
/**
|
||||
* Person holds someone's most important attributes
|
||||
*/
|
||||
export class Person {
|
||||
/**
|
||||
* Creates a new Person instance.
|
||||
* @param {Partial<Person>} [$$source = {}] - The source object to create the Person.
|
||||
*/
|
||||
constructor($$source = {}) {
|
||||
if (!("name" in $$source)) {
|
||||
/**
|
||||
* Name is the person's name
|
||||
* @member
|
||||
* @type {string}
|
||||
*/
|
||||
this["name"] = "";
|
||||
}
|
||||
if (!("counts" in $$source)) {
|
||||
/**
|
||||
* Counts tracks the number of time the person
|
||||
* has been greeted in various ways
|
||||
* @member
|
||||
* @type {number[]}
|
||||
*/
|
||||
this["counts"] = [];
|
||||
}
|
||||
|
||||
Object.assign(this, $$source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Person instance from a string or object.
|
||||
* @param {any} [$$source = {}]
|
||||
* @returns {Person}
|
||||
*/
|
||||
static createFrom($$source = {}) {
|
||||
const $$createField1_0 = $$createType0;
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
if ("counts" in $$parsedSource) {
|
||||
$$parsedSource["counts"] = $$createField1_0($$parsedSource["counts"]);
|
||||
}
|
||||
return new Person(/** @type {Partial<Person>} */($$parsedSource));
|
||||
}
|
||||
}
|
||||
|
||||
// Private type creation functions
|
||||
const $$createType0 = $Create.Array($Create.Any);
|
||||
|
@ -1,22 +1,20 @@
|
||||
module changeme
|
||||
|
||||
go 1.22
|
||||
|
||||
toolchain go1.22.0
|
||||
go 1.23.4
|
||||
|
||||
require github.com/wailsapp/wails/v3 v3.0.0-alpha.0
|
||||
|
||||
require (
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/bep/debounce v1.2.1 // indirect
|
||||
github.com/ebitengine/purego v0.4.0-alpha.4 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.5.0 // indirect
|
||||
github.com/go-git/go-git/v5 v5.11.0 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
||||
github.com/go-git/go-git/v5 v5.13.1 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
|
||||
@ -25,25 +23,25 @@ require (
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/leaanthony/go-ansi-parser v1.6.1 // indirect
|
||||
github.com/leaanthony/u v1.1.0 // indirect
|
||||
github.com/lmittmann/tint v1.0.3 // indirect
|
||||
github.com/lmittmann/tint v1.0.4 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
|
||||
github.com/rivo/uniseg v0.4.4 // indirect
|
||||
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/rogpeppe/go-internal v1.12.0 // indirect
|
||||
github.com/samber/lo v1.38.1 // indirect
|
||||
github.com/sergi/go-diff v1.2.0 // indirect
|
||||
github.com/stretchr/testify v1.8.4 // indirect
|
||||
github.com/wailsapp/go-webview2 v1.0.9 // indirect
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||
github.com/stretchr/testify v1.10.0 // indirect
|
||||
github.com/wailsapp/go-webview2 v1.0.19 // indirect
|
||||
github.com/wailsapp/mimetype v1.4.1 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
golang.org/x/crypto v0.21.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect
|
||||
golang.org/x/net v0.21.0 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
golang.org/x/crypto v0.32.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||
golang.org/x/net v0.34.0 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
)
|
||||
|
||||
|
@ -3,6 +3,7 @@ github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/
|
||||
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
|
||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
|
||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
||||
@ -31,13 +32,16 @@ github.com/go-git/go-billy/v5 v5.1.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI
|
||||
github.com/go-git/go-billy/v5 v5.2.0 h1:GcoouCP9J+5slw2uXAocL70z8ml4A8B/H8nEPt6CLPk=
|
||||
github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
|
||||
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
|
||||
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 h1:PbKy9zOy4aAKrJ5pibIRpVO2BXnK1Tlcg+caKI7Ox5M=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
|
||||
github.com/go-git/go-git/v5 v5.3.0 h1:8WKMtJR2j8RntEXR/uvTKagfEt4GYlwQ7mntE4+0GWc=
|
||||
github.com/go-git/go-git/v5 v5.3.0/go.mod h1:xdX4bWJ48aOrdhnl2XqHYstHbbp6+LFS4r4X+lNVprw=
|
||||
github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY=
|
||||
github.com/go-git/go-git/v5 v5.13.1/go.mod h1:qryJB4cSBoq3FRoBRf5A77joojuBcmPJ0qu3XXXVixc=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
@ -46,6 +50,7 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
@ -74,6 +79,7 @@ github.com/leaanthony/u v1.1.0/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQc
|
||||
github.com/lmittmann/tint v1.0.0 h1:fzEj70K1L58uyoePQxKe+ezDZJ5pybiWGdA0JeFvvyw=
|
||||
github.com/lmittmann/tint v1.0.0/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
|
||||
github.com/lmittmann/tint v1.0.3/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
|
||||
github.com/lmittmann/tint v1.0.4/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
|
||||
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
||||
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
@ -81,6 +87,7 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||
@ -99,15 +106,18 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
||||
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97 h1:3RPlVWzZ/PDqmVuf/FKHARG5EMid/tl7cv54Sw/QRVY=
|
||||
github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
|
||||
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
|
||||
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
@ -117,8 +127,10 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/wailsapp/go-webview2 v1.0.9 h1:lrU+q0cf1wgLdR69rN+ZnRtMJNaJRrcQ4ELxoO7/xjs=
|
||||
github.com/wailsapp/go-webview2 v1.0.9/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo=
|
||||
github.com/wailsapp/go-webview2 v1.0.19/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc=
|
||||
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
|
||||
github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
|
||||
github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI=
|
||||
@ -132,8 +144,10 @@ golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0
|
||||
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME=
|
||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
|
||||
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
@ -142,6 +156,7 @@ golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -157,12 +172,14 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
|
@ -1,27 +1,25 @@
|
||||
module changeme
|
||||
|
||||
go 1.22.4
|
||||
|
||||
toolchain go1.23.0
|
||||
go 1.23.4
|
||||
|
||||
require github.com/wailsapp/wails/v3 v3.0.0-alpha.7
|
||||
|
||||
require (
|
||||
dario.cat/mergo v1.0.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect
|
||||
dario.cat/mergo v1.0.1 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.4 // indirect
|
||||
github.com/bep/debounce v1.2.1 // indirect
|
||||
github.com/cloudflare/circl v1.3.7 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
|
||||
github.com/cloudflare/circl v1.5.0 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.4.0 // indirect
|
||||
github.com/ebitengine/purego v0.4.0-alpha.4 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.5.0 // indirect
|
||||
github.com/go-git/go-git/v5 v5.11.0 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
||||
github.com/go-git/go-git/v5 v5.13.1 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
|
||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||
@ -30,22 +28,22 @@ require (
|
||||
github.com/lmittmann/tint v1.0.4 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.1 // indirect
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/samber/lo v1.38.1 // indirect
|
||||
github.com/sergi/go-diff v1.2.0 // indirect
|
||||
github.com/skeema/knownhosts v1.2.1 // indirect
|
||||
github.com/wailsapp/go-webview2 v1.0.16 // indirect
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||
github.com/skeema/knownhosts v1.3.0 // indirect
|
||||
github.com/wailsapp/go-webview2 v1.0.19 // indirect
|
||||
github.com/wailsapp/mimetype v1.4.1 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
golang.org/x/crypto v0.23.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect
|
||||
golang.org/x/mod v0.17.0 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||
golang.org/x/crypto v0.32.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||
golang.org/x/mod v0.22.0 // indirect
|
||||
golang.org/x/net v0.34.0 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/tools v0.29.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
)
|
||||
|
||||
|
@ -1,10 +1,13 @@
|
||||
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
||||
github.com/ProtonMail/go-crypto v1.1.4/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
@ -15,8 +18,10 @@ github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7N
|
||||
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
|
||||
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
|
||||
github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
|
||||
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||
github.com/cyphar/filepath-securejoin v0.4.0/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@ -32,20 +37,25 @@ github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66D
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||
github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
|
||||
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
|
||||
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||
github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4=
|
||||
github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY=
|
||||
github.com/go-git/go-git/v5 v5.13.1/go.mod h1:qryJB4cSBoq3FRoBRf5A77joojuBcmPJ0qu3XXXVixc=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
|
||||
@ -76,6 +86,7 @@ github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
|
||||
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
|
||||
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
|
||||
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
|
||||
github.com/pjbgf/sha1cd v0.3.1/go.mod h1:Y8t7jSB/dEI/lQE04A1HVKteqjj9bX5O4+Cex0TCu8s=
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
@ -91,9 +102,11 @@ github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
|
||||
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
|
||||
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
|
||||
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ=
|
||||
github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
|
||||
github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
@ -101,6 +114,7 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/wailsapp/go-webview2 v1.0.16 h1:wffnvnkkLvhRex/aOrA3R7FP7rkvOqL/bir1br7BekU=
|
||||
github.com/wailsapp/go-webview2 v1.0.16/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo=
|
||||
github.com/wailsapp/go-webview2 v1.0.19/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc=
|
||||
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
|
||||
github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
|
||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||
@ -113,12 +127,15 @@ golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2Uz
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME=
|
||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
@ -129,11 +146,13 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -147,12 +166,14 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
@ -175,6 +196,7 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@ -184,5 +206,6 @@ gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
@ -2,9 +2,13 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
import * as Hashes from "./hashes.js";
|
||||
import * as Service from "./service.js";
|
||||
export {
|
||||
Hashes
|
||||
Service
|
||||
};
|
||||
|
||||
export * from "./models.js";
|
||||
import * as $models from "./models.js";
|
||||
|
||||
/**
|
||||
* @typedef {$models.Hashes} Hashes
|
||||
*/
|
||||
|
@ -6,44 +6,9 @@
|
||||
// @ts-ignore: Unused imports
|
||||
import {Create as $Create} from "/wails/runtime.js";
|
||||
|
||||
export class Hashes {
|
||||
/**
|
||||
* Creates a new Hashes instance.
|
||||
* @param {Partial<Hashes>} [$$source = {}] - The source object to create the Hashes.
|
||||
*/
|
||||
constructor($$source = {}) {
|
||||
if (!("md5" in $$source)) {
|
||||
/**
|
||||
* @member
|
||||
* @type {string}
|
||||
*/
|
||||
this["md5"] = "";
|
||||
}
|
||||
if (!("sha1" in $$source)) {
|
||||
/**
|
||||
* @member
|
||||
* @type {string}
|
||||
*/
|
||||
this["sha1"] = "";
|
||||
}
|
||||
if (!("sha256" in $$source)) {
|
||||
/**
|
||||
* @member
|
||||
* @type {string}
|
||||
*/
|
||||
this["sha256"] = "";
|
||||
}
|
||||
|
||||
Object.assign(this, $$source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Hashes instance from a string or object.
|
||||
* @param {any} [$$source = {}]
|
||||
* @returns {Hashes}
|
||||
*/
|
||||
static createFrom($$source = {}) {
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
return new Hashes(/** @type {Partial<Hashes>} */($$parsedSource));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @typedef {Object} Hashes
|
||||
* @property {string} md5
|
||||
* @property {string} sha1
|
||||
* @property {string} sha256
|
||||
*/
|
||||
|
@ -0,0 +1,20 @@
|
||||
// @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 {Call as $Call, Create as $Create} from "/wails/runtime.js";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import * as $models from "./models.js";
|
||||
|
||||
/**
|
||||
* @param {string} s
|
||||
* @returns {Promise<$models.Hashes> & { cancel(): void }}
|
||||
*/
|
||||
export function Generate(s) {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(1123907498, s));
|
||||
return $resultPromise;
|
||||
}
|
@ -26,15 +26,6 @@ export function Get(key) {
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Name returns the name of the plugin.
|
||||
* @returns {Promise<string> & { cancel(): void }}
|
||||
*/
|
||||
export function Name() {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(2879709053));
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save saves the store to disk
|
||||
* @returns {Promise<void> & { cancel(): void }}
|
||||
|
@ -40,16 +40,6 @@ export function Info(message, ...args) {
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Name returns the name of the plugin.
|
||||
* You should use the go module format e.g. github.com/myuser/myplugin
|
||||
* @returns {Promise<string> & { cancel(): void }}
|
||||
*/
|
||||
export function Name() {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(3407342027));
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {slog$0.Level} level
|
||||
* @returns {Promise<void> & { cancel(): void }}
|
||||
|
@ -24,16 +24,6 @@ export function Execute(query, ...args) {
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Name returns the name of the plugin.
|
||||
* You should use the go module format e.g. github.com/myuser/myplugin
|
||||
* @returns {Promise<string> & { cancel(): void }}
|
||||
*/
|
||||
export function Name() {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(2075046103));
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} dbPath
|
||||
* @returns {Promise<string> & { cancel(): void }}
|
||||
@ -57,16 +47,6 @@ export function Select(query, ...args) {
|
||||
return $typingPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown is called when the app is shutting down
|
||||
* You can use this to clean up any resources you have allocated
|
||||
* @returns {Promise<void> & { cancel(): void }}
|
||||
*/
|
||||
export function Shutdown() {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(846401686));
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
// Private type creation functions
|
||||
const $$createType0 = $Create.Map($Create.Any, $Create.Any);
|
||||
const $$createType1 = $Create.Array($$createType0);
|
||||
|
@ -2,4 +2,10 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
export * from "./models.js";
|
||||
import * as $models from "./models.js";
|
||||
|
||||
/**
|
||||
* A Level is the importance or severity of a log event.
|
||||
* The higher the level, the more important or severe the event.
|
||||
* @typedef {$models.Level} Level
|
||||
*/
|
||||
|
@ -9,7 +9,7 @@
|
||||
import * as sqlite from './bindings/github.com/wailsapp/wails/v3/pkg/services/sqlite/service.js';
|
||||
import * as kvstore from './bindings/github.com/wailsapp/wails/v3/pkg/services/kvstore/keyvaluestore.js';
|
||||
import {Debug, Info, Warning, Error} from './bindings/github.com/wailsapp/wails/v3/pkg/services/log/loggerservice.js';
|
||||
import * as hash from './bindings/github.com/wailsapp/wails/v3/examples/services/hashes/hashes.js';
|
||||
import * as hash from './bindings/github.com/wailsapp/wails/v3/examples/services/hashes/service.js';
|
||||
|
||||
function runHash() {
|
||||
let hashstring = document.getElementById("hashstring").value;
|
||||
|
@ -6,16 +6,19 @@ import (
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
)
|
||||
|
||||
type Hashes struct {
|
||||
type Hashes = struct {
|
||||
MD5 string `json:"md5"`
|
||||
SHA1 string `json:"sha1"`
|
||||
SHA256 string `json:"sha256"`
|
||||
}
|
||||
|
||||
func (h *Hashes) Generate(s string) Hashes {
|
||||
type Service struct{}
|
||||
|
||||
func (h *Service) Generate(s string) Hashes {
|
||||
md5Hash := md5.Sum([]byte(s))
|
||||
sha1Hash := sha1.Sum([]byte(s))
|
||||
sha256Hash := sha256.Sum256([]byte(s))
|
||||
@ -27,16 +30,16 @@ func (h *Hashes) Generate(s string) Hashes {
|
||||
}
|
||||
}
|
||||
|
||||
func New() *Hashes {
|
||||
return &Hashes{}
|
||||
func New() *Service {
|
||||
return &Service{}
|
||||
}
|
||||
|
||||
func (h *Hashes) ServiceShutdown() error { return nil }
|
||||
|
||||
func (h *Hashes) ServiceName() string {
|
||||
func (h *Service) ServiceName() string {
|
||||
return "Hashes Service"
|
||||
}
|
||||
|
||||
func (h *Hashes) ServiceStartup(_ context.Context, _ application.ServiceOptions) error {
|
||||
func (h *Service) ServiceStartup(context.Context, application.ServiceOptions) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Service) ServiceShutdown() error { return nil }
|
||||
|
@ -128,6 +128,7 @@ require (
|
||||
gitlab.com/digitalxero/go-conventional-commit v1.0.7 // indirect
|
||||
golang.org/x/crypto v0.32.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||
golang.org/x/exp/typeparams v0.0.0-20250128182459-e0ece0dbea4c
|
||||
golang.org/x/image v0.21.0 // indirect
|
||||
golang.org/x/mod v0.22.0 // indirect
|
||||
golang.org/x/net v0.34.0 // indirect
|
||||
|
@ -350,6 +350,8 @@ golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||
golang.org/x/exp/typeparams v0.0.0-20250128182459-e0ece0dbea4c h1:sMPlrlhFwAE8DZXzAIztseGS+N8uGlLbFQCOTsoIPmc=
|
||||
golang.org/x/exp/typeparams v0.0.0-20250128182459-e0ece0dbea4c/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
|
||||
golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s=
|
||||
golang.org/x/image v0.21.0/go.mod h1:vUbsLavqK/W303ZroQQVKQ+Af3Yl6Uz1Ppu5J/cLz78=
|
||||
|
@ -11,7 +11,6 @@ type GenerateBindingsOptions struct {
|
||||
BuildFlagsString string `name:"f" description:"A list of additional space-separated Go build flags. Flags (or parts of them) can be wrapped in single or double quotes to include spaces"`
|
||||
OutputDirectory string `name:"d" description:"The output directory" default:"frontend/bindings"`
|
||||
ModelsFilename string `name:"models" description:"File name for exported JS/TS models (excluding the extension)" default:"models"`
|
||||
InternalFilename string `name:"internal" description:"File name for unexported JS/TS models (excluding the extension)" default:"internal"`
|
||||
IndexFilename string `name:"index" description:"File name for JS/TS package indexes (excluding the extension)" default:"index"`
|
||||
TS bool `name:"ts" description:"Generate Typescript bindings"`
|
||||
UseInterfaces bool `name:"i" description:"Generate Typescript interfaces instead of classes"`
|
||||
|
1
v3/internal/generator/.gitignore
vendored
1
v3/internal/generator/.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
.task
|
||||
node_modules
|
||||
testdata/output/**/*.got.[jt]s
|
||||
testdata/output/**/*.got.log
|
||||
|
@ -7,7 +7,7 @@ shopt: [globstar]
|
||||
tasks:
|
||||
clean:
|
||||
cmds:
|
||||
- rm -rf ./testdata/output/**/*.got.[jt]s
|
||||
- rm -rf ./testdata/output/**/*.got.[jt]s ./testdata/output/**/*.got.log
|
||||
|
||||
test:
|
||||
cmds:
|
||||
|
@ -68,16 +68,11 @@ func FindServices(pkgs []*packages.Package, systemPaths *config.SystemPaths, log
|
||||
|
||||
// Object seen for the first time:
|
||||
// add type params to owner map.
|
||||
// If applicable, process methods too.
|
||||
var tp *types.TypeParamList
|
||||
var recv *types.Named
|
||||
switch t := obj.Type().(type) {
|
||||
case *types.Named:
|
||||
|
||||
if t, ok := obj.Type().(interface{ TypeParams() *types.TypeParamList }); ok {
|
||||
tp = t.TypeParams()
|
||||
recv = t
|
||||
case *types.Signature:
|
||||
tp = t.TypeParams()
|
||||
default:
|
||||
} else {
|
||||
// Instantiated object has unexpected kind:
|
||||
// the spec might have changed.
|
||||
logger.Warningf(
|
||||
@ -94,8 +89,8 @@ func FindServices(pkgs []*packages.Package, systemPaths *config.SystemPaths, log
|
||||
}
|
||||
}
|
||||
|
||||
// Process methods.
|
||||
if recv != nil && recv.NumMethods() > 0 {
|
||||
// If this is a named type, process methods.
|
||||
if recv, ok := obj.Type().(*types.Named); ok && recv.NumMethods() > 0 {
|
||||
// Register receiver type params.
|
||||
for i := range recv.NumMethods() {
|
||||
tp := recv.Method(i).Type().(*types.Signature).RecvTypeParams()
|
||||
|
@ -3,6 +3,8 @@ package collect
|
||||
import (
|
||||
"go/types"
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/tools/go/types/typeutil"
|
||||
)
|
||||
|
||||
type (
|
||||
@ -120,26 +122,26 @@ func (imports *ImportMap) Add(pkg *PackageInfo) {
|
||||
// AddType does not support unsynchronised concurrent calls
|
||||
// on the same receiver.
|
||||
func (imports *ImportMap) AddType(typ types.Type) {
|
||||
imports.addTypeImpl(typ, make(map[*types.TypeName]bool))
|
||||
imports.addTypeImpl(typ, new(typeutil.Map))
|
||||
}
|
||||
|
||||
// addTypeImpl provides the actual implementation of AddType.
|
||||
// The visited parameter is used to break cycles.
|
||||
func (imports *ImportMap) addTypeImpl(typ types.Type, visited map[*types.TypeName]bool) {
|
||||
func (imports *ImportMap) addTypeImpl(typ types.Type, visited *typeutil.Map) {
|
||||
collector := imports.collector
|
||||
if collector == nil {
|
||||
panic("AddType called on ImportMap with nil importing package")
|
||||
panic("AddType called on ImportMap with nil collector")
|
||||
}
|
||||
|
||||
for { // Avoid recursion where possible.
|
||||
switch t := typ.(type) {
|
||||
case *types.Alias, *types.Named:
|
||||
obj := typ.(interface{ Obj() *types.TypeName }).Obj()
|
||||
if visited[obj] {
|
||||
if visited.Set(typ, true) != nil {
|
||||
// Break type cycles.
|
||||
return
|
||||
}
|
||||
visited[obj] = true
|
||||
|
||||
obj := typ.(interface{ Obj() *types.TypeName }).Obj()
|
||||
if obj.Pkg() == nil {
|
||||
// Ignore universe type.
|
||||
return
|
||||
@ -155,7 +157,7 @@ func (imports *ImportMap) addTypeImpl(typ types.Type, visited map[*types.TypeNam
|
||||
// Import parent package.
|
||||
imports.Add(collector.Package(obj.Pkg()))
|
||||
|
||||
instance, _ := t.(interface{ TypeArgs() *types.TypeList })
|
||||
instance, _ := typ.(interface{ TypeArgs() *types.TypeList })
|
||||
if instance != nil {
|
||||
// Record type argument dependencies.
|
||||
if targs := instance.TypeArgs(); targs != nil {
|
||||
@ -170,25 +172,29 @@ func (imports *ImportMap) addTypeImpl(typ types.Type, visited map[*types.TypeNam
|
||||
return
|
||||
}
|
||||
|
||||
if _, isAlias := t.(*types.Alias); isAlias {
|
||||
if _, isAlias := typ.(*types.Alias); isAlias {
|
||||
// Aliased type might be needed during
|
||||
// JS value creation and initialisation.
|
||||
typ = types.Unalias(typ)
|
||||
break
|
||||
}
|
||||
|
||||
if IsClass(typ) || IsString(typ) || IsAny(typ) {
|
||||
if IsClass(typ) || IsAny(typ) || IsStringAlias(typ) {
|
||||
return
|
||||
}
|
||||
|
||||
// If named type does not map to a class, string or unknown type,
|
||||
// If named type does not map to a class, unknown type or string,
|
||||
// its underlying type may be needed during JS value creation.
|
||||
typ = typ.Underlying()
|
||||
|
||||
case *types.Basic:
|
||||
if t.Info()&types.IsComplex != 0 {
|
||||
// Complex types are not supported by encoding/json
|
||||
collector.logger.Warningf("complex types are not supported by encoding/json")
|
||||
switch {
|
||||
case t.Info()&(types.IsBoolean|types.IsInteger|types.IsUnsigned|types.IsFloat|types.IsString) != 0:
|
||||
break
|
||||
case t.Info()&types.IsComplex != 0:
|
||||
collector.logger.Warningf("package %s: complex types are not supported by encoding/json", imports.Self)
|
||||
default:
|
||||
collector.logger.Warningf("package %s: unknown basic type %s: please report this to Wails maintainers", imports.Self, typ)
|
||||
}
|
||||
return
|
||||
|
||||
@ -196,32 +202,40 @@ func (imports *ImportMap) addTypeImpl(typ types.Type, visited map[*types.TypeNam
|
||||
typ = typ.(interface{ Elem() types.Type }).Elem()
|
||||
|
||||
case *types.Chan:
|
||||
collector.logger.Warningf("channel types are not supported by encoding/json")
|
||||
collector.logger.Warningf("package %s: channel types are not supported by encoding/json", imports.Self)
|
||||
return
|
||||
|
||||
case *types.Map:
|
||||
if IsMapKey(t.Key()) {
|
||||
if IsString(t.Key()) {
|
||||
if IsStringAlias(t.Key()) {
|
||||
// This model type is always rendered as a string alias,
|
||||
// hence we can generate it and use it as a type for JS object keys.
|
||||
imports.addTypeImpl(t.Key(), visited)
|
||||
}
|
||||
} else if IsTypeParam(t.Key()) {
|
||||
// In some cases, type params or pointers to type params
|
||||
// may be valid as map keys, but not for all instantiations.
|
||||
// When that happens, emit a softer warning.
|
||||
collector.logger.Warningf(
|
||||
"package %s: type %s is used as a map key, but some of its instantiations might not implement encoding.TextMarshaler: this might result in runtime errors",
|
||||
imports.Self, types.TypeString(t.Key(), nil),
|
||||
)
|
||||
} else {
|
||||
collector.logger.Warningf(
|
||||
"%s is used as a map key, but does not implement encoding.TextMarshaler: this will likely result in runtime errors",
|
||||
types.TypeString(t.Key(), nil),
|
||||
"package %s: type %s is used as a map key, but does not implement encoding.TextMarshaler: this will likely result in runtime errors",
|
||||
imports.Self, types.TypeString(t.Key(), nil),
|
||||
)
|
||||
}
|
||||
|
||||
typ = t.Elem()
|
||||
|
||||
case *types.Signature:
|
||||
collector.logger.Warningf("function types are not supported by encoding/json")
|
||||
collector.logger.Warningf("package %s: function types are not supported by encoding/json", imports.Self)
|
||||
return
|
||||
|
||||
case *types.Struct:
|
||||
if t.NumFields() == 0 {
|
||||
// Empty struct.
|
||||
if t.NumFields() == 0 || MaybeJSONMarshaler(typ) != NonMarshaler || MaybeTextMarshaler(typ) != NonMarshaler {
|
||||
// Struct is empty, or marshals to custom JSON (any) or string.
|
||||
return
|
||||
}
|
||||
|
||||
@ -246,7 +260,7 @@ func (imports *ImportMap) addTypeImpl(typ types.Type, visited map[*types.TypeNam
|
||||
return
|
||||
|
||||
default:
|
||||
collector.logger.Warningf("unknown type %s: please report this to Wails maintainers", typ)
|
||||
collector.logger.Warningf("package %s: unknown type %s: please report this to Wails maintainers", imports.Self, typ)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -10,13 +10,13 @@ import (
|
||||
//
|
||||
// When obtained through a call to [PackageInfo.Index],
|
||||
// each service and model appears at most once;
|
||||
// services are sorted by name;
|
||||
// exported models precede all unexported ones
|
||||
// and both ranges are sorted by name.
|
||||
// services and models are sorted
|
||||
// by internal property (all exported first), then by name.
|
||||
type PackageIndex struct {
|
||||
Package *PackageInfo
|
||||
|
||||
Services []*ServiceInfo
|
||||
Services []*ServiceInfo
|
||||
HasExportedServices bool // If true, there is at least one exported service.
|
||||
|
||||
Models []*ModelInfo
|
||||
HasExportedModels bool // If true, there is at least one exported model.
|
||||
@ -47,9 +47,10 @@ func (info *PackageInfo) Index(TS bool) (index *PackageIndex) {
|
||||
for _, value := range info.services.Range {
|
||||
service := value.(*ServiceInfo)
|
||||
if !service.IsEmpty() {
|
||||
if service.Object().Exported() {
|
||||
// Publish non-internal service on the local index.
|
||||
index.Services = append(index.Services, service)
|
||||
index.Services = append(index.Services, service)
|
||||
// Mark presence of exported services
|
||||
if !service.Internal {
|
||||
index.HasExportedServices = true
|
||||
}
|
||||
// Update service stats.
|
||||
stats.NumServices++
|
||||
@ -57,12 +58,21 @@ func (info *PackageInfo) Index(TS bool) (index *PackageIndex) {
|
||||
}
|
||||
}
|
||||
|
||||
// Sort services by name.
|
||||
slices.SortFunc(index.Services, func(b1 *ServiceInfo, b2 *ServiceInfo) int {
|
||||
if b1 == b2 {
|
||||
// Sort services by internal property (exported first), then by name.
|
||||
slices.SortFunc(index.Services, func(s1 *ServiceInfo, s2 *ServiceInfo) int {
|
||||
if s1 == s2 {
|
||||
return 0
|
||||
}
|
||||
return strings.Compare(b1.Name, b2.Name)
|
||||
|
||||
if s1.Internal != s2.Internal {
|
||||
if s1.Internal {
|
||||
return 1
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Compare(s1.Name, s2.Name)
|
||||
})
|
||||
|
||||
// Gather models.
|
||||
@ -70,7 +80,7 @@ func (info *PackageInfo) Index(TS bool) (index *PackageIndex) {
|
||||
model := value.(*ModelInfo)
|
||||
index.Models = append(index.Models, model)
|
||||
// Mark presence of exported models
|
||||
if model.Object().Exported() {
|
||||
if !model.Internal {
|
||||
index.HasExportedModels = true
|
||||
}
|
||||
// Update model stats.
|
||||
@ -81,18 +91,17 @@ func (info *PackageInfo) Index(TS bool) (index *PackageIndex) {
|
||||
}
|
||||
}
|
||||
|
||||
// Sort models by exported property (exported first), then by name.
|
||||
// Sort models by internal property (exported first), then by name.
|
||||
slices.SortFunc(index.Models, func(m1 *ModelInfo, m2 *ModelInfo) int {
|
||||
if m1 == m2 {
|
||||
return 0
|
||||
}
|
||||
|
||||
m1e, m2e := m1.Object().Exported(), m2.Object().Exported()
|
||||
if m1e != m2e {
|
||||
if m1e {
|
||||
return -1
|
||||
} else {
|
||||
if m1.Internal != m2.Internal {
|
||||
if m1.Internal {
|
||||
return 1
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,5 +117,5 @@ func (info *PackageInfo) Index(TS bool) (index *PackageIndex) {
|
||||
// IsEmpty returns true if the given index
|
||||
// contains no data for the selected language.
|
||||
func (index *PackageIndex) IsEmpty() bool {
|
||||
return len(index.Package.Injections) == 0 && len(index.Services) == 0 && len(index.Models) == 0
|
||||
return !index.HasExportedServices && !index.HasExportedModels && len(index.Package.Injections) == 0
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package collect
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"go/ast"
|
||||
"go/constant"
|
||||
"go/types"
|
||||
"slices"
|
||||
@ -20,6 +21,10 @@ type (
|
||||
ModelInfo struct {
|
||||
*TypeInfo
|
||||
|
||||
// Internal records whether the model
|
||||
// should be exported by the index file.
|
||||
Internal bool
|
||||
|
||||
// Imports records dependencies for this model.
|
||||
Imports *ImportMap
|
||||
|
||||
@ -39,6 +44,13 @@ type (
|
||||
// TypeParams records type parameter names for generic models.
|
||||
TypeParams []string
|
||||
|
||||
// Predicates caches the value of all type predicates for this model.
|
||||
//
|
||||
// WARN: whenever working with a generic uninstantiated model type,
|
||||
// use these instead of invoking predicate functions,
|
||||
// which may incur a large performance penalty.
|
||||
Predicates Predicates
|
||||
|
||||
collector *Collector
|
||||
once sync.Once
|
||||
}
|
||||
@ -49,6 +61,19 @@ type (
|
||||
*StructField
|
||||
*FieldInfo
|
||||
}
|
||||
|
||||
// Predicates caches the value of all type predicates.
|
||||
Predicates struct {
|
||||
IsJSONMarshaler MarshalerKind
|
||||
MaybeJSONMarshaler MarshalerKind
|
||||
IsTextMarshaler MarshalerKind
|
||||
MaybeTextMarshaler MarshalerKind
|
||||
IsMapKey bool
|
||||
IsTypeParam bool
|
||||
IsStringAlias bool
|
||||
IsClass bool
|
||||
IsAny bool
|
||||
}
|
||||
)
|
||||
|
||||
func newModelInfo(collector *Collector, obj *types.TypeName) *ModelInfo {
|
||||
@ -113,15 +138,24 @@ func (info *ModelInfo) Collect() *ModelInfo {
|
||||
// Setup fallback type.
|
||||
info.Type = types.Universe.Lookup("any").Type()
|
||||
|
||||
// Retrieve type denotation and skip alias chains.
|
||||
def := info.TypeInfo.Def
|
||||
// Record whether the model should be exported.
|
||||
info.Internal = !obj.Exported()
|
||||
|
||||
// Check marshalers and detect enums.
|
||||
var constants []*types.Const
|
||||
// Parse directives.
|
||||
for _, doc := range []*ast.CommentGroup{info.Doc, info.Decl.Doc} {
|
||||
if doc == nil {
|
||||
continue
|
||||
}
|
||||
for _, comment := range doc.List {
|
||||
if IsDirective(comment.Text, "internal") {
|
||||
info.Internal = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Record type parameter names.
|
||||
var isGeneric bool
|
||||
if generic, ok := obj.Type().(interface{ TypeParams() *types.TypeParamList }); ok {
|
||||
// Record type parameter names.
|
||||
if generic, ok := typ.(interface{ TypeParams() *types.TypeParamList }); ok {
|
||||
tparams := generic.TypeParams()
|
||||
isGeneric = tparams != nil
|
||||
|
||||
@ -133,59 +167,116 @@ func (info *ModelInfo) Collect() *ModelInfo {
|
||||
}
|
||||
}
|
||||
|
||||
if _, isNamed := obj.Type().(*types.Named); isNamed {
|
||||
// Model is a named type.
|
||||
// Check whether it implements marshaler interfaces
|
||||
// or has defined constants.
|
||||
// Precompute predicates.
|
||||
// Preinstantiate typ to avoid repeated instantiations in predicate code.
|
||||
ityp := instantiate(typ)
|
||||
info.Predicates = Predicates{
|
||||
IsJSONMarshaler: IsJSONMarshaler(ityp),
|
||||
MaybeJSONMarshaler: MaybeJSONMarshaler(ityp),
|
||||
IsTextMarshaler: IsTextMarshaler(ityp),
|
||||
MaybeTextMarshaler: MaybeTextMarshaler(ityp),
|
||||
IsMapKey: IsMapKey(ityp),
|
||||
IsTypeParam: IsTypeParam(ityp),
|
||||
IsStringAlias: IsStringAlias(ityp),
|
||||
IsClass: IsClass(ityp),
|
||||
IsAny: IsAny(ityp),
|
||||
}
|
||||
|
||||
if IsAny(typ) {
|
||||
// Type marshals to a custom value of unknown shape.
|
||||
return
|
||||
} else if MaybeTextMarshaler(typ) {
|
||||
// Type marshals to a custom string of unknown shape.
|
||||
info.Type = types.Typ[types.String]
|
||||
return
|
||||
} else if isGeneric && !collector.options.UseInterfaces && IsClass(typ) {
|
||||
// Generic classes cannot be defined in terms of other generic classes.
|
||||
// That would break class creation code,
|
||||
// and I (@fbbdev) couldn't find any other satisfying workaround.
|
||||
def = typ.Underlying()
|
||||
}
|
||||
var def types.Type
|
||||
var constants []*types.Const
|
||||
|
||||
// Test for enums (excluding generic types).
|
||||
basic, ok := typ.Underlying().(*types.Basic)
|
||||
if ok && !isGeneric && basic.Info()&types.IsConstType != 0 && basic.Info()&types.IsComplex == 0 {
|
||||
// Named type is defined as a representable constant type:
|
||||
// look for defined constants of that named type.
|
||||
for _, name := range obj.Pkg().Scope().Names() {
|
||||
if cnst, ok := obj.Pkg().Scope().Lookup(name).(*types.Const); ok {
|
||||
if cnst.Val().Kind() != constant.Unknown && types.Identical(cnst.Type(), typ) {
|
||||
constants = append(constants, cnst)
|
||||
switch t := typ.(type) {
|
||||
case *types.Alias:
|
||||
// Model is an alias: take rhs as definition.
|
||||
// It is important not to skip alias chains with [types.Unalias]
|
||||
// because in doing so we could end up with a private type from another package.
|
||||
def = t.Rhs()
|
||||
|
||||
// Test for constants with alias type,
|
||||
// but only when non-generic alias resolves to a basic type
|
||||
// (hence not to e.g. a named type).
|
||||
if basic, ok := types.Unalias(def).(*types.Basic); ok {
|
||||
if !isGeneric && basic.Info()&types.IsConstType != 0 && basic.Info()&types.IsComplex == 0 {
|
||||
// Non-generic alias resolves to a representable constant type:
|
||||
// look for defined constants whose type is exactly the alias typ.
|
||||
for _, name := range obj.Pkg().Scope().Names() {
|
||||
if cnst, ok := obj.Pkg().Scope().Lookup(name).(*types.Const); ok {
|
||||
alias, isAlias := cnst.Type().(*types.Alias)
|
||||
if isAlias && cnst.Val().Kind() != constant.Unknown && alias.Obj() == t.Obj() {
|
||||
constants = append(constants, cnst)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case *types.Named:
|
||||
// Model is a named type:
|
||||
// jump directly to underlying type to match go semantics,
|
||||
// i.e. do not render named types as aliases for other named types.
|
||||
def = typ.Underlying()
|
||||
|
||||
// Check whether it implements marshaler interfaces or has defined constants.
|
||||
if info.Predicates.MaybeJSONMarshaler != NonMarshaler {
|
||||
// Type marshals to a custom value of unknown shape.
|
||||
// If it has explicit custom marshaling logic, render it as any;
|
||||
// otherwise, delegate to the underlying type that must be the actual [json.Marshaler].
|
||||
if info.Predicates.MaybeJSONMarshaler == ExplicitMarshaler {
|
||||
return
|
||||
}
|
||||
} else if info.Predicates.MaybeTextMarshaler != NonMarshaler {
|
||||
// Type marshals to a custom string of unknown shape.
|
||||
// If it has explicit custom marshaling logic, render it as string;
|
||||
// otherwise, delegate to the underlying type that must be the actual [encoding.TextMarshaler].
|
||||
//
|
||||
// One exception must be made for situations
|
||||
// where the underlying type is a [json.Marshaler] but the model is not:
|
||||
// in that case, we cannot delegate to the underlying type either.
|
||||
// Note that in such a case the underlying type is never a pointer or interface,
|
||||
// because those cannot have explicitly defined methods,
|
||||
// hence it would not possible for the model not to be a [json.Marshaler]
|
||||
// while the underlying type is.
|
||||
if info.Predicates.MaybeTextMarshaler == ExplicitMarshaler || MaybeJSONMarshaler(def) != NonMarshaler {
|
||||
info.Type = types.Typ[types.String]
|
||||
return
|
||||
}
|
||||
} else if basic, ok := def.Underlying().(*types.Basic); ok {
|
||||
// Test for enums (excluding marshalers and generic types).
|
||||
if !isGeneric && basic.Info()&types.IsConstType != 0 && basic.Info()&types.IsComplex == 0 {
|
||||
// Named type is defined as a representable constant type:
|
||||
// look for defined constants of that named type.
|
||||
for _, name := range obj.Pkg().Scope().Names() {
|
||||
if cnst, ok := obj.Pkg().Scope().Lookup(name).(*types.Const); ok {
|
||||
if cnst.Val().Kind() != constant.Unknown && types.Identical(cnst.Type(), typ) {
|
||||
constants = append(constants, cnst)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
panic("model has unknown object kind (neither alias nor named type)")
|
||||
}
|
||||
|
||||
// Handle struct types.
|
||||
strct, isStruct := def.(*types.Struct)
|
||||
if isStruct && info.Predicates.MaybeJSONMarshaler == NonMarshaler && info.Predicates.MaybeTextMarshaler == NonMarshaler {
|
||||
// Def is struct and model is not a marshaler:
|
||||
// collect information about struct fields.
|
||||
info.collectStruct(strct)
|
||||
info.Type = nil
|
||||
return
|
||||
}
|
||||
|
||||
// Record required imports.
|
||||
info.Imports.AddType(def)
|
||||
|
||||
// Handle enum types.
|
||||
// constants slice is always empty for aliases.
|
||||
// constants slice is always empty for structs, marshalers.
|
||||
if len(constants) > 0 {
|
||||
// Collect information about enum values.
|
||||
info.collectEnum(constants)
|
||||
info.Type = def
|
||||
return
|
||||
}
|
||||
|
||||
// Handle struct types.
|
||||
strct, isStruct := def.(*types.Struct)
|
||||
if isStruct {
|
||||
// Collect information about struct fields.
|
||||
info.collectStruct(strct)
|
||||
info.Type = nil
|
||||
return
|
||||
}
|
||||
|
||||
// That's all, folks. Render as a TS alias.
|
||||
@ -265,6 +356,9 @@ func (info *ModelInfo) collectStruct(strct *types.Struct) {
|
||||
|
||||
// Collect fields.
|
||||
for i, field := range structInfo.Fields {
|
||||
// Record required imports.
|
||||
info.Imports.AddType(field.Type)
|
||||
|
||||
fields[i] = &ModelFieldInfo{
|
||||
StructField: field,
|
||||
FieldInfo: collector.Field(field.Object).Collect(),
|
||||
|
478
v3/internal/generator/collect/predicates.go
Normal file
478
v3/internal/generator/collect/predicates.go
Normal file
@ -0,0 +1,478 @@
|
||||
package collect
|
||||
|
||||
// This file gathers functions that test useful properties of model types.
|
||||
// The rationale for the way things are handled here
|
||||
// is given in the example file found at ./_reference/json_marshaler_behaviour.go
|
||||
|
||||
import (
|
||||
"go/token"
|
||||
"go/types"
|
||||
"iter"
|
||||
|
||||
"golang.org/x/exp/typeparams"
|
||||
)
|
||||
|
||||
// Cached interface types.
|
||||
var (
|
||||
ifaceTextMarshaler = types.NewInterfaceType([]*types.Func{
|
||||
types.NewFunc(token.NoPos, nil, "MarshalText",
|
||||
types.NewSignatureType(nil, nil, nil, types.NewTuple(), types.NewTuple(
|
||||
types.NewParam(token.NoPos, nil, "", types.NewSlice(types.Universe.Lookup("byte").Type())),
|
||||
types.NewParam(token.NoPos, nil, "", types.Universe.Lookup("error").Type()),
|
||||
), false)),
|
||||
}, nil).Complete()
|
||||
|
||||
ifaceJSONMarshaler = types.NewInterfaceType([]*types.Func{
|
||||
types.NewFunc(token.NoPos, nil, "MarshalJSON",
|
||||
types.NewSignatureType(nil, nil, nil, types.NewTuple(), types.NewTuple(
|
||||
types.NewParam(token.NoPos, nil, "", types.NewSlice(types.Universe.Lookup("byte").Type())),
|
||||
types.NewParam(token.NoPos, nil, "", types.Universe.Lookup("error").Type()),
|
||||
), false)),
|
||||
}, nil).Complete()
|
||||
)
|
||||
|
||||
// MarshalerKind values describe
|
||||
// whether and how a type implements a marshaler interface.
|
||||
// For any one of the two marshaler interfaces, a type is
|
||||
// - a NonMarshaler if it does not implement it;
|
||||
// - an ImplicitMarshaler if it inherits the implementation from its underlying type;
|
||||
// - an ExplicitMarshaler if it defines the relevant method explicitly.
|
||||
type MarshalerKind byte
|
||||
|
||||
const (
|
||||
NonMarshaler MarshalerKind = iota
|
||||
ImplicitMarshaler
|
||||
ExplicitMarshaler
|
||||
)
|
||||
|
||||
// termlist returns an iterator over the normalised term list of the given type.
|
||||
// If typ is invalid or has an empty type set, termlist returns the empty sequence.
|
||||
// If typ has an empty term list
|
||||
// then termlist returns a sequence with just one element: the type itself.
|
||||
//
|
||||
// TODO: replace with new term set API once Go 1.25 is out.
|
||||
// See go.dev/issue/61013
|
||||
func termlist(typ types.Type) iter.Seq[*typeparams.Term] {
|
||||
terms, err := typeparams.NormalTerms(types.Unalias(typ))
|
||||
return func(yield func(*typeparams.Term) bool) {
|
||||
if err == nil && len(terms) == 0 {
|
||||
yield(typeparams.NewTerm(false, typ))
|
||||
} else {
|
||||
for _, term := range terms {
|
||||
if !yield(term) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// instantiate instantiates typ if it is an uninstantiated generic type
|
||||
// using its own type parameters as arguments in order to preserve genericity.
|
||||
//
|
||||
// If typ is not generic or already instantiated, it is returned as is.
|
||||
// If typ is not an alias, then the returned type is not an alias either.
|
||||
func instantiate(typ types.Type) types.Type {
|
||||
if t, ok := typ.(interface {
|
||||
TypeParams() *types.TypeParamList
|
||||
TypeArgs() *types.TypeList
|
||||
}); ok && t.TypeParams() != nil && t.TypeArgs() == nil {
|
||||
args := make([]types.Type, t.TypeParams().Len())
|
||||
for i := range args {
|
||||
args[i] = t.TypeParams().At(i)
|
||||
}
|
||||
|
||||
typ, _ = types.Instantiate(nil, typ, args, false)
|
||||
}
|
||||
|
||||
return typ
|
||||
}
|
||||
|
||||
// isMarshaler checks whether the given type
|
||||
// implements one of the two marshaler interfaces,
|
||||
// and whether it implements it explicitly,
|
||||
// i.e. by defining the relevant method directly
|
||||
// instead of inheriting it from the underlying type.
|
||||
//
|
||||
// If addressable is true, it checks both pointer and non-pointer receivers.
|
||||
//
|
||||
// The behaviour of isMarshaler is unspecified
|
||||
// if marshaler is not one of [json.Marshaler] or [encoding.TextMarshaler].
|
||||
func isMarshaler(typ types.Type, marshaler *types.Interface, addressable bool, visited map[*types.TypeName]MarshalerKind) MarshalerKind {
|
||||
// Follow alias chain and instantiate if necessary.
|
||||
//
|
||||
// types.Implements does not handle generics,
|
||||
// hence when typ is generic it must be instantiated.
|
||||
//
|
||||
// Instantiation operations may incur a large performance penalty and are usually cached,
|
||||
// but doing so here would entail some complex global state and a potential memory leak.
|
||||
// Because typ should be generic only during model collection,
|
||||
// it should be enough to cache the result of marshaler queries for models.
|
||||
typ = instantiate(types.Unalias(typ))
|
||||
|
||||
// Invariant: at this point, typ is not an alias.
|
||||
|
||||
if typ == types.Typ[types.Invalid] {
|
||||
// Do not pass invalid types to [types.Implements].
|
||||
return NonMarshaler
|
||||
}
|
||||
|
||||
result := types.Implements(typ, marshaler)
|
||||
|
||||
ptr, isPtr := typ.Underlying().(*types.Pointer)
|
||||
|
||||
if !result && addressable && !isPtr {
|
||||
result = types.Implements(types.NewPointer(typ), marshaler)
|
||||
}
|
||||
|
||||
named, isNamed := typ.(*types.Named)
|
||||
|
||||
if result {
|
||||
// Check whether marshaler method is implemented explicitly on a named type.
|
||||
if isNamed {
|
||||
method := marshaler.Method(0).Name()
|
||||
for i := range named.NumMethods() {
|
||||
if named.Method(i).Name() == method {
|
||||
return ExplicitMarshaler
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ImplicitMarshaler
|
||||
}
|
||||
|
||||
// Fast path: named types that fail the [types.Implements] test cannot be marshalers.
|
||||
//
|
||||
// WARN: currently typeparams cannot be used on the rhs of a named type declaration.
|
||||
// If that changes in the future,
|
||||
// this guard will become essential for correctness,
|
||||
// not just a shortcut.
|
||||
if isNamed {
|
||||
return NonMarshaler
|
||||
}
|
||||
|
||||
// Unwrap at most one pointer and follow alias chain.
|
||||
if isPtr {
|
||||
typ = types.Unalias(ptr.Elem())
|
||||
}
|
||||
|
||||
// Invariant: at this point, typ is not an alias.
|
||||
|
||||
// Type parameters require special handling:
|
||||
// iterate over their term list and treat them as marshalers
|
||||
// if so are all their potential instantiations.
|
||||
|
||||
tp, ok := typ.(*types.TypeParam)
|
||||
if !ok {
|
||||
return NonMarshaler
|
||||
}
|
||||
|
||||
// Init cycle detection/deduplication map.
|
||||
if visited == nil {
|
||||
visited = make(map[*types.TypeName]MarshalerKind)
|
||||
}
|
||||
|
||||
// Type params cannot be embedded in constraints directly,
|
||||
// but they can be embedded as pointer terms.
|
||||
//
|
||||
// When we hit that kind of cycle,
|
||||
// we can err towards it being a marshaler:
|
||||
// such a constraint is meaningless anyways,
|
||||
// as no type can be simultaneously a pointer to itself.
|
||||
//
|
||||
// Therefore, we iterate the type set
|
||||
// only for unvisited pointers-to-typeparams,
|
||||
// and return the current best guess
|
||||
// for those we have already visited.
|
||||
//
|
||||
// WARN: there has been some talk
|
||||
// of allowing type parameters as embedded fields/terms.
|
||||
// That might make our lives miserable here.
|
||||
// The spec must be monitored for changes in that regard.
|
||||
if isPtr {
|
||||
if kind, ok := visited[tp.Obj()]; ok {
|
||||
return kind
|
||||
}
|
||||
}
|
||||
|
||||
// Initialise kind to explicit marshaler, then decrease as needed.
|
||||
kind := ExplicitMarshaler
|
||||
|
||||
if isPtr {
|
||||
// Pointers are never explicit marshalers.
|
||||
kind = ImplicitMarshaler
|
||||
// Mark pointer-to-typeparam as visited and init current best guess.
|
||||
visited[tp.Obj()] = kind
|
||||
}
|
||||
|
||||
// Iterate term list.
|
||||
for term := range termlist(tp) {
|
||||
ttyp := types.Unalias(term.Type())
|
||||
|
||||
// Reject if tp has a tilde or invalid element in its term list
|
||||
// or has a method-only constraint.
|
||||
//
|
||||
// Valid tilde terms
|
||||
// can always be satisfied by named types that hide their methods
|
||||
// hence fail in general to implement the required interface.
|
||||
if term.Tilde() || ttyp == types.Typ[types.Invalid] || ttyp == tp {
|
||||
kind = NonMarshaler
|
||||
break
|
||||
}
|
||||
|
||||
// Propagate the presence of a wrapping pointer.
|
||||
if isPtr {
|
||||
ttyp = types.NewPointer(ttyp)
|
||||
}
|
||||
|
||||
kind = min(kind, isMarshaler(ttyp, marshaler, addressable && !isPtr, visited))
|
||||
if kind == NonMarshaler {
|
||||
// We can stop here as we've reached the minimum [MarshalerKind].
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Store final response for pointer-to-typeparam.
|
||||
if isPtr {
|
||||
visited[tp.Obj()] = kind
|
||||
}
|
||||
|
||||
return kind
|
||||
}
|
||||
|
||||
// IsTextMarshaler queries whether and how the given type
|
||||
// implements the [encoding.TextMarshaler] interface.
|
||||
func IsTextMarshaler(typ types.Type) MarshalerKind {
|
||||
return isMarshaler(typ, ifaceTextMarshaler, false, nil)
|
||||
}
|
||||
|
||||
// MaybeTextMarshaler queries whether and how the given type
|
||||
// implements the [encoding.TextMarshaler] interface for at least one receiver form.
|
||||
func MaybeTextMarshaler(typ types.Type) MarshalerKind {
|
||||
return isMarshaler(typ, ifaceTextMarshaler, true, nil)
|
||||
}
|
||||
|
||||
// IsJSONMarshaler queries whether and how the given type
|
||||
// implements the [json.Marshaler] interface.
|
||||
func IsJSONMarshaler(typ types.Type) MarshalerKind {
|
||||
return isMarshaler(typ, ifaceJSONMarshaler, false, nil)
|
||||
}
|
||||
|
||||
// MaybeJSONMarshaler queries whether and how the given type
|
||||
// implements the [json.Marshaler] interface for at least one receiver form.
|
||||
func MaybeJSONMarshaler(typ types.Type) MarshalerKind {
|
||||
return isMarshaler(typ, ifaceJSONMarshaler, true, nil)
|
||||
}
|
||||
|
||||
// IsMapKey returns true if the given type
|
||||
// is accepted as a map key by encoding/json.
|
||||
func IsMapKey(typ types.Type) bool {
|
||||
// Iterate over type set and return true if all elements are valid.
|
||||
//
|
||||
// We cannot simply delegate to [IsTextMarshaler] here
|
||||
// because a union of some basic terms and some TextMarshalers
|
||||
// might still be acceptable.
|
||||
//
|
||||
// NOTE: If typ is not a typeparam or constraint, termlist returns just typ itself.
|
||||
// If typ has an empty type set, it's safe to return true
|
||||
// because the map cannot be instantiated anyways.
|
||||
for term := range termlist(typ) {
|
||||
ttyp := types.Unalias(term.Type())
|
||||
|
||||
// Types whose underlying type is a signed/unsigned integer or a string
|
||||
// are always acceptable, whether they are marshalers or not.
|
||||
if basic, ok := ttyp.Underlying().(*types.Basic); ok {
|
||||
if basic.Info()&(types.IsInteger|types.IsUnsigned|types.IsString) != 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Valid tilde terms
|
||||
// can always be satisfied by named types that hide their methods
|
||||
// hence fail in general to implement the required interface.
|
||||
// For example one could have:
|
||||
//
|
||||
// type NotAKey struct{ encoding.TextMarshaler }
|
||||
// func (NotAKey) MarshalText() int { ... }
|
||||
//
|
||||
// which satisfies ~struct{ encoding.TextMarshaler }
|
||||
// but is not itself a TextMarshaler.
|
||||
//
|
||||
// It might still be the case that the constraint
|
||||
// requires explicitly a marshaling method,
|
||||
// hence we perform one last check on typ.
|
||||
//
|
||||
// For example, we reject interface{ ~struct{ ... } }
|
||||
// but still accept interface{ ~struct{ ... }; MarshalText() ([]byte, error) }
|
||||
//
|
||||
// All other cases are only acceptable
|
||||
// if the type implements [encoding.TextMarshaler] in non-addressable mode.
|
||||
if term.Tilde() || IsTextMarshaler(ttyp) == NonMarshaler {
|
||||
// When some term fails, test the input typ itself,
|
||||
// but only if it has not been tested already.
|
||||
//
|
||||
// Note that when term.Tilde() is true
|
||||
// then it is always the case that typ != term.Type(),
|
||||
// because cyclic constraints are not allowed
|
||||
// and naked type parameters cannot occur in type unions.
|
||||
return typ != term.Type() && IsTextMarshaler(typ) != NonMarshaler
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// IsTypeParam returns true when the given type
|
||||
// is either a TypeParam or a pointer to a TypeParam.
|
||||
func IsTypeParam(typ types.Type) bool {
|
||||
switch t := types.Unalias(typ).(type) {
|
||||
case *types.TypeParam:
|
||||
return true
|
||||
case *types.Pointer:
|
||||
_, ok := types.Unalias(t.Elem()).(*types.TypeParam)
|
||||
return ok
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// IsStringAlias returns true when
|
||||
// either typ will be rendered to JS/TS as an alias for the TS type `string`,
|
||||
// or typ itself (not its underlying type) is a pointer
|
||||
// whose element type satisfies the property described above.
|
||||
//
|
||||
// This predicate is only safe to use either with map keys,
|
||||
// where pointers are treated in an ad-hoc way by [json.Marshal],
|
||||
// or when typ IS ALREADY KNOWN to be either [types.Alias] or [types.Named].
|
||||
//
|
||||
// Otherwise, the result might be incorrect:
|
||||
// IsStringAlias MUST NOT be used to check
|
||||
// whether an arbitrary instance of [types.Type]
|
||||
// renders as a JS/TS string type.
|
||||
//
|
||||
// Notice that IsStringAlias returns false for all type parameters:
|
||||
// detecting those that must be always instantiated as string aliases
|
||||
// is technically possible, but very difficult.
|
||||
func IsStringAlias(typ types.Type) bool {
|
||||
// Unwrap at most one pointer.
|
||||
// NOTE: do not unalias typ before testing:
|
||||
// aliases whose underlying type is a pointer
|
||||
// are never rendered as strings.
|
||||
if ptr, ok := typ.(*types.Pointer); ok {
|
||||
typ = ptr.Elem()
|
||||
}
|
||||
|
||||
switch typ.(type) {
|
||||
case *types.Alias, *types.Named:
|
||||
// Aliases and named types might be rendered as string aliases.
|
||||
default:
|
||||
// Not a model type, hence not an alias.
|
||||
return false
|
||||
}
|
||||
|
||||
// Skip pointer and interface types: they are always nullable
|
||||
// and cannot have any explicitly defined methods.
|
||||
// This takes care of rejecting type params as well,
|
||||
// since their underlying type is guaranteed to be an interface.
|
||||
switch typ.Underlying().(type) {
|
||||
case *types.Pointer, *types.Interface:
|
||||
return false
|
||||
}
|
||||
|
||||
// Follow alias chain.
|
||||
typ = types.Unalias(typ)
|
||||
|
||||
// Aliases of the basic string type are rendered as strings.
|
||||
if basic, ok := typ.(*types.Basic); ok {
|
||||
return basic.Info()&types.IsString != 0
|
||||
}
|
||||
|
||||
// json.Marshalers can only be rendered as any.
|
||||
// TextMarshalers that aren't json.Marshalers render as strings.
|
||||
if MaybeJSONMarshaler(typ) != NonMarshaler {
|
||||
return false
|
||||
} else if MaybeTextMarshaler(typ) != NonMarshaler {
|
||||
return true
|
||||
}
|
||||
|
||||
// Named types whose underlying type is a string are rendered as strings.
|
||||
basic, ok := typ.Underlying().(*types.Basic)
|
||||
return ok && basic.Info()&types.IsString != 0
|
||||
}
|
||||
|
||||
// IsClass returns true if the given type will be rendered
|
||||
// as a JS/TS model class (or interface).
|
||||
func IsClass(typ types.Type) bool {
|
||||
// Follow alias chain.
|
||||
typ = types.Unalias(typ)
|
||||
|
||||
if _, isNamed := typ.(*types.Named); !isNamed {
|
||||
// Unnamed types are never rendered as classes.
|
||||
return false
|
||||
}
|
||||
|
||||
// Struct named types without custom marshaling are rendered as classes.
|
||||
_, isStruct := typ.Underlying().(*types.Struct)
|
||||
return isStruct && MaybeJSONMarshaler(typ) == NonMarshaler && MaybeTextMarshaler(typ) == NonMarshaler
|
||||
}
|
||||
|
||||
// IsAny returns true if the given type
|
||||
// is guaranteed to render as the TS any type or equivalent.
|
||||
//
|
||||
// It might return false negatives for generic aliases,
|
||||
// hence should only be used with instantiated types
|
||||
// or in contexts where false negatives are acceptable.
|
||||
func IsAny(typ types.Type) bool {
|
||||
// Follow alias chain.
|
||||
typ = types.Unalias(typ)
|
||||
|
||||
if MaybeJSONMarshaler(typ) != NonMarshaler {
|
||||
// If typ is either a named type, an interface, a pointer or a struct,
|
||||
// it will be rendered as (possibly an alias for) the TS any type.
|
||||
//
|
||||
// If it is a type parameter that implements json.Marshal,
|
||||
// every possible concrete instantiation will implement json.Marshal,
|
||||
// hence will be rendered as the TS any type.
|
||||
return true
|
||||
}
|
||||
|
||||
if MaybeTextMarshaler(typ) != NonMarshaler {
|
||||
// If type is either a named type, an interface, a pointer or a struct,
|
||||
// it will be rendered as (possibly an alias for)
|
||||
// the (possibly nullable) TS string type.
|
||||
//
|
||||
// If typ is a type parameter, we know at this point
|
||||
// that it does not necessarily implement json.Marshaler,
|
||||
// hence it will be possible to instantiate it in a way
|
||||
// that renders as the (possibly nullable) TS string type.
|
||||
return false
|
||||
}
|
||||
|
||||
if ptr, ok := typ.Underlying().(*types.Pointer); ok {
|
||||
// Pointers render as the union of their element type with null.
|
||||
// This is equivalent to the TS any type
|
||||
// if and only if so is the element type.
|
||||
return IsAny(ptr.Elem())
|
||||
}
|
||||
|
||||
// All types listed below have rich TS equivalents,
|
||||
// hence won't be equivalent to the TS any type.
|
||||
//
|
||||
// WARN: it is important to keep these lists explicit and up to date
|
||||
// instead of listing the unsupported types (which would be much easier).
|
||||
//
|
||||
// By doing so, IsAny will keep working correctly
|
||||
// in case future updates to the Go spec introduce new type families,
|
||||
// thus buying the maintainers some time to patch the binding generator.
|
||||
|
||||
// Retrieve underlying type.
|
||||
switch t := typ.Underlying().(type) {
|
||||
case *types.Basic:
|
||||
// Complex types are not supported.
|
||||
return t.Info()&(types.IsBoolean|types.IsInteger|types.IsUnsigned|types.IsFloat|types.IsString) == 0
|
||||
case *types.Array, *types.Slice, *types.Map, *types.Struct, *types.TypeParam:
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
@ -1,152 +0,0 @@
|
||||
package collect
|
||||
|
||||
// This file gathers functions that test useful properties of model types.
|
||||
// The rationale for the way things are handled here
|
||||
// is given in the example file found at ./_reference/json_marshaler_behaviour.go
|
||||
|
||||
import (
|
||||
"go/token"
|
||||
"go/types"
|
||||
)
|
||||
|
||||
// Cached interface types.
|
||||
var (
|
||||
ifaceTextMarshaler = types.NewInterfaceType([]*types.Func{
|
||||
types.NewFunc(token.NoPos, nil, "MarshalText",
|
||||
types.NewSignatureType(nil, nil, nil, types.NewTuple(), types.NewTuple(
|
||||
types.NewParam(token.NoPos, nil, "", types.NewSlice(types.Universe.Lookup("byte").Type())),
|
||||
types.NewParam(token.NoPos, nil, "", types.Universe.Lookup("error").Type()),
|
||||
), false)),
|
||||
}, nil).Complete()
|
||||
|
||||
ifaceJSONMarshaler = types.NewInterfaceType([]*types.Func{
|
||||
types.NewFunc(token.NoPos, nil, "MarshalJSON",
|
||||
types.NewSignatureType(nil, nil, nil, types.NewTuple(), types.NewTuple(
|
||||
types.NewParam(token.NoPos, nil, "", types.NewSlice(types.Universe.Lookup("byte").Type())),
|
||||
types.NewParam(token.NoPos, nil, "", types.Universe.Lookup("error").Type()),
|
||||
), false)),
|
||||
}, nil).Complete()
|
||||
)
|
||||
|
||||
// IsTextMarshaler tests whether the given type implements
|
||||
// the encoding.TextMarshaler interface.
|
||||
func IsTextMarshaler(typ types.Type) bool {
|
||||
return types.Implements(typ, ifaceTextMarshaler)
|
||||
}
|
||||
|
||||
// MaybeTextMarshaler tests whether the given type implements
|
||||
// the encoding.TextMarshaler interface for at least one receiver form.
|
||||
func MaybeTextMarshaler(typ types.Type) bool {
|
||||
if _, ok := types.Unalias(typ).(*types.Pointer); !ok {
|
||||
typ = types.NewPointer(typ)
|
||||
}
|
||||
return IsTextMarshaler(typ)
|
||||
}
|
||||
|
||||
// IsJSONMarshaler tests whether the given type implements
|
||||
// the json.Marshaler interface.
|
||||
func IsJSONMarshaler(typ types.Type) bool {
|
||||
return types.Implements(typ, ifaceJSONMarshaler)
|
||||
}
|
||||
|
||||
// MaybeJSONMarshaler tests whether the given type implements
|
||||
// the json.Marshaler interface for at least one receiver form.
|
||||
func MaybeJSONMarshaler(typ types.Type) bool {
|
||||
if _, ok := types.Unalias(typ).(*types.Pointer); !ok {
|
||||
typ = types.NewPointer(typ)
|
||||
}
|
||||
return IsJSONMarshaler(typ)
|
||||
}
|
||||
|
||||
// IsMapKey returns true if the given type
|
||||
// is accepted as a map key by encoding/json.
|
||||
func IsMapKey(typ types.Type) bool {
|
||||
if basic, ok := typ.Underlying().(*types.Basic); ok {
|
||||
return basic.Info()&(types.IsInteger|types.IsString) != 0
|
||||
}
|
||||
|
||||
// Other types are only accepted
|
||||
// if they implement encoding.TextMarshaler strictly as they are.
|
||||
return IsTextMarshaler(typ)
|
||||
}
|
||||
|
||||
// IsString returns true if the given type (or element type for pointers)
|
||||
// will be rendered as an alias for the TS string type.
|
||||
func IsString(typ types.Type) bool {
|
||||
// Unwrap at most one pointer.
|
||||
// NOTE: do not unalias typ before testing:
|
||||
// aliases whose underlying type is a pointer
|
||||
// are _never_ rendered as strings.
|
||||
if ptr, ok := typ.(*types.Pointer); ok {
|
||||
typ = ptr.Elem()
|
||||
}
|
||||
|
||||
switch typ.(type) {
|
||||
case *types.Alias, *types.Named:
|
||||
// Aliases and named types might be rendered as string aliases.
|
||||
default:
|
||||
// Not a model type.
|
||||
return false
|
||||
}
|
||||
|
||||
// Follow alias chain.
|
||||
typ = types.Unalias(typ)
|
||||
|
||||
if basic, ok := typ.(*types.Basic); ok {
|
||||
// Test whether basic type is a string.
|
||||
return basic.Info()&types.IsString != 0
|
||||
}
|
||||
|
||||
// JSONMarshalers can only be rendered as any.
|
||||
// TextMarshalers that aren't JSONMarshalers render as strings.
|
||||
if MaybeJSONMarshaler(typ) {
|
||||
return false
|
||||
} else if MaybeTextMarshaler(typ) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Named types whose underlying type is a string are rendered as strings.
|
||||
basic, ok := typ.Underlying().(*types.Basic)
|
||||
return ok && basic.Info()&types.IsString != 0
|
||||
}
|
||||
|
||||
// IsClass returns true if the given type will be rendered
|
||||
// as a JS/TS model class (or interface).
|
||||
func IsClass(typ types.Type) bool {
|
||||
// Follow alias chain.
|
||||
typ = types.Unalias(typ)
|
||||
|
||||
if _, isNamed := typ.(*types.Named); !isNamed {
|
||||
// Unnamed types are never rendered as classes.
|
||||
return false
|
||||
}
|
||||
|
||||
// Struct named types without custom marshaling are rendered as classes.
|
||||
_, isStruct := typ.Underlying().(*types.Struct)
|
||||
return isStruct && !MaybeJSONMarshaler(typ) && !MaybeTextMarshaler(typ)
|
||||
}
|
||||
|
||||
// IsAny returns true if the given type will be rendered as a TS any type.
|
||||
func IsAny(typ types.Type) bool {
|
||||
// Follow alias chain.
|
||||
typ = types.Unalias(typ)
|
||||
|
||||
if MaybeJSONMarshaler(typ) {
|
||||
return true
|
||||
}
|
||||
|
||||
if MaybeTextMarshaler(typ) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Retrieve underlying type
|
||||
switch t := typ.Underlying().(type) {
|
||||
case *types.Basic:
|
||||
// Complex types are not supported.
|
||||
return t.Info()&types.IsComplex != 0
|
||||
case *types.Chan, *types.Signature, *types.Interface:
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
@ -22,9 +22,17 @@ type (
|
||||
ServiceInfo struct {
|
||||
*TypeInfo
|
||||
|
||||
// Internal records whether the service
|
||||
// should be exported by the index file.
|
||||
Internal bool
|
||||
|
||||
Imports *ImportMap
|
||||
Methods []*ServiceMethodInfo
|
||||
|
||||
// HasInternalMethods records whether the service
|
||||
// defines lifecycle or http server methods.
|
||||
HasInternalMethods bool
|
||||
|
||||
// Injections stores a list of JS code lines
|
||||
// that should be injected into the generated file.
|
||||
Injections []string
|
||||
@ -80,7 +88,7 @@ func (collector *Collector) Service(obj *types.TypeName) *ServiceInfo {
|
||||
func (info *ServiceInfo) IsEmpty() bool {
|
||||
// Ensure information has been collected.
|
||||
info.Collect()
|
||||
return len(info.Injections) == 0 && len(info.Methods) == 0
|
||||
return len(info.Methods) == 0 && len(info.Injections) == 0
|
||||
}
|
||||
|
||||
// Collect gathers information about the service described by its receiver.
|
||||
@ -119,7 +127,11 @@ func (info *ServiceInfo) Collect() *ServiceInfo {
|
||||
// Collect method information.
|
||||
info.Methods = make([]*ServiceMethodInfo, 0, len(mset))
|
||||
for _, sel := range mset {
|
||||
if !sel.Obj().Exported() || internalServiceMethods[sel.Obj().Name()] {
|
||||
switch {
|
||||
case internalServiceMethods[sel.Obj().Name()]:
|
||||
info.HasInternalMethods = true
|
||||
continue
|
||||
case !sel.Obj().Exported():
|
||||
// Ignore unexported and internal methods.
|
||||
continue
|
||||
}
|
||||
@ -130,13 +142,20 @@ func (info *ServiceInfo) Collect() *ServiceInfo {
|
||||
}
|
||||
}
|
||||
|
||||
// Record whether the service should be exported.
|
||||
info.Internal = !obj.Exported()
|
||||
|
||||
// Parse directives.
|
||||
for _, doc := range []*ast.CommentGroup{info.Doc, info.Decl.Doc} {
|
||||
if doc == nil {
|
||||
continue
|
||||
}
|
||||
for _, comment := range doc.List {
|
||||
if IsDirective(comment.Text, "inject") {
|
||||
switch {
|
||||
case IsDirective(comment.Text, "internal"):
|
||||
info.Internal = true
|
||||
|
||||
case IsDirective(comment.Text, "inject"):
|
||||
// Check condition.
|
||||
line, cond, err := ParseCondition(ParseDirective(comment.Text, "inject"))
|
||||
if err != nil {
|
||||
@ -217,6 +236,9 @@ func (info *ServiceInfo) collectMethod(method *types.Func) *ServiceMethodInfo {
|
||||
|
||||
for _, comment := range methodInfo.Doc.List {
|
||||
switch {
|
||||
case IsDirective(comment.Text, "ignore"):
|
||||
return nil
|
||||
|
||||
case IsDirective(comment.Text, "internal"):
|
||||
methodInfo.Internal = true
|
||||
|
||||
|
@ -193,6 +193,14 @@ func (info *StructInfo) Collect() *StructInfo {
|
||||
// or field is not structure:
|
||||
// add to field list.
|
||||
|
||||
if !info.collector.options.UseInterfaces {
|
||||
// In class mode, mark parametric fields as optional
|
||||
// because there is no way to know their default JS value in advance.
|
||||
if _, isTypeParam := types.Unalias(field.Type()).(*types.TypeParam); isTypeParam {
|
||||
optional = true
|
||||
}
|
||||
}
|
||||
|
||||
finfo := fieldData{
|
||||
StructField: &StructField{
|
||||
JsonName: name,
|
||||
@ -317,7 +325,7 @@ func parseTag(tag string) (name string, optional bool, quoted bool, visible bool
|
||||
|
||||
for _, option := range parts[1:] {
|
||||
switch option {
|
||||
case "omitempty":
|
||||
case "omitempty", "omitzero":
|
||||
optional = true
|
||||
case "string":
|
||||
quoted = true
|
||||
|
@ -22,12 +22,6 @@ type TypeInfo struct {
|
||||
Doc *ast.CommentGroup
|
||||
Decl *GroupInfo
|
||||
|
||||
// Def holds the actual denotation of the type expression
|
||||
// that defines the described type.
|
||||
// This is not the same as the underlying type,
|
||||
// which skips all intermediate aliases and named types.
|
||||
Def types.Type
|
||||
|
||||
obj *types.TypeName
|
||||
node ast.Node
|
||||
|
||||
@ -92,13 +86,8 @@ func (info *TypeInfo) Collect() *TypeInfo {
|
||||
info.Name,
|
||||
)
|
||||
|
||||
// Provide dummy group and def.
|
||||
// Provide dummy group.
|
||||
info.Decl = newGroupInfo(nil).Collect()
|
||||
if _, isAlias := info.obj.Type().(*types.Alias); isAlias {
|
||||
info.Def = types.Unalias(info.obj.Type())
|
||||
} else {
|
||||
info.Def = info.obj.Type().Underlying()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -117,8 +106,6 @@ func (info *TypeInfo) Collect() *TypeInfo {
|
||||
|
||||
info.Decl = collector.fromCache(path[1]).(*GroupInfo).Collect()
|
||||
|
||||
info.Def = collector.Package(info.obj.Pkg()).TypesInfo.TypeOf(tspec.Type)
|
||||
|
||||
info.node = path[0]
|
||||
})
|
||||
|
||||
|
@ -209,13 +209,7 @@ func (generator *Generator) generateModelsIndexIncludes(info *collect.PackageInf
|
||||
|
||||
if len(index.Models) > 0 {
|
||||
generator.scheduler.Schedule(func() {
|
||||
generator.generateTypedefs(info, index.Models)
|
||||
})
|
||||
}
|
||||
|
||||
if index.HasExportedModels {
|
||||
generator.scheduler.Schedule(func() {
|
||||
generator.generateModels(index)
|
||||
generator.generateModels(info, index.Models)
|
||||
})
|
||||
}
|
||||
|
||||
@ -236,29 +230,17 @@ func (generator *Generator) validateFileNames() error {
|
||||
case generator.options.ModelsFilename == "":
|
||||
return fmt.Errorf("models filename must not be empty")
|
||||
|
||||
case generator.options.InternalFilename == "":
|
||||
return fmt.Errorf("internal models filename must not be empty")
|
||||
|
||||
case !generator.options.NoIndex && generator.options.IndexFilename == "":
|
||||
return fmt.Errorf("package index filename must not be empty")
|
||||
|
||||
case generator.options.ModelsFilename != strings.ToLower(generator.options.ModelsFilename):
|
||||
return fmt.Errorf("models filename must not contain uppercase characters")
|
||||
|
||||
case generator.options.InternalFilename != strings.ToLower(generator.options.InternalFilename):
|
||||
return fmt.Errorf("internal models filename must not contain uppercase characters")
|
||||
|
||||
case generator.options.IndexFilename != strings.ToLower(generator.options.IndexFilename):
|
||||
return fmt.Errorf("package index filename must not contain uppercase characters")
|
||||
|
||||
case generator.options.ModelsFilename == generator.options.InternalFilename:
|
||||
return fmt.Errorf("models and internal models cannot share the same filename")
|
||||
|
||||
case !generator.options.NoIndex && generator.options.ModelsFilename == generator.options.IndexFilename:
|
||||
return fmt.Errorf("models and package indexes cannot share the same filename")
|
||||
|
||||
case !generator.options.NoIndex && generator.options.InternalFilename == generator.options.IndexFilename:
|
||||
return fmt.Errorf("internal models and package indexes cannot share the same filename")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -3,10 +3,12 @@ package generator
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/wailsapp/wails/v3/internal/generator/render"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
@ -37,9 +39,8 @@ func TestGenerator(t *testing.T) {
|
||||
tests := make([]*testParams, 1<<3)
|
||||
for i := range tests {
|
||||
options := &flags.GenerateBindingsOptions{
|
||||
ModelsFilename: "models",
|
||||
InternalFilename: "internal",
|
||||
IndexFilename: "index",
|
||||
ModelsFilename: "models",
|
||||
IndexFilename: "index",
|
||||
|
||||
UseBundledRuntime: true,
|
||||
|
||||
@ -89,9 +90,11 @@ func TestGenerator(t *testing.T) {
|
||||
// Run tests.
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
creator := outputCreator(t, test)
|
||||
|
||||
generator := NewGenerator(
|
||||
test.options,
|
||||
outputCreator(t, test),
|
||||
creator,
|
||||
config.DefaultPtermLogger(nil),
|
||||
)
|
||||
|
||||
@ -102,6 +105,22 @@ func TestGenerator(t *testing.T) {
|
||||
} else if report.HasWarnings() {
|
||||
pterm.Warning.Println(report)
|
||||
}
|
||||
|
||||
// Log warnings and compare with reference output.
|
||||
if log, err := creator.Create("warnings.log"); err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
func() {
|
||||
defer log.Close()
|
||||
|
||||
warnings := report.Warnings()
|
||||
slices.Sort(warnings)
|
||||
|
||||
for _, msg := range warnings {
|
||||
fmt.Fprint(log, msg, render.Newline)
|
||||
}
|
||||
}()
|
||||
}
|
||||
} else if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
@ -26,16 +26,6 @@ func (generator *Generator) generateIncludes(index *collect.PackageIndex) {
|
||||
return
|
||||
}
|
||||
|
||||
case generator.renderer.InternalFile():
|
||||
if len(index.Models) > 0 {
|
||||
generator.logger.Errorf(
|
||||
"package %s: included file '%s' collides with internal models filename; please rename the file or choose a different filename for internal models",
|
||||
index.Package.Path,
|
||||
path,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
case generator.renderer.IndexFile():
|
||||
if !generator.options.NoIndex && !index.IsEmpty() {
|
||||
generator.logger.Errorf(
|
||||
@ -93,7 +83,12 @@ func (generator *Generator) generateIncludes(index *collect.PackageIndex) {
|
||||
generator.logger.Errorf("package %s: could not write included file '%s'", index.Package.Path, name)
|
||||
return
|
||||
}
|
||||
defer dst.Close()
|
||||
defer func() {
|
||||
if err := dst.Close(); err != nil {
|
||||
generator.logger.Errorf("%v", err)
|
||||
generator.logger.Errorf("package %s: could not write included file '%s'", index.Package.Path, name)
|
||||
}
|
||||
}()
|
||||
|
||||
_, err = io.Copy(dst, src)
|
||||
if err != nil {
|
||||
|
@ -16,7 +16,12 @@ func (generator *Generator) generateIndex(index *collect.PackageIndex) {
|
||||
generator.logger.Errorf("package %s: index generation failed", index.Package.Path)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
defer func() {
|
||||
if err := file.Close(); err != nil {
|
||||
generator.logger.Errorf("%v", err)
|
||||
generator.logger.Errorf("package %s: index generation failed", index.Package.Path)
|
||||
}
|
||||
}()
|
||||
|
||||
err = generator.renderer.Index(file, index)
|
||||
if err != nil {
|
||||
|
@ -6,19 +6,34 @@ import (
|
||||
"github.com/wailsapp/wails/v3/internal/generator/collect"
|
||||
)
|
||||
|
||||
// generateModels generates a file for exported models from the given index information.
|
||||
func (generator *Generator) generateModels(index *collect.PackageIndex) {
|
||||
file, err := generator.creator.Create(filepath.Join(index.Package.Path, generator.renderer.ModelsFile()))
|
||||
// generateModels generates a JS/TS models file for the given list of models.
|
||||
// A call to info.Collect must complete before entering generateModels.
|
||||
func (generator *Generator) generateModels(info *collect.PackageInfo, models []*collect.ModelInfo) {
|
||||
// Merge all import maps.
|
||||
imports := collect.NewImportMap(info)
|
||||
for _, model := range models {
|
||||
imports.Merge(model.Imports)
|
||||
}
|
||||
|
||||
// Clear irrelevant imports.
|
||||
imports.ImportModels = false
|
||||
|
||||
file, err := generator.creator.Create(filepath.Join(info.Path, generator.renderer.ModelsFile()))
|
||||
if err != nil {
|
||||
generator.logger.Errorf("%v", err)
|
||||
generator.logger.Errorf("package %s: exported models generation failed", index.Package.Path)
|
||||
generator.logger.Errorf("package %s: models generation failed", info.Path)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
defer func() {
|
||||
if err := file.Close(); err != nil {
|
||||
generator.logger.Errorf("%v", err)
|
||||
generator.logger.Errorf("package %s: models generation failed", info.Path)
|
||||
}
|
||||
}()
|
||||
|
||||
err = generator.renderer.Models(file, index)
|
||||
err = generator.renderer.Models(file, imports, models)
|
||||
if err != nil {
|
||||
generator.logger.Errorf("%v", err)
|
||||
generator.logger.Errorf("package %s: exported models generation failed", index.Package.Path)
|
||||
generator.logger.Errorf("package %s: models generation failed", info.Path)
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"text/template"
|
||||
|
||||
"github.com/wailsapp/wails/v3/internal/generator/collect"
|
||||
"golang.org/x/tools/go/types/typeutil"
|
||||
)
|
||||
|
||||
// SkipCreate returns true if the given array of types needs no creation code.
|
||||
@ -21,31 +22,34 @@ func (m *module) SkipCreate(ts []types.Type) bool {
|
||||
|
||||
// NeedsCreate returns true if the given type needs some creation code.
|
||||
func (m *module) NeedsCreate(typ types.Type) bool {
|
||||
return m.needsCreateImpl(typ, make(map[*types.TypeName]bool))
|
||||
return m.needsCreateImpl(typ, new(typeutil.Map))
|
||||
}
|
||||
|
||||
// needsCreateImpl provides the actual implementation of NeedsCreate.
|
||||
// The visited parameter is used to break cycles.
|
||||
func (m *module) needsCreateImpl(typ types.Type, visited map[*types.TypeName]bool) bool {
|
||||
func (m *module) needsCreateImpl(typ types.Type, visited *typeutil.Map) bool {
|
||||
switch t := typ.(type) {
|
||||
case *types.Alias, *types.Named:
|
||||
obj := typ.(interface{ Obj() *types.TypeName }).Obj()
|
||||
if visited[obj] {
|
||||
case *types.Alias:
|
||||
return m.needsCreateImpl(types.Unalias(typ), visited)
|
||||
|
||||
case *types.Named:
|
||||
if visited.Set(typ, true) != nil {
|
||||
// The only way to hit a cycle here
|
||||
// is through a chain of structs, nested pointers and arrays (not slices).
|
||||
// We can safely return false at this point
|
||||
// as the final answer is independent of the cycle.
|
||||
return false
|
||||
}
|
||||
visited[obj] = true
|
||||
|
||||
if obj.Pkg() == nil {
|
||||
// Builtin alias or named type: render underlying type.
|
||||
if t.Obj().Pkg() == nil {
|
||||
// Builtin named type: render underlying type.
|
||||
return m.needsCreateImpl(t.Underlying(), visited)
|
||||
}
|
||||
|
||||
if collect.IsAny(t) || collect.IsString(t) {
|
||||
if collect.IsAny(typ) || collect.IsStringAlias(typ) {
|
||||
break
|
||||
} else if collect.IsClass(t) {
|
||||
} else if collect.IsClass(typ) {
|
||||
return true
|
||||
} else if _, isAlias := typ.(*types.Alias); isAlias {
|
||||
return m.needsCreateImpl(types.Unalias(t), visited)
|
||||
} else {
|
||||
return m.needsCreateImpl(t.Underlying(), visited)
|
||||
}
|
||||
@ -57,6 +61,10 @@ func (m *module) needsCreateImpl(typ types.Type, visited map[*types.TypeName]boo
|
||||
return true
|
||||
|
||||
case *types.Struct:
|
||||
if t.NumFields() == 0 || collect.MaybeJSONMarshaler(typ) != collect.NonMarshaler || collect.MaybeTextMarshaler(typ) != collect.NonMarshaler {
|
||||
return false
|
||||
}
|
||||
|
||||
info := m.collector.Struct(t)
|
||||
info.Collect()
|
||||
|
||||
@ -114,7 +122,6 @@ func (m *module) JSCreateWithParams(typ types.Type, params string) string {
|
||||
case *types.Map:
|
||||
pp, ok := m.postponedCreates.At(typ).(*postponed)
|
||||
if !ok {
|
||||
m.JSCreateWithParams(t.Key(), params)
|
||||
m.JSCreateWithParams(t.Elem(), params)
|
||||
pp = &postponed{m.postponedCreates.Len(), params}
|
||||
m.postponedCreates.Set(typ, pp)
|
||||
@ -128,7 +135,7 @@ func (m *module) JSCreateWithParams(typ types.Type, params string) string {
|
||||
return m.JSCreateWithParams(t.Underlying(), params)
|
||||
}
|
||||
|
||||
if collect.IsAny(typ) || collect.IsString(typ) || !m.NeedsCreate(typ) {
|
||||
if !m.NeedsCreate(typ) {
|
||||
break
|
||||
}
|
||||
|
||||
@ -166,6 +173,10 @@ func (m *module) JSCreateWithParams(typ types.Type, params string) string {
|
||||
return fmt.Sprintf("$$createType%d%s", pp.index, params)
|
||||
|
||||
case *types.Struct:
|
||||
if t.NumFields() == 0 || collect.MaybeJSONMarshaler(typ) != collect.NonMarshaler || collect.MaybeTextMarshaler(typ) != collect.NonMarshaler {
|
||||
break
|
||||
}
|
||||
|
||||
pp, ok := m.postponedCreates.At(typ).(*postponed)
|
||||
if ok {
|
||||
return fmt.Sprintf("$$createType%d%s", pp.index, params)
|
||||
@ -212,12 +223,7 @@ func (m *module) PostponedCreates() []string {
|
||||
result[pp.index] = fmt.Sprintf("%s$Create.Array(%s)", pre, m.JSCreateWithParams(t.(interface{ Elem() types.Type }).Elem(), pp.params))
|
||||
|
||||
case *types.Map:
|
||||
result[pp.index] = fmt.Sprintf(
|
||||
"%s$Create.Map(%s, %s)",
|
||||
pre,
|
||||
m.JSCreateWithParams(t.Key(), pp.params),
|
||||
m.JSCreateWithParams(t.Elem(), pp.params),
|
||||
)
|
||||
result[pp.index] = fmt.Sprintf("%s$Create.Map($Create.Any, %s)", pre, m.JSCreateWithParams(t.Elem(), pp.params))
|
||||
|
||||
case *types.Named:
|
||||
if !collect.IsClass(key) {
|
||||
@ -313,10 +319,10 @@ func (m *module) PostponedCreates() []string {
|
||||
}
|
||||
})
|
||||
|
||||
if newline != "\n" {
|
||||
if Newline != "\n" {
|
||||
// Replace newlines according to local git config.
|
||||
for i := range result {
|
||||
result[i] = strings.ReplaceAll(result[i], "\n", newline)
|
||||
result[i] = strings.ReplaceAll(result[i], "\n", Newline)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,11 +44,12 @@ func (m *module) JSDefault(typ types.Type, quoted bool) (result string) {
|
||||
case *types.Map:
|
||||
return "{}"
|
||||
|
||||
case *types.Pointer:
|
||||
return "null"
|
||||
|
||||
case *types.Struct:
|
||||
return m.renderStructDefault(t)
|
||||
|
||||
case *types.TypeParam:
|
||||
// Should be unreachable
|
||||
panic("type parameters have no default value")
|
||||
}
|
||||
|
||||
// Fall back to null.
|
||||
@ -102,8 +103,8 @@ func (m *module) renderNamedDefault(typ aliasOrNamed, quoted bool) (result strin
|
||||
}
|
||||
|
||||
if quoted {
|
||||
// WARN: Do not test with IsString here!! We only want to catch marshalers.
|
||||
if !collect.IsAny(typ) && !collect.MaybeTextMarshaler(typ) {
|
||||
// WARN: Do not test with IsAny/IsStringAlias here!! We only want to catch marshalers.
|
||||
if collect.MaybeJSONMarshaler(typ) == collect.NonMarshaler && collect.MaybeTextMarshaler(typ) == collect.NonMarshaler {
|
||||
if basic, ok := typ.Underlying().(*types.Basic); ok {
|
||||
// Quoted mode for basic alias/named type that is not a marshaler: delegate.
|
||||
return m.renderBasicDefault(basic, quoted), true
|
||||
@ -119,9 +120,9 @@ func (m *module) renderNamedDefault(typ aliasOrNamed, quoted bool) (result strin
|
||||
|
||||
if collect.IsAny(typ) {
|
||||
return "", false
|
||||
} else if collect.MaybeTextMarshaler(typ) {
|
||||
} else if collect.MaybeTextMarshaler(typ) != collect.NonMarshaler {
|
||||
return `""`, true
|
||||
} else if collect.IsClass(typ) {
|
||||
} else if collect.IsClass(typ) && !istpalias(typ) {
|
||||
if typ.Obj().Pkg().Path() == m.Imports.Self {
|
||||
return fmt.Sprintf("(new %s%s())", prefix, jsid(typ.Obj().Name())), true
|
||||
} else {
|
||||
@ -129,29 +130,26 @@ func (m *module) renderNamedDefault(typ aliasOrNamed, quoted bool) (result strin
|
||||
}
|
||||
} else if _, isAlias := typ.(*types.Alias); isAlias {
|
||||
return m.JSDefault(types.Unalias(typ), quoted), true
|
||||
} else {
|
||||
// Inject a type assertion in case we are breaking an enum.
|
||||
// Using the true Go zero value is preferrable to selecting an arbitrary enum value.
|
||||
value := m.JSDefault(typ.Underlying(), quoted)
|
||||
} else if len(m.collector.Model(typ.Obj()).Collect().Values) > 0 {
|
||||
if typ.Obj().Pkg().Path() == m.Imports.Self {
|
||||
if m.TS {
|
||||
return fmt.Sprintf("(%s as %s%s)", value, prefix, jsid(typ.Obj().Name())), true
|
||||
} else {
|
||||
return fmt.Sprintf("(/** @type {%s%s} */(%s))", prefix, jsid(typ.Obj().Name()), value), true
|
||||
}
|
||||
return fmt.Sprintf("%s%s.$zero", prefix, jsid(typ.Obj().Name())), true
|
||||
} else {
|
||||
if m.TS {
|
||||
return fmt.Sprintf("(%s as %s.%s)", value, jsimport(m.Imports.External[typ.Obj().Pkg().Path()]), jsid(typ.Obj().Name())), true
|
||||
} else {
|
||||
return fmt.Sprintf("(/** @type {%s.%s} */(%s))", jsimport(m.Imports.External[typ.Obj().Pkg().Path()]), jsid(typ.Obj().Name()), value), true
|
||||
}
|
||||
return fmt.Sprintf("%s.%s.$zero", jsimport(m.Imports.External[typ.Obj().Pkg().Path()]), jsid(typ.Obj().Name())), true
|
||||
}
|
||||
} else {
|
||||
return m.JSDefault(typ.Underlying(), quoted), true
|
||||
}
|
||||
}
|
||||
|
||||
// renderStructDefault outputs the Javascript representation
|
||||
// of the zero value for the given struct type.
|
||||
func (m *module) renderStructDefault(typ *types.Struct) string {
|
||||
if collect.MaybeJSONMarshaler(typ) != collect.NonMarshaler {
|
||||
return "null"
|
||||
} else if collect.MaybeTextMarshaler(typ) != collect.NonMarshaler {
|
||||
return `""`
|
||||
}
|
||||
|
||||
info := m.collector.Struct(typ)
|
||||
info.Collect()
|
||||
|
||||
|
@ -35,7 +35,7 @@ var commentTerminator = []byte("*/")
|
||||
// with the given indentation.
|
||||
func jsdoc(comment string, indent string) string {
|
||||
var builder strings.Builder
|
||||
prefix := []byte(newline + indent + " * ")
|
||||
prefix := []byte(Newline + indent + " * ")
|
||||
|
||||
scanner := bufio.NewScanner(bytes.NewReader([]byte(comment)))
|
||||
for scanner.Scan() {
|
||||
|
@ -2,6 +2,7 @@ package render
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/types"
|
||||
"math/big"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -15,16 +16,18 @@ import (
|
||||
var tmplFunctions = template.FuncMap{
|
||||
"fixext": fixext,
|
||||
"hasdoc": hasdoc,
|
||||
"isclass": collect.IsClass,
|
||||
"isjsdocid": isjsdocid,
|
||||
"isjsdocobj": isjsdocobj,
|
||||
"istpalias": istpalias,
|
||||
"jsdoc": jsdoc,
|
||||
"jsdocline": jsdocline,
|
||||
"jsid": jsid,
|
||||
"jsimport": jsimport,
|
||||
"jsparam": jsparam,
|
||||
"jsvalue": jsvalue,
|
||||
"modelinfo": modelinfo,
|
||||
"typeparam": typeparam,
|
||||
"unalias": types.Unalias,
|
||||
}
|
||||
|
||||
// fixext replaces a *.ts extension with *.js in the given string.
|
||||
@ -92,3 +95,13 @@ func jsvalue(value any) string {
|
||||
// Fall back to undefined.
|
||||
return "(void(0))"
|
||||
}
|
||||
|
||||
// istpalias determines whether typ is an alias
|
||||
// that when uninstantiated resolves to a typeparam.
|
||||
func istpalias(typ types.Type) bool {
|
||||
if alias, ok := typ.(*types.Alias); ok {
|
||||
return collect.IsTypeParam(alias.Origin())
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
70
v3/internal/generator/render/info.go
Normal file
70
v3/internal/generator/render/info.go
Normal file
@ -0,0 +1,70 @@
|
||||
package render
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/wailsapp/wails/v3/internal/generator/collect"
|
||||
)
|
||||
|
||||
// modelInfo gathers useful information about a model.
|
||||
type modelInfo struct {
|
||||
HasValues bool
|
||||
IsEnum bool
|
||||
|
||||
IsAlias bool
|
||||
IsClassAlias bool
|
||||
IsTypeAlias bool
|
||||
|
||||
IsClassOrInterface bool
|
||||
IsInterface bool
|
||||
IsClass bool
|
||||
|
||||
Template struct {
|
||||
Params string
|
||||
ParamList string
|
||||
CreateList string
|
||||
}
|
||||
}
|
||||
|
||||
// modelinfo gathers and returns useful information about the given model.
|
||||
func modelinfo(model *collect.ModelInfo, useInterfaces bool) (info modelInfo) {
|
||||
info.HasValues = len(model.Values) > 0
|
||||
info.IsEnum = info.HasValues && !model.Alias
|
||||
|
||||
info.IsAlias = !info.IsEnum && model.Type != nil
|
||||
info.IsClassAlias = info.IsAlias && model.Predicates.IsClass && !useInterfaces
|
||||
info.IsTypeAlias = info.IsAlias && !info.IsClassAlias
|
||||
|
||||
info.IsClassOrInterface = !info.IsEnum && !info.IsAlias
|
||||
info.IsInterface = info.IsClassOrInterface && (model.Alias || useInterfaces)
|
||||
info.IsClass = info.IsClassOrInterface && !info.IsInterface
|
||||
|
||||
if len(model.TypeParams) > 0 {
|
||||
var params, paramList, createList strings.Builder
|
||||
|
||||
paramList.WriteRune('<')
|
||||
createList.WriteRune('(')
|
||||
|
||||
for i, param := range model.TypeParams {
|
||||
if i > 0 {
|
||||
params.WriteRune(',')
|
||||
paramList.WriteString(", ")
|
||||
createList.WriteString(", ")
|
||||
}
|
||||
params.WriteString(param)
|
||||
paramList.WriteString(param)
|
||||
|
||||
createList.WriteString("$$createParam")
|
||||
createList.WriteString(param)
|
||||
}
|
||||
|
||||
paramList.WriteRune('>')
|
||||
createList.WriteRune(')')
|
||||
|
||||
info.Template.Params = params.String()
|
||||
info.Template.ParamList = paramList.String()
|
||||
info.Template.CreateList = createList.String()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
@ -38,7 +38,7 @@ func NewRenderer(options *flags.GenerateBindingsOptions, collector *collect.Coll
|
||||
ext: ext,
|
||||
|
||||
service: tmplService[tmplLanguage(options.TS)],
|
||||
typedefs: tmplTypedefs[tmplLanguage(options.TS)],
|
||||
typedefs: tmplModels[tmplLanguage(options.TS)],
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,12 +54,6 @@ func (renderer *Renderer) ModelsFile() string {
|
||||
return renderer.options.ModelsFilename + renderer.ext
|
||||
}
|
||||
|
||||
// InternalFile returns the standard name of an internal model file
|
||||
// with the appropriate extension.
|
||||
func (renderer *Renderer) InternalFile() string {
|
||||
return renderer.options.InternalFilename + renderer.ext
|
||||
}
|
||||
|
||||
// IndexFile returns the standard name of a package index file
|
||||
// with the appropriate extension.
|
||||
func (renderer *Renderer) IndexFile() string {
|
||||
@ -82,7 +76,7 @@ func (renderer *Renderer) Service(w io.Writer, info *collect.ServiceInfo) error
|
||||
}
|
||||
|
||||
// Typedefs renders type definitions for the given list of models.
|
||||
func (renderer *Renderer) Typedefs(w io.Writer, imports *collect.ImportMap, models []*collect.ModelInfo) error {
|
||||
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.
|
||||
// Works in amortized linear time thanks to an auxiliary map.
|
||||
@ -92,7 +86,7 @@ func (renderer *Renderer) Typedefs(w io.Writer, imports *collect.ImportMap, mode
|
||||
|
||||
models = slices.Clone(models)
|
||||
for i, j := 0, 0; i < len(models); i++ {
|
||||
if models[i].Type != nil && collect.IsClass(models[i].Type) {
|
||||
if models[i].Type != nil && models[i].Predicates.IsClass {
|
||||
// models[i] is a class alias:
|
||||
// models[i].Type is guaranteed to be
|
||||
// either an alias or a named type
|
||||
@ -133,19 +127,6 @@ func (renderer *Renderer) Typedefs(w io.Writer, imports *collect.ImportMap, mode
|
||||
})
|
||||
}
|
||||
|
||||
// Models renders exported models for the given package index to w.
|
||||
func (renderer *Renderer) Models(w io.Writer, index *collect.PackageIndex) error {
|
||||
return tmplModels.Execute(w, &struct {
|
||||
*collect.PackageIndex
|
||||
*Renderer
|
||||
*flags.GenerateBindingsOptions
|
||||
}{
|
||||
index,
|
||||
renderer,
|
||||
renderer.options,
|
||||
})
|
||||
}
|
||||
|
||||
// Index renders the given package index to w.
|
||||
func (renderer *Renderer) Index(w io.Writer, index *collect.PackageIndex) error {
|
||||
return tmplIndex.Execute(w, &struct {
|
||||
|
@ -18,16 +18,14 @@ var tmplService = map[tmplLanguage]*template.Template{
|
||||
tmplTS: template.Must(template.New("service.ts.tmpl").Funcs(tmplFunctions).ParseFS(templates, "templates/service.ts.tmpl")),
|
||||
}
|
||||
|
||||
var tmplTypedefs = map[tmplLanguage]*template.Template{
|
||||
tmplJS: template.Must(template.New("internal.js.tmpl").Funcs(tmplFunctions).ParseFS(templates, "templates/internal.js.tmpl")),
|
||||
tmplTS: template.Must(template.New("internal.ts.tmpl").Funcs(tmplFunctions).ParseFS(templates, "templates/internal.ts.tmpl")),
|
||||
var tmplModels = map[tmplLanguage]*template.Template{
|
||||
tmplJS: template.Must(template.New("models.js.tmpl").Funcs(tmplFunctions).ParseFS(templates, "templates/models.js.tmpl")),
|
||||
tmplTS: template.Must(template.New("models.ts.tmpl").Funcs(tmplFunctions).ParseFS(templates, "templates/models.ts.tmpl")),
|
||||
}
|
||||
|
||||
var tmplModels = template.Must(template.New("models.tmpl").Funcs(tmplFunctions).ParseFS(templates, "templates/models.tmpl"))
|
||||
|
||||
var tmplIndex = template.Must(template.New("index.tmpl").Funcs(tmplFunctions).ParseFS(templates, "templates/index.tmpl"))
|
||||
|
||||
var newline string
|
||||
var Newline string
|
||||
|
||||
func init() {
|
||||
var builder strings.Builder
|
||||
@ -37,5 +35,5 @@ func init() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
newline = builder.String()
|
||||
Newline = builder.String()
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
{{$renderer := .}}
|
||||
{{- $useInterfaces := .UseInterfaces}}
|
||||
{{- $models := (fixext .ModelsFile)}}
|
||||
{{- if not .TS -}}
|
||||
// @ts-check
|
||||
@ -18,19 +19,83 @@
|
||||
*/
|
||||
{{end}}
|
||||
{{- if .Services}}
|
||||
{{- range .Services}}
|
||||
{{- range .Services}}{{if .Internal}}{{break}}{{end}}
|
||||
import * as {{jsid .Name}} from "./{{js (fixext ($renderer.ServiceFile .Name))}}";
|
||||
{{- end}}
|
||||
export {
|
||||
{{- range $i, $service := .Services}}
|
||||
{{- if .Internal}}{{break}}{{end}}
|
||||
{{- if gt $i 0}},{{end}}
|
||||
{{jsid .Name}}
|
||||
{{- end}}
|
||||
};
|
||||
{{end}}
|
||||
{{- if .HasExportedModels}}
|
||||
export * from "./{{js $models}}";
|
||||
|
||||
{{- $hasObjects := false}}
|
||||
{{- $hasTypes := false}}
|
||||
|
||||
{{- range $model := .Models}}
|
||||
{{- if $model.Internal}}{{break}}{{end}}
|
||||
|
||||
{{- $info := modelinfo $model $useInterfaces }}
|
||||
|
||||
{{- if or $info.HasValues $info.IsClassAlias $info.IsClass}}
|
||||
{{- if not $hasObjects}}
|
||||
{{- $hasObjects = true}}
|
||||
export {
|
||||
{{- else}},{{end}}
|
||||
{{jsid $model.Name}}
|
||||
{{- else}}
|
||||
{{- $hasTypes = true}}
|
||||
{{- end}}
|
||||
{{- end}}
|
||||
{{- if $hasObjects}}
|
||||
} from "./{{js $models}}";
|
||||
{{end}}
|
||||
|
||||
{{- if $hasTypes}}
|
||||
{{- $hasTypes = false}}
|
||||
|
||||
{{- if .TS}}
|
||||
export type {
|
||||
{{- else}}
|
||||
import * as $models from "./{{js $models}}";
|
||||
{{end}}
|
||||
{{- range $model := .Models}}
|
||||
{{- if $model.Internal}}{{break}}{{end}}
|
||||
|
||||
{{- $info := modelinfo $model $useInterfaces }}
|
||||
{{- $template := $info.Template }}
|
||||
|
||||
{{- if or $info.HasValues $info.IsClassAlias $info.IsClass}}{{continue}}{{end}}
|
||||
|
||||
{{- if $renderer.TS}}
|
||||
{{- if $hasTypes}},{{end}}
|
||||
{{jsid $model.Name}}
|
||||
{{- else}}
|
||||
/**
|
||||
{{- if hasdoc $model.Decl.Doc}}
|
||||
{{- jsdoc $model.Decl.Doc.Text ""}}{{if hasdoc $model.Doc}}
|
||||
*{{end}}
|
||||
{{- end}}
|
||||
{{- if hasdoc $model.Doc}}
|
||||
{{- jsdoc $model.Doc.Text ""}}
|
||||
{{- end}}
|
||||
{{- if $template.ParamList}}
|
||||
* @template {{$template.Params}}
|
||||
{{- end}}
|
||||
* @typedef {$models.{{jsid $model.Name}}{{$template.ParamList -}} } {{jsid $model.Name}}
|
||||
*/
|
||||
{{end}}
|
||||
|
||||
{{- $hasTypes = true}}
|
||||
{{- end}}
|
||||
|
||||
{{- if .TS}}
|
||||
} from "./{{js $models}}";
|
||||
{{end}}
|
||||
|
||||
{{- end}}
|
||||
{{- range .Package.Injections}}
|
||||
{{.}}
|
||||
{{- end}}{{if .Package.Injections}}
|
||||
|
@ -19,34 +19,10 @@ import * as {{jsimport .}} from "{{js .RelPath}}/{{js $models}}";
|
||||
{{end}}
|
||||
{{- range $model := .Models}}
|
||||
|
||||
{{- $isEnum := $model.Values}}
|
||||
{{- $isClassAlias := and $model.Type (not $useInterfaces) (isclass $model.Type)}}
|
||||
{{- $isTypeAlias := and $model.Type (or $useInterfaces (not (isclass $model.Type)))}}
|
||||
{{- $isClassOrInterface := and (not $model.Type) (not $model.Values)}}
|
||||
{{- $isInterface := and $isClassOrInterface (or $useInterfaces $model.Alias)}}
|
||||
{{- $info := modelinfo $model $useInterfaces }}
|
||||
{{- $template := $info.Template }}
|
||||
|
||||
{{- /* Build type parameter list */}}
|
||||
{{- $typeParams := ""}}
|
||||
{{- $typeParamList := ""}}
|
||||
{{- $createParamList := ""}}
|
||||
{{- range $i, $param := $model.TypeParams}}
|
||||
{{- $param = (typeparam $i $param)}}
|
||||
{{- if eq $i 0}}
|
||||
{{- $typeParams = $param}}
|
||||
{{- $typeParamList = (printf "<%s" $param)}}
|
||||
{{- $createParamList = (printf "($$createParam%s" $param)}}
|
||||
{{- else}}
|
||||
{{- $typeParams = (printf "%s,%s" $typeParams $param)}}
|
||||
{{- $typeParamList = (printf "%s, %s" $typeParamList $param)}}
|
||||
{{- $createParamList = (printf "%s, $$createParam%s" $createParamList $param)}}
|
||||
{{- end}}
|
||||
{{- end}}
|
||||
{{- if $typeParamList}}
|
||||
{{- $typeParamList = (printf "%s>" $typeParamList)}}
|
||||
{{- $createParamList = (printf "%s)" $createParamList)}}
|
||||
{{- end}}
|
||||
|
||||
{{- if or $typeParamList (hasdoc $model.Decl.Doc) (hasdoc $model.Doc) $isEnum $isTypeAlias $isInterface}}
|
||||
{{- if or $template.ParamList (hasdoc $model.Decl.Doc) (hasdoc $model.Doc) $info.IsEnum $info.IsTypeAlias $info.IsInterface}}
|
||||
/**
|
||||
{{- if hasdoc $model.Decl.Doc}}
|
||||
{{- jsdoc $model.Decl.Doc.Text ""}}{{if hasdoc $model.Doc}}
|
||||
@ -55,15 +31,15 @@ import * as {{jsimport .}} from "{{js .RelPath}}/{{js $models}}";
|
||||
{{- if hasdoc $model.Doc}}
|
||||
{{- jsdoc $model.Doc.Text ""}}
|
||||
{{- end}}
|
||||
{{- if and $typeParamList (not $isClassAlias)}}
|
||||
* @template {{$typeParams}}
|
||||
{{- if and $template.ParamList (not $info.IsClassAlias)}}
|
||||
* @template {{$template.Params}}
|
||||
{{- end}}
|
||||
{{- if $isEnum}}
|
||||
{{- if $info.IsEnum}}
|
||||
* @readonly
|
||||
* @enum { {{- $module.JSType $model.Type -}} }
|
||||
{{- else if $isTypeAlias}}
|
||||
{{- else if $info.IsTypeAlias}}
|
||||
* @typedef { {{- $module.JSType $model.Type -}} } {{jsid $model.Name}}
|
||||
{{- else if $isInterface}}
|
||||
{{- else if $info.IsInterface}}
|
||||
{{- if isjsdocobj $model}}
|
||||
* @typedef {Object} {{jsid $model.Name}}
|
||||
{{- range $i, $decl := $model.Fields}}{{range $j, $field := $decl}}
|
||||
@ -81,13 +57,22 @@ import * as {{jsimport .}} from "{{js .RelPath}}/{{js $models}}";
|
||||
{{- end}}
|
||||
*/
|
||||
{{- end}}
|
||||
{{- if $isEnum}}
|
||||
{{- if $info.HasValues}}
|
||||
{{- if not $info.IsEnum}}
|
||||
|
||||
/**
|
||||
* Predefined constants for type {{jsid $model.Name}}.
|
||||
* @namespace
|
||||
*/
|
||||
{{- end}}
|
||||
export const {{jsid $model.Name}} = {
|
||||
{{- if $info.IsEnum}}
|
||||
/**
|
||||
* The Go zero value for the underlying type of the enum.
|
||||
*/
|
||||
$zero: {{$module.JSDefault $model.Type false}},
|
||||
{{range $i, $decl := $model.Values}}{{range $j, $spec := $decl}}{{range $k, $value := $spec}}
|
||||
{{end}}
|
||||
{{- range $i, $decl := $model.Values}}{{range $j, $spec := $decl}}{{range $k, $value := $spec}}
|
||||
{{- if and (ne $i 0) (eq $j 0) (eq $k 0)}}
|
||||
{{end}}
|
||||
{{- if or (and (eq $j 0) (eq $k 0) (hasdoc $value.Decl.Doc)) (and (eq $k 0) (hasdoc $value.Spec.Doc))}}
|
||||
@ -106,8 +91,12 @@ export const {{jsid $model.Name}} = {
|
||||
{{jsid $value.Name}}: {{jsvalue $value.Value}},
|
||||
{{- end}}{{end}}{{end}}
|
||||
};
|
||||
{{else if $isClassAlias}}
|
||||
export const {{jsid $model.Name}} = {{$module.JSType $model.Type.Origin}};
|
||||
{{else if $info.IsClassAlias}}
|
||||
export const {{jsid $model.Name}} = {{if istpalias $model.Type -}}
|
||||
{{$module.JSType (unalias $model.Type).Origin}};
|
||||
{{- else -}}
|
||||
{{$module.JSType $model.Type.Origin}};
|
||||
{{- end}}
|
||||
|
||||
/**
|
||||
{{- if hasdoc $model.Decl.Doc}}
|
||||
@ -117,16 +106,16 @@ export const {{jsid $model.Name}} = {{$module.JSType $model.Type.Origin}};
|
||||
{{- if hasdoc $model.Doc}}
|
||||
{{- jsdoc $model.Doc.Text ""}}
|
||||
{{- end}}
|
||||
{{- if $typeParamList}}
|
||||
* @template {{$typeParams}}
|
||||
{{- if $template.ParamList}}
|
||||
* @template {{$template.Params}}
|
||||
{{- end}}
|
||||
* @typedef { {{- $module.JSType $model.Type -}} } {{jsid $model.Name}}
|
||||
*/
|
||||
{{else if and $isClassOrInterface (not $isInterface)}}
|
||||
{{else if and $info.IsClass}}
|
||||
export class {{jsid $model.Name}} {
|
||||
/**
|
||||
* Creates a new {{jsid $model.Name}} instance.
|
||||
* @param {Partial<{{jsid $model.Name}}{{$typeParamList}}>} [$$source = {}] - The source object to create the {{jsid $model.Name}}.
|
||||
* @param {Partial<{{jsid $model.Name}}{{$template.ParamList}}>} [$$source = {}] - The source object to create the {{jsid $model.Name}}.
|
||||
*/
|
||||
constructor($$source = {}) {
|
||||
{{- range $decl := $model.Fields}}{{range $j, $field := $decl}}
|
||||
@ -144,9 +133,9 @@ export class {{jsid $model.Name}} {
|
||||
{{- jsdoc $field.Decl.Doc.Text " "}}
|
||||
{{- end}}
|
||||
* @member
|
||||
* @type { {{- $module.JSFieldType $field.StructField}}{{if .Optional}} | undefined{{end -}} }
|
||||
* @type { {{- $module.JSFieldType $field.StructField}}{{if $field.Optional}} | undefined{{end -}} }
|
||||
*/
|
||||
this["{{js $field.JsonName}}"] = {{$module.JSDefault $field.Type $field.Quoted}};
|
||||
this["{{js $field.JsonName}}"] = {{if $field.Optional}}undefined{{else}}{{$module.JSDefault $field.Type $field.Quoted}}{{end}};
|
||||
}
|
||||
{{- end}}{{end}}
|
||||
|
||||
@ -154,31 +143,31 @@ export class {{jsid $model.Name}} {
|
||||
}
|
||||
|
||||
/**
|
||||
{{- if $typeParamList}}
|
||||
{{- if $template.ParamList}}
|
||||
* Given creation functions for each type parameter,
|
||||
* returns a creation function for a concrete instance
|
||||
* of the generic class {{jsid $model.Name}}.
|
||||
* @template {{$typeParams}}
|
||||
* @template {{$template.Params}}
|
||||
{{- range $i, $param := $model.TypeParams}}
|
||||
{{- $param = (typeparam $i $param)}}
|
||||
* @param {(source: any) => {{$param -}} } $$createParam{{$param}}
|
||||
{{- end}}
|
||||
* @returns {($$source?: any) => {{jsid $model.Name}}{{$typeParamList -}} }
|
||||
* @returns {($$source?: any) => {{jsid $model.Name}}{{$template.ParamList -}} }
|
||||
{{- else}}
|
||||
* Creates a new {{jsid $model.Name}} instance from a string or object.
|
||||
* @param {any} [$$source = {}]
|
||||
* @returns { {{- jsid $model.Name -}} }
|
||||
{{- end}}
|
||||
*/
|
||||
static createFrom{{if $typeParamList}}{{$createParamList}}{{else}}($$source = {}){{end}} {
|
||||
static createFrom{{if $template.ParamList}}{{$template.CreateList}}{{else}}($$source = {}){{end}} {
|
||||
{{- range $i, $spec := $model.Fields}}{{range $j, $field := $spec}}
|
||||
{{- $create := ($module.JSCreateWithParams $field.Type $createParamList)}}
|
||||
{{- $create := ($module.JSCreateWithParams $field.Type $template.CreateList)}}
|
||||
{{- if ne $create "$Create.Any"}}
|
||||
const $$createField{{$i}}_{{$j}} = {{$create}};
|
||||
{{- end}}
|
||||
{{- end}}{{end}}
|
||||
{{- $indent := ""}}
|
||||
{{- if $typeParamList}}
|
||||
{{- if $template.ParamList}}
|
||||
{{- $indent = " "}}
|
||||
return ($$source = {}) => {
|
||||
{{- end}}
|
||||
@ -190,8 +179,8 @@ export class {{jsid $model.Name}} {
|
||||
{{$indent -}} }
|
||||
{{- end}}
|
||||
{{- end}}{{end}}
|
||||
{{$indent}}return new {{jsid $model.Name}}(/** @type {Partial<{{jsid $model.Name}}{{$typeParamList}}>} */($$parsedSource));
|
||||
{{- if $typeParamList}}
|
||||
{{$indent}}return new {{jsid $model.Name}}(/** @type {Partial<{{jsid $model.Name}}{{$template.ParamList}}>} */($$parsedSource));
|
||||
{{- if $template.ParamList}}
|
||||
};
|
||||
{{- end}}
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
{{$renderer := .}}
|
||||
{{- $useInterfaces := .UseInterfaces}}
|
||||
{{- $internal := (fixext .InternalFile)}}
|
||||
{{- if not .TS -}}
|
||||
// @ts-check
|
||||
{{end -}}
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
{{- $hasObjects := false}}
|
||||
{{- $hasTypes := false}}
|
||||
|
||||
{{- range $model := .Models}}
|
||||
{{- if not $model.Object.Exported}}{{break}}{{end}}
|
||||
|
||||
{{- $isEnum := $model.Values}}
|
||||
{{- $isClassAlias := and $model.Type (not $useInterfaces) (isclass $model.Type)}}
|
||||
{{- $isClass := and (not $model.Type) (not $model.Values) (not $useInterfaces) (not $model.Alias)}}
|
||||
|
||||
{{- if or $isEnum $isClassAlias $isClass}}
|
||||
{{- if not $hasObjects}}
|
||||
{{- $hasObjects = true}}
|
||||
|
||||
export {
|
||||
{{- else}},{{end}}
|
||||
{{jsid $model.Name}}
|
||||
{{- else}}
|
||||
{{- $hasTypes = true}}
|
||||
{{- end}}
|
||||
{{- end}}
|
||||
{{- if $hasObjects}}
|
||||
} from "./{{js $internal}}";
|
||||
{{- end}}
|
||||
|
||||
{{- if $hasTypes}}
|
||||
{{- $hasTypes = false}}
|
||||
|
||||
{{if .TS -}}
|
||||
export type {
|
||||
{{- else -}}
|
||||
import * as $models from "./{{js $internal}}";
|
||||
{{- end}}
|
||||
{{- range $model := .Models}}
|
||||
{{- if not $model.Object.Exported}}{{break}}{{end}}
|
||||
|
||||
{{- $isEnum := $model.Values}}
|
||||
{{- $isClassAlias := and $model.Type (not $useInterfaces) (isclass $model.Type)}}
|
||||
{{- $isClass := and (not $model.Type) (not $model.Values) (not $useInterfaces) (not $model.Alias)}}
|
||||
{{- if or $isEnum $isClassAlias $isClass}}{{continue}}{{end}}
|
||||
|
||||
{{- /* Build type parameter list */}}
|
||||
{{- $typeParams := ""}}
|
||||
{{- $typeParamList := ""}}
|
||||
{{- range $i, $param := $model.TypeParams}}
|
||||
{{- $param = (typeparam $i $param)}}
|
||||
{{- if eq $i 0}}
|
||||
{{- $typeParams = $param}}
|
||||
{{- $typeParamList = (printf "<%s" $param)}}
|
||||
{{- else}}
|
||||
{{- $typeParams = (printf "%s,%s" $typeParams $param)}}
|
||||
{{- $typeParamList = (printf "%s, %s" $typeParamList $param)}}
|
||||
{{- end}}
|
||||
{{- end}}
|
||||
{{- if $typeParamList}}
|
||||
{{- $typeParamList = (printf "%s>" $typeParamList)}}
|
||||
{{- end}}
|
||||
{{- if $renderer.TS}}
|
||||
{{- if $hasTypes}},{{end}}
|
||||
{{jsid $model.Name}}
|
||||
{{- else}}
|
||||
|
||||
/**
|
||||
{{- if hasdoc $model.Decl.Doc}}
|
||||
{{- jsdoc $model.Decl.Doc.Text ""}}{{if hasdoc $model.Doc}}
|
||||
*{{end}}
|
||||
{{- end}}
|
||||
{{- if hasdoc $model.Doc}}
|
||||
{{- jsdoc $model.Doc.Text ""}}
|
||||
{{- end}}
|
||||
{{- if $typeParamList}}
|
||||
* @template {{$typeParams}}
|
||||
{{- end}}
|
||||
* @typedef {$models.{{jsid $model.Name}}{{$typeParamList -}} } {{jsid $model.Name}}
|
||||
*/
|
||||
{{- end}}
|
||||
|
||||
{{- $hasTypes = true}}
|
||||
{{- end}}
|
||||
|
||||
{{- if .TS}}
|
||||
} from "./{{js $internal}}";
|
||||
{{- end}}
|
||||
|
||||
{{- end}}
|
@ -18,29 +18,8 @@ import * as {{jsimport .}} from "{{js .RelPath}}/{{js $models}}";
|
||||
{{end}}
|
||||
{{- range $model := .Models}}
|
||||
|
||||
{{- $isEnum := $model.Values}}
|
||||
{{- $isClassAlias := and $model.Type (not $useInterfaces) (isclass $model.Type)}}
|
||||
{{- $isTypeAlias := and $model.Type (or $useInterfaces (not (isclass $model.Type)))}}
|
||||
{{- $isClassOrInterface := and (not $model.Type) (not $model.Values)}}
|
||||
{{- $isInterface := or $useInterfaces $model.Alias}}
|
||||
|
||||
{{- /* Build type parameter list */}}
|
||||
{{- $typeParamList := ""}}
|
||||
{{- $createParamList := ""}}
|
||||
{{- range $i, $param := $model.TypeParams}}
|
||||
{{- $param = (typeparam $i $param)}}
|
||||
{{- if eq $i 0}}
|
||||
{{- $typeParamList = (printf "<%s" $param)}}
|
||||
{{- $createParamList = (printf "($$createParam%s" $param)}}
|
||||
{{- else}}
|
||||
{{- $typeParamList = (printf "%s, %s" $typeParamList $param)}}
|
||||
{{- $createParamList = (printf "%s, $$createParam%s" $createParamList $param)}}
|
||||
{{- end}}
|
||||
{{- end}}
|
||||
{{- if $typeParamList}}
|
||||
{{- $typeParamList = (printf "%s>" $typeParamList)}}
|
||||
{{- $createParamList = (printf "%s)" $createParamList)}}
|
||||
{{- end}}
|
||||
{{- $info := modelinfo $model $useInterfaces }}
|
||||
{{- $template := $info.Template }}
|
||||
|
||||
{{- if or (hasdoc $model.Decl.Doc) (hasdoc $model.Doc)}}
|
||||
/**
|
||||
@ -53,7 +32,7 @@ import * as {{jsimport .}} from "{{js .RelPath}}/{{js $models}}";
|
||||
{{- end}}
|
||||
*/
|
||||
{{- end}}
|
||||
{{- if $isEnum}}
|
||||
{{- if $info.IsEnum}}
|
||||
export enum {{jsid $model.Name}} {
|
||||
/**
|
||||
* The Go zero value for the underlying type of the enum.
|
||||
@ -78,8 +57,12 @@ export enum {{jsid $model.Name}} {
|
||||
{{jsid $value.Name}} = {{jsvalue $value.Value}},
|
||||
{{- end}}{{end}}{{end}}
|
||||
};
|
||||
{{else if $isClassAlias}}
|
||||
export const {{jsid $model.Name}} = {{$module.JSType $model.Type.Origin}};
|
||||
{{else if $info.IsClassAlias}}
|
||||
export const {{jsid $model.Name}} = {{if istpalias $model.Type -}}
|
||||
{{$module.JSType (unalias $model.Type).Origin}};
|
||||
{{- else -}}
|
||||
{{$module.JSType $model.Type.Origin}};
|
||||
{{- end}}
|
||||
{{- if or (hasdoc $model.Decl.Doc) (hasdoc $model.Doc)}}
|
||||
|
||||
/**
|
||||
@ -92,11 +75,38 @@ export const {{jsid $model.Name}} = {{$module.JSType $model.Type.Origin}};
|
||||
{{- end}}
|
||||
*/
|
||||
{{- end}}
|
||||
export type {{jsid $model.Name}}{{$typeParamList}} = {{$module.JSType $model.Type}};
|
||||
{{else if $isTypeAlias}}
|
||||
export type {{jsid $model.Name}}{{$typeParamList}} = {{$module.JSType $model.Type}};
|
||||
{{else if $isClassOrInterface}}
|
||||
export {{if $isInterface}}interface{{else}}class{{end}} {{jsid $model.Name}}{{$typeParamList}} {
|
||||
export type {{jsid $model.Name}}{{$template.ParamList}} = {{$module.JSType $model.Type}};
|
||||
{{else if $info.IsTypeAlias}}
|
||||
export type {{jsid $model.Name}}{{$template.ParamList}} = {{$module.JSType $model.Type}};
|
||||
{{- if $info.HasValues}}
|
||||
|
||||
/**
|
||||
* Predefined constants for type {{jsid $model.Name}}.
|
||||
* @namespace
|
||||
*/
|
||||
export const {{jsid $model.Name}} = {
|
||||
{{- range $i, $decl := $model.Values}}{{range $j, $spec := $decl}}{{range $k, $value := $spec}}
|
||||
{{- if and (ne $i 0) (eq $j 0) (eq $k 0)}}
|
||||
{{end}}
|
||||
{{- if or (and (eq $j 0) (eq $k 0) (hasdoc $value.Decl.Doc)) (and (eq $k 0) (hasdoc $value.Spec.Doc))}}
|
||||
{{- if gt $j 0}}
|
||||
{{end}}
|
||||
/**
|
||||
{{- if and (eq $j 0) (eq $k 0) (hasdoc $value.Decl.Doc)}}
|
||||
{{- jsdoc $value.Decl.Doc.Text " "}}{{if and (eq $k 0) (hasdoc $value.Spec.Doc)}}
|
||||
*{{end}}
|
||||
{{- end}}
|
||||
{{- if and (eq $k 0) (hasdoc $value.Spec.Doc)}}
|
||||
{{- jsdoc $value.Spec.Doc.Text " "}}
|
||||
{{- end}}
|
||||
*/
|
||||
{{- end}}
|
||||
{{jsid $value.Name}}: {{jsvalue $value.Value}},
|
||||
{{- end}}{{end}}{{end}}
|
||||
};
|
||||
{{- end}}
|
||||
{{else if $info.IsClassOrInterface}}
|
||||
export {{if $info.IsInterface}}interface{{else}}class{{end}} {{jsid $model.Name}}{{$template.ParamList}} {
|
||||
{{- range $i, $decl := $model.Fields}}{{range $j, $field := $decl}}
|
||||
{{- if and (eq $j 0) (hasdoc $field.Decl.Doc)}}
|
||||
{{- if gt $i 0}}
|
||||
@ -107,11 +117,11 @@ export {{if $isInterface}}interface{{else}}class{{end}} {{jsid $model.Name}}{{$t
|
||||
{{- end}}
|
||||
"{{js $field.JsonName}}"{{if $field.Optional}}?{{end}}: {{$module.JSFieldType $field.StructField}};
|
||||
{{- end}}{{end}}
|
||||
{{- if not $isInterface}}
|
||||
{{- if $info.IsClass}}
|
||||
|
||||
/** Creates a new {{jsid $model.Name}} instance. */
|
||||
constructor($$source: Partial<{{jsid $model.Name}}{{$typeParamList}}> = {}) {
|
||||
{{- range $spec := $model.Fields}}{{range $i, $field := $spec}}{{if not .Optional}}
|
||||
constructor($$source: Partial<{{jsid $model.Name}}{{$template.ParamList}}> = {}) {
|
||||
{{- range $spec := $model.Fields}}{{range $i, $field := $spec}}{{if not $field.Optional}}
|
||||
if (!("{{js $field.JsonName}}" in $$source)) {
|
||||
this["{{js $field.JsonName}}"] = {{$module.JSDefault $field.Type $field.Quoted}};
|
||||
}
|
||||
@ -121,7 +131,7 @@ export {{if $isInterface}}interface{{else}}class{{end}} {{jsid $model.Name}}{{$t
|
||||
}
|
||||
|
||||
/**
|
||||
{{- if $typeParamList}}
|
||||
{{- if $template.ParamList}}
|
||||
* Given creation functions for each type parameter,
|
||||
* returns a creation function for a concrete instance
|
||||
* of the generic class {{jsid $model.Name}}.
|
||||
@ -129,21 +139,21 @@ export {{if $isInterface}}interface{{else}}class{{end}} {{jsid $model.Name}}{{$t
|
||||
* Creates a new {{jsid $model.Name}} instance from a string or object.
|
||||
{{- end}}
|
||||
*/
|
||||
static createFrom{{$typeParamList}}({{if $typeParamList}}
|
||||
static createFrom{{$template.ParamList}}({{if $template.ParamList}}
|
||||
{{- range $i, $param := $model.TypeParams}}
|
||||
{{- $param = (typeparam $i $param)}}
|
||||
{{- if gt $i 0}}, {{end -}}
|
||||
$$createParam{{$param}}: (source: any) => {{$param}}{{end -}}
|
||||
{{else}}$$source: any = {}{{end}}):
|
||||
{{- if $typeParamList}} ($$source?: any) =>{{end}} {{jsid $model.Name}}{{$typeParamList}} {
|
||||
{{- if $template.ParamList}} ($$source?: any) =>{{end}} {{jsid $model.Name}}{{$template.ParamList}} {
|
||||
{{- range $i, $spec := $model.Fields}}{{range $j, $field := $spec}}
|
||||
{{- $create := ($module.JSCreateWithParams $field.Type $createParamList)}}
|
||||
{{- $create := ($module.JSCreateWithParams $field.Type $template.CreateList)}}
|
||||
{{- if ne $create "$Create.Any"}}
|
||||
const $$createField{{$i}}_{{$j}} = {{$create}};
|
||||
{{- end}}
|
||||
{{- end}}{{end}}
|
||||
{{- $indent := ""}}
|
||||
{{- if $typeParamList}}
|
||||
{{- if $template.ParamList}}
|
||||
{{- $indent = " "}}
|
||||
return ($$source: any = {}) => {
|
||||
{{- end}}
|
||||
@ -155,8 +165,8 @@ export {{if $isInterface}}interface{{else}}class{{end}} {{jsid $model.Name}}{{$t
|
||||
{{$indent -}} }
|
||||
{{- end}}
|
||||
{{- end}}{{end}}
|
||||
{{$indent}}return new {{jsid $model.Name}}{{$typeParamList}}($$parsedSource as Partial<{{jsid $model.Name}}{{$typeParamList}}>);
|
||||
{{- if $typeParamList}}
|
||||
{{$indent}}return new {{jsid $model.Name}}{{$template.ParamList}}($$parsedSource as Partial<{{jsid $model.Name}}{{$template.ParamList}}>);
|
||||
{{- if $template.ParamList}}
|
||||
};
|
||||
{{- end}}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
{{$module := .}}
|
||||
{{- $runtime := $module.Runtime}}
|
||||
{{- $models := (fixext $module.ModelsFile)}}
|
||||
{{- $internal := (fixext $module.InternalFile)}}
|
||||
{{- $useNames := $module.UseNames}}
|
||||
{{- $useInterfaces := $module.UseInterfaces}}
|
||||
{{- $imports := $module.Imports}}
|
||||
@ -33,11 +32,7 @@ import * as {{jsimport .}} from "{{js .RelPath}}/{{js $models}}";
|
||||
{{- if $imports.ImportModels}}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import * as $models from "./{{js $internal}}";
|
||||
{{end}}
|
||||
{{- range .Injections}}
|
||||
{{.}}
|
||||
{{- end}}{{if .Injections}}
|
||||
import * as $models from "./{{js $models}}";
|
||||
{{end}}
|
||||
{{- range .Methods}}
|
||||
/**
|
||||
@ -100,4 +95,8 @@ import * as $models from "./{{js $internal}}";
|
||||
{{if and (ge (len $create) 54) (eq (slice $create 39 54) "function $$init")}}var {{else}}const {{end -}}
|
||||
$$createType{{$i}} = {{$create}};
|
||||
{{- end}}
|
||||
{{end}}
|
||||
{{- range .Injections}}
|
||||
{{.}}
|
||||
{{- end}}{{if .Injections}}
|
||||
{{end}}{{end -}}
|
||||
|
@ -1,7 +1,6 @@
|
||||
{{$module := .}}
|
||||
{{- $runtime := $module.Runtime}}
|
||||
{{- $models := (fixext $module.ModelsFile)}}
|
||||
{{- $internal := (fixext $module.InternalFile)}}
|
||||
{{- $useNames := $module.UseNames}}
|
||||
{{- $useInterfaces := $module.UseInterfaces}}
|
||||
{{- $imports := $module.Imports}}
|
||||
@ -32,11 +31,7 @@ import * as {{jsimport .}} from "{{js .RelPath}}/{{js $models}}";
|
||||
{{- if $imports.ImportModels}}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import * as $models from "./{{js $internal}}";
|
||||
{{end}}
|
||||
{{- range .Injections}}
|
||||
{{.}}
|
||||
{{- end}}{{if .Injections}}
|
||||
import * as $models from "./{{js $models}}";
|
||||
{{end}}
|
||||
{{- range .Methods}}
|
||||
{{- if or (hasdoc .Decl.Doc) (hasdoc .Doc)}}
|
||||
@ -97,4 +92,8 @@ import * as $models from "./{{js $internal}}";
|
||||
{{if and (ge (len $create) 16) (eq (slice $create 1 16) "function $$init")}}var {{else}}const {{end -}}
|
||||
$$createType{{$i}} = {{$create}};
|
||||
{{- end}}
|
||||
{{end}}
|
||||
{{- range .Injections}}
|
||||
{{.}}
|
||||
{{- end}}{{if .Injections}}
|
||||
{{end}}{{end -}}
|
||||
|
@ -72,9 +72,9 @@ func (m *module) renderType(typ types.Type, quoted bool) (result string, nullabl
|
||||
return m.renderMapType(t)
|
||||
|
||||
case *types.Pointer:
|
||||
elem, ptr := m.renderType(t.Elem(), false)
|
||||
if ptr {
|
||||
return elem, true
|
||||
elem, nullable := m.renderType(t.Elem(), false)
|
||||
if nullable {
|
||||
return elem, nullable
|
||||
} else {
|
||||
return fmt.Sprintf("%s | null", elem), true
|
||||
}
|
||||
@ -83,11 +83,11 @@ func (m *module) renderType(typ types.Type, quoted bool) (result string, nullabl
|
||||
return m.renderStructType(t), false
|
||||
|
||||
case *types.TypeParam:
|
||||
str := ""
|
||||
pre, post := "", ""
|
||||
if quoted {
|
||||
str = "| string "
|
||||
pre, post = "(", " | string)"
|
||||
}
|
||||
return fmt.Sprintf("%s %s| null", typeparam(t.Index(), t.Obj().Name()), str), true
|
||||
return fmt.Sprintf("%s%s%s", pre, typeparam(t.Index(), t.Obj().Name()), post), false
|
||||
}
|
||||
|
||||
// Fall back to untyped mode.
|
||||
@ -147,29 +147,22 @@ func (m *module) renderMapType(typ *types.Map) (result string, nullable bool) {
|
||||
key = m.renderBasicType(k, true)
|
||||
}
|
||||
|
||||
case *types.Alias, *types.Named:
|
||||
if collect.IsMapKey(typ) {
|
||||
if collect.IsString(typ) {
|
||||
case *types.Alias, *types.Named, *types.Pointer:
|
||||
if collect.IsMapKey(k) {
|
||||
if collect.IsStringAlias(k) {
|
||||
// Alias or named type is a string and therefore
|
||||
// safe to use as a JS object key.
|
||||
if ptr, ok := k.(*types.Pointer); ok {
|
||||
// Unwrap pointer to named string type, but not pointer aliases.
|
||||
// Unwrap pointers to string aliases.
|
||||
key, _ = m.renderType(ptr.Elem(), false)
|
||||
} else {
|
||||
key, _ = m.renderType(k, false)
|
||||
}
|
||||
} else if basic, ok := typ.Underlying().(*types.Basic); ok && basic.Info()&types.IsString == 0 {
|
||||
} else if basic, ok := k.Underlying().(*types.Basic); ok && basic.Info()&types.IsString == 0 {
|
||||
// Render non-string basic type in quoted mode.
|
||||
key = m.renderBasicType(basic, true)
|
||||
}
|
||||
}
|
||||
|
||||
case *types.Pointer:
|
||||
if collect.IsMapKey(typ) && collect.IsString(typ.Elem()) {
|
||||
// Base type is a string alias and therefore
|
||||
// safe to use as a JS object key.
|
||||
key, _ = m.renderType(k.Elem(), false)
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("{ [_: %s]: %s }%s", key, elem, null), m.UseInterfaces
|
||||
@ -193,16 +186,12 @@ func (m *module) renderNamedType(typ aliasOrNamed, quoted bool) (result string,
|
||||
return m.renderType(a, quoted)
|
||||
case *types.Named:
|
||||
// Quoted mode for (alias of?) named type.
|
||||
// WARN: Do not test with IsString here!! We only want to catch marshalers.
|
||||
if !collect.IsAny(typ) && !collect.MaybeTextMarshaler(typ) {
|
||||
// WARN: Do not test with IsAny/IsStringAlias here!! We only want to catch marshalers.
|
||||
if collect.MaybeJSONMarshaler(typ) == collect.NonMarshaler && collect.MaybeTextMarshaler(typ) == collect.NonMarshaler {
|
||||
// No custom marshaling for this type.
|
||||
switch u := a.Underlying().(type) {
|
||||
case *types.Basic:
|
||||
if u, ok := a.Underlying().(*types.Basic); ok {
|
||||
// Quoted mode for basic named type that is not a marshaler: delegate.
|
||||
return m.renderBasicType(u, quoted), false
|
||||
case *types.TypeParam:
|
||||
// Quoted mode for generic type that maps to typeparam: delegate.
|
||||
return m.renderType(u, quoted)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -242,6 +231,12 @@ func (m *module) renderNamedType(typ aliasOrNamed, quoted bool) (result string,
|
||||
// renderStructType outputs the TS representation
|
||||
// of the given anonymous struct type.
|
||||
func (m *module) renderStructType(typ *types.Struct) string {
|
||||
if collect.MaybeJSONMarshaler(typ) != collect.NonMarshaler {
|
||||
return "any"
|
||||
} else if collect.MaybeTextMarshaler(typ) != collect.NonMarshaler {
|
||||
return "string"
|
||||
}
|
||||
|
||||
info := m.collector.Struct(typ)
|
||||
info.Collect()
|
||||
|
||||
|
@ -33,11 +33,13 @@ func (generator *Generator) generateService(obj *types.TypeName) {
|
||||
}
|
||||
|
||||
if info.IsEmpty() {
|
||||
generator.logger.Infof(
|
||||
"package %s: type %s: service has no valid exported methods, skipping",
|
||||
obj.Pkg().Path(),
|
||||
obj.Name(),
|
||||
)
|
||||
if !info.HasInternalMethods {
|
||||
generator.logger.Infof(
|
||||
"package %s: type %s: service has no valid exported methods, skipping",
|
||||
obj.Pkg().Path(),
|
||||
obj.Name(),
|
||||
)
|
||||
}
|
||||
success = true
|
||||
return
|
||||
}
|
||||
@ -53,14 +55,6 @@ func (generator *Generator) generateService(obj *types.TypeName) {
|
||||
)
|
||||
return
|
||||
|
||||
case generator.renderer.InternalFile():
|
||||
generator.logger.Errorf(
|
||||
"package %s: type %s: service filename collides with internal models filename; please rename the type or choose a different filename for internal models",
|
||||
obj.Pkg().Path(),
|
||||
obj.Name(),
|
||||
)
|
||||
return
|
||||
|
||||
case generator.renderer.IndexFile():
|
||||
if !generator.options.NoIndex {
|
||||
generator.logger.Errorf(
|
||||
@ -90,7 +84,12 @@ func (generator *Generator) generateService(obj *types.TypeName) {
|
||||
generator.logger.Errorf("%v", err)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
defer func() {
|
||||
if err := file.Close(); err != nil {
|
||||
generator.logger.Errorf("%v", err)
|
||||
success = false
|
||||
}
|
||||
}()
|
||||
|
||||
// Render service code.
|
||||
err = generator.renderer.Service(file, info)
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
_ "embed"
|
||||
"log"
|
||||
|
||||
nobindingshere "github.com/wailsapp/wails/v3/internal/generator/testcases/no_bindings_here"
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
)
|
||||
|
||||
@ -52,6 +53,39 @@ type GenericPerson[T any] struct {
|
||||
// Another class alias, but ordered after its aliased class.
|
||||
type StrangelyAliasedPerson = Person
|
||||
|
||||
// A generic alias that forwards to a type parameter.
|
||||
// type GenericAlias[T any] = T
|
||||
|
||||
// A generic alias that wraps a pointer type.
|
||||
// type GenericPtrAlias[T any] = *GenericAlias[T]
|
||||
|
||||
// A generic alias that wraps a map.
|
||||
// type GenericMapAlias[T interface {
|
||||
// comparable
|
||||
// encoding.TextMarshaler
|
||||
// }, U any] = map[T]U
|
||||
|
||||
// A generic alias that wraps a generic struct.
|
||||
// type GenericPersonAlias[T any] = GenericPerson[[]GenericPtrAlias[T]]
|
||||
|
||||
// An alias that wraps a class through a non-typeparam alias.
|
||||
// type IndirectPersonAlias = GenericPersonAlias[bool]
|
||||
|
||||
// An alias that wraps a class through a typeparam alias.
|
||||
// type TPIndirectPersonAlias = GenericAlias[GenericPerson[bool]]
|
||||
|
||||
// A class whose fields have various aliased types.
|
||||
// type AliasGroup struct {
|
||||
// GAi GenericAlias[int]
|
||||
// GAP GenericAlias[GenericPerson[bool]]
|
||||
// GPAs GenericPtrAlias[[]string]
|
||||
// GPAP GenericPtrAlias[GenericPerson[[]int]]
|
||||
// GMA GenericMapAlias[struct{ encoding.TextMarshaler }, float32]
|
||||
// GPA GenericPersonAlias[bool]
|
||||
// IPA IndirectPersonAlias
|
||||
// TPIPA TPIndirectPersonAlias
|
||||
// }
|
||||
|
||||
// Get someone.
|
||||
func (GreetService) Get(aliasValue Alias) Person {
|
||||
return Person{"hello", aliasValue}
|
||||
@ -67,6 +101,14 @@ func (GreetService) GetButAliased(p AliasedPerson) StrangelyAliasedPerson {
|
||||
return p
|
||||
}
|
||||
|
||||
func (GreetService) GetButForeignPrivateAlias() (_ nobindingshere.PrivatePerson) {
|
||||
return
|
||||
}
|
||||
|
||||
// func (GreetService) GetButGenericAliases() (_ AliasGroup) {
|
||||
// return
|
||||
// }
|
||||
|
||||
// Greet a lot of unusual things.
|
||||
func (GreetService) Greet(EmptyAliasStruct, EmptyStruct) AliasStruct {
|
||||
return AliasStruct{}
|
||||
|
@ -12,5 +12,5 @@
|
||||
".Service11",
|
||||
".Service12",
|
||||
".Service13",
|
||||
"/other.Service14"
|
||||
"/other.Service16"
|
||||
]
|
||||
|
@ -21,6 +21,10 @@ type Service10 struct{}
|
||||
type Service11 struct{}
|
||||
type Service12 struct{}
|
||||
type Service13 struct{}
|
||||
type Service14 struct{}
|
||||
type Service15 struct{}
|
||||
|
||||
// type SimplifiedFactory[T any] = Factory[T, Service15]
|
||||
|
||||
func main() {
|
||||
factory := NewFactory[Service1, Service2]()
|
||||
@ -38,6 +42,7 @@ func main() {
|
||||
other.CustomNewService(Service7{}),
|
||||
other.ServiceInitialiser[Service8]()(&Service8{}),
|
||||
application.NewServiceWithOptions(&Service13{}, application.ServiceOptions{Name: "custom name"}),
|
||||
// SimplifiedFactory[Service14]{}.Get(),
|
||||
other.LocalService,
|
||||
},
|
||||
CustomNewServices[Service9, Service10]()...),
|
||||
|
@ -2,6 +2,6 @@ package other
|
||||
|
||||
import "github.com/wailsapp/wails/v3/pkg/application"
|
||||
|
||||
type Service14 int
|
||||
type Service16 int
|
||||
|
||||
var LocalService = application.NewService(new(Service14))
|
||||
var LocalService = application.NewService(new(Service16))
|
||||
|
@ -0,0 +1,5 @@
|
||||
[
|
||||
".InternalService",
|
||||
".Service",
|
||||
".unexportedService"
|
||||
]
|
11
v3/internal/generator/testcases/directives/includes.go
Normal file
11
v3/internal/generator/testcases/directives/includes.go
Normal file
@ -0,0 +1,11 @@
|
||||
//wails:include js/test.js
|
||||
//wails:include **:js/test_all.js
|
||||
//wails:include *c:js/test_c.js
|
||||
//wails:include *i:js/test_i.js
|
||||
//wails:include j*:js/test_j.js
|
||||
//wails:include jc:js/test_jc.js
|
||||
//wails:include ji:js/test_ji.js
|
||||
//wails:include t*:js/test_t.ts
|
||||
//wails:include tc:js/test_tc.ts
|
||||
//wails:include ti:js/test_ti.ts
|
||||
package main
|
15
v3/internal/generator/testcases/directives/internal.go
Normal file
15
v3/internal/generator/testcases/directives/internal.go
Normal file
@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
// An exported but internal model.
|
||||
//
|
||||
//wails:internal
|
||||
type InternalModel struct {
|
||||
Field string
|
||||
}
|
||||
|
||||
// An exported but internal service.
|
||||
//
|
||||
//wails:internal
|
||||
type InternalService struct{}
|
||||
|
||||
func (InternalService) Method(InternalModel) {}
|
3
v3/internal/generator/testcases/directives/js/test.js
Normal file
3
v3/internal/generator/testcases/directives/js/test.js
Normal file
@ -0,0 +1,3 @@
|
||||
import { CustomMethod } from "./service.js";
|
||||
|
||||
CustomMethod("everywhere");
|
@ -0,0 +1,3 @@
|
||||
import { CustomMethod } from "./service.js";
|
||||
|
||||
CustomMethod("everywhere again");
|
3
v3/internal/generator/testcases/directives/js/test_c.js
Normal file
3
v3/internal/generator/testcases/directives/js/test_c.js
Normal file
@ -0,0 +1,3 @@
|
||||
import { CustomMethod } from "./service.js";
|
||||
|
||||
CustomMethod("Classes");
|
3
v3/internal/generator/testcases/directives/js/test_i.js
Normal file
3
v3/internal/generator/testcases/directives/js/test_i.js
Normal file
@ -0,0 +1,3 @@
|
||||
import { CustomMethod } from "./service.js";
|
||||
|
||||
CustomMethod("Interfaces");
|
3
v3/internal/generator/testcases/directives/js/test_j.js
Normal file
3
v3/internal/generator/testcases/directives/js/test_j.js
Normal file
@ -0,0 +1,3 @@
|
||||
import { CustomMethod } from "./service.js";
|
||||
|
||||
CustomMethod("JS");
|
3
v3/internal/generator/testcases/directives/js/test_jc.js
Normal file
3
v3/internal/generator/testcases/directives/js/test_jc.js
Normal file
@ -0,0 +1,3 @@
|
||||
import { CustomMethod } from "./service.js";
|
||||
|
||||
CustomMethod("JS Classes");
|
3
v3/internal/generator/testcases/directives/js/test_ji.js
Normal file
3
v3/internal/generator/testcases/directives/js/test_ji.js
Normal file
@ -0,0 +1,3 @@
|
||||
import { CustomMethod } from "./service.js";
|
||||
|
||||
CustomMethod("JS Interfaces");
|
3
v3/internal/generator/testcases/directives/js/test_t.ts
Normal file
3
v3/internal/generator/testcases/directives/js/test_t.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import { CustomMethod } from "./service.js";
|
||||
|
||||
CustomMethod("TS");
|
3
v3/internal/generator/testcases/directives/js/test_tc.ts
Normal file
3
v3/internal/generator/testcases/directives/js/test_tc.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import { CustomMethod } from "./service.js";
|
||||
|
||||
CustomMethod("TS Classes");
|
3
v3/internal/generator/testcases/directives/js/test_ti.ts
Normal file
3
v3/internal/generator/testcases/directives/js/test_ti.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import { CustomMethod } from "./service.js";
|
||||
|
||||
CustomMethod("TS Interfaces");
|
60
v3/internal/generator/testcases/directives/main.go
Normal file
60
v3/internal/generator/testcases/directives/main.go
Normal file
@ -0,0 +1,60 @@
|
||||
//wails:inject console.log("Hello everywhere!");
|
||||
//wails:inject **:console.log("Hello everywhere again!");
|
||||
//wails:inject *c:console.log("Hello Classes!");
|
||||
//wails:inject *i:console.log("Hello Interfaces!");
|
||||
//wails:inject j*:console.log("Hello JS!");
|
||||
//wails:inject jc:console.log("Hello JS Classes!");
|
||||
//wails:inject ji:console.log("Hello JS Interfaces!");
|
||||
//wails:inject t*:console.log("Hello TS!");
|
||||
//wails:inject tc:console.log("Hello TS Classes!");
|
||||
//wails:inject ti:console.log("Hello TS Interfaces!");
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"log"
|
||||
|
||||
"github.com/wailsapp/wails/v3/internal/generator/testcases/directives/otherpackage"
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
)
|
||||
|
||||
type IgnoredType struct {
|
||||
Field int
|
||||
}
|
||||
|
||||
//wails:inject j*:/**
|
||||
//wails:inject j*: * @param {string} arg
|
||||
//wails:inject j*: * @returns {Promise<void>}
|
||||
//wails:inject j*: */
|
||||
//wails:inject j*:export async function CustomMethod(arg) {
|
||||
//wails:inject t*:export async function CustomMethod(arg: string): Promise<void> {
|
||||
//wails:inject await InternalMethod("Hello " + arg + "!");
|
||||
//wails:inject }
|
||||
type Service struct{}
|
||||
|
||||
func (*Service) VisibleMethod(otherpackage.Dummy) {}
|
||||
|
||||
//wails:ignore
|
||||
func (*Service) IgnoredMethod(IgnoredType) {}
|
||||
|
||||
//wails:internal
|
||||
func (*Service) InternalMethod(string) {}
|
||||
|
||||
func main() {
|
||||
app := application.New(application.Options{
|
||||
Services: []application.Service{
|
||||
application.NewService(&Service{}),
|
||||
application.NewService(&unexportedService{}),
|
||||
application.NewService(&InternalService{}),
|
||||
},
|
||||
})
|
||||
|
||||
app.NewWebviewWindow()
|
||||
|
||||
err := app.Run()
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
//wails:include jc:js/*_j*.js
|
||||
//wails:include tc:js/*_t*.ts
|
||||
package otherpackage
|
||||
|
||||
type Dummy struct{}
|
@ -0,0 +1,3 @@
|
||||
import { CustomMethod } from "../service.js";
|
||||
|
||||
CustomMethod("JS");
|
@ -0,0 +1,3 @@
|
||||
import { CustomMethod } from "../service.js";
|
||||
|
||||
CustomMethod("JS Classes");
|
@ -0,0 +1,3 @@
|
||||
import { CustomMethod } from "../service.js";
|
||||
|
||||
CustomMethod("TS");
|
@ -0,0 +1,3 @@
|
||||
import { CustomMethod } from "../service.js";
|
||||
|
||||
CustomMethod("TS Classes");
|
11
v3/internal/generator/testcases/directives/unexported.go
Normal file
11
v3/internal/generator/testcases/directives/unexported.go
Normal file
@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
// An unexported model.
|
||||
type unexportedModel struct {
|
||||
Field string
|
||||
}
|
||||
|
||||
// An unexported service.
|
||||
type unexportedService struct{}
|
||||
|
||||
func (unexportedService) Method(unexportedModel) {}
|
@ -19,6 +19,19 @@ const (
|
||||
Dr Title = "Dr"
|
||||
)
|
||||
|
||||
// Age is an integer with some predefined values
|
||||
type Age = int
|
||||
|
||||
const (
|
||||
NewBorn Age = 0
|
||||
Teenager Age = 12
|
||||
YoungAdult Age = 18
|
||||
|
||||
// Oh no, some grey hair!
|
||||
MiddleAged Age = 50
|
||||
Mathusalem Age = 1000 // Unbelievable!
|
||||
)
|
||||
|
||||
// GreetService is great
|
||||
type GreetService struct {
|
||||
SomeVariable int
|
||||
@ -30,6 +43,7 @@ type GreetService struct {
|
||||
type Person struct {
|
||||
Title Title
|
||||
Name string
|
||||
Age Age
|
||||
}
|
||||
|
||||
// Greet does XYZ
|
||||
|
@ -0,0 +1,3 @@
|
||||
[
|
||||
".Service"
|
||||
]
|
307
v3/internal/generator/testcases/map_keys/main.go
Normal file
307
v3/internal/generator/testcases/map_keys/main.go
Normal file
@ -0,0 +1,307 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"log"
|
||||
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
)
|
||||
|
||||
type Service struct{}
|
||||
|
||||
type NonTextMarshaler struct{}
|
||||
|
||||
type ValueTextMarshaler struct{}
|
||||
|
||||
func (ValueTextMarshaler) MarshalText() ([]byte, error) { return nil, nil }
|
||||
|
||||
type PointerTextMarshaler struct{}
|
||||
|
||||
func (*PointerTextMarshaler) MarshalText() ([]byte, error) { return nil, nil }
|
||||
|
||||
type JsonTextMarshaler struct{}
|
||||
|
||||
func (JsonTextMarshaler) MarshalJSON() ([]byte, error) { return nil, nil }
|
||||
func (JsonTextMarshaler) MarshalText() ([]byte, error) { return nil, nil }
|
||||
|
||||
type CustomInterface interface {
|
||||
MarshalText() ([]byte, error)
|
||||
}
|
||||
|
||||
type EmbeddedInterface interface {
|
||||
encoding.TextMarshaler
|
||||
}
|
||||
|
||||
type EmbeddedInterfaces interface {
|
||||
json.Marshaler
|
||||
encoding.TextMarshaler
|
||||
}
|
||||
|
||||
type BasicConstraint interface {
|
||||
~int | ~int8 | ~int16 | ~int32 | ~int64 |
|
||||
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 |
|
||||
~string
|
||||
}
|
||||
|
||||
type BadTildeConstraint interface {
|
||||
int | ~struct{} | string
|
||||
}
|
||||
|
||||
type GoodTildeConstraint interface {
|
||||
int | ~struct{} | string
|
||||
MarshalText() ([]byte, error)
|
||||
}
|
||||
|
||||
type NonBasicConstraint interface {
|
||||
ValueTextMarshaler | *PointerTextMarshaler
|
||||
}
|
||||
|
||||
type PointableConstraint interface {
|
||||
ValueTextMarshaler | PointerTextMarshaler
|
||||
}
|
||||
|
||||
type MixedConstraint interface {
|
||||
uint | ~string | ValueTextMarshaler | *PointerTextMarshaler
|
||||
}
|
||||
|
||||
type InterfaceConstraint interface {
|
||||
comparable
|
||||
encoding.TextMarshaler
|
||||
}
|
||||
|
||||
type PointerConstraint[T comparable] interface {
|
||||
*T
|
||||
encoding.TextMarshaler
|
||||
}
|
||||
|
||||
type EmbeddedValue struct{ ValueTextMarshaler }
|
||||
type EmbeddedValuePtr struct{ *ValueTextMarshaler }
|
||||
type EmbeddedPointer struct{ PointerTextMarshaler }
|
||||
type EmbeddedPointerPtr struct{ *PointerTextMarshaler }
|
||||
|
||||
type EmbeddedCustomInterface struct{ CustomInterface }
|
||||
type EmbeddedOriginalInterface struct{ encoding.TextMarshaler }
|
||||
|
||||
type WrongType bool
|
||||
type WrongAlias = bool
|
||||
type StringType string
|
||||
type StringAlias = string
|
||||
type IntType int
|
||||
type IntAlias = int
|
||||
|
||||
type ValueType ValueTextMarshaler
|
||||
type ValuePtrType *ValueTextMarshaler
|
||||
type ValueAlias = ValueTextMarshaler
|
||||
type ValuePtrAlias = *ValueTextMarshaler
|
||||
|
||||
type PointerType PointerTextMarshaler
|
||||
type PointerPtrType *PointerTextMarshaler
|
||||
type PointerAlias = PointerTextMarshaler
|
||||
type PointerPtrAlias = *PointerTextMarshaler
|
||||
|
||||
type InterfaceType encoding.TextMarshaler
|
||||
type InterfacePtrType *encoding.TextMarshaler
|
||||
type InterfaceAlias = encoding.TextMarshaler
|
||||
type InterfacePtrAlias = *encoding.TextMarshaler
|
||||
|
||||
// type ComparableCstrAlias[R comparable] = R
|
||||
// type ComparableCstrPtrAlias[R comparable] = *R
|
||||
// type BasicCstrAlias[S BasicConstraint] = S
|
||||
// type BasicCstrPtrAlias[S BasicConstraint] = *S
|
||||
// type BadTildeCstrAlias[T BadTildeConstraint] = T
|
||||
// type BadTildeCstrPtrAlias[T BadTildeConstraint] = *T
|
||||
// type GoodTildeCstrAlias[U GoodTildeConstraint] = U
|
||||
// type GoodTildeCstrPtrAlias[U GoodTildeConstraint] = *U
|
||||
// type NonBasicCstrAlias[V NonBasicConstraint] = V
|
||||
// type NonBasicCstrPtrAlias[V NonBasicConstraint] = *V
|
||||
// type PointableCstrAlias[W PointableConstraint] = W
|
||||
// type PointableCstrPtrAlias[W PointableConstraint] = *W
|
||||
// type MixedCstrAlias[X MixedConstraint] = X
|
||||
// type MixedCstrPtrAlias[X MixedConstraint] = *X
|
||||
// type InterfaceCstrAlias[Y InterfaceConstraint] = Y
|
||||
// type InterfaceCstrPtrAlias[Y InterfaceConstraint] = *Y
|
||||
// type PointerCstrAlias[R comparable, Z PointerConstraint[R]] = Z
|
||||
// type PointerCstrPtrAlias[R comparable, Z PointerConstraint[R]] = *Z
|
||||
|
||||
type Maps[R comparable, S BasicConstraint, T BadTildeConstraint, U GoodTildeConstraint, V NonBasicConstraint, W PointableConstraint, X MixedConstraint, Y InterfaceConstraint, Z PointerConstraint[R]] struct {
|
||||
Bool map[bool]int // Reject
|
||||
Int map[int]int // Accept
|
||||
Uint map[uint]int // Accept
|
||||
Float map[float32]int // Reject
|
||||
Complex map[complex64]int // Reject
|
||||
Byte map[byte]int // Accept
|
||||
Rune map[rune]int // Accept
|
||||
String map[string]int // Accept
|
||||
|
||||
IntPtr map[*int]int // Reject
|
||||
UintPtr map[*uint]int // Reject
|
||||
FloatPtr map[*float32]int // Reject
|
||||
ComplexPtr map[*complex64]int // Reject
|
||||
StringPtr map[*string]int // Reject
|
||||
|
||||
NTM map[NonTextMarshaler]int // Reject
|
||||
NTMPtr map[*NonTextMarshaler]int // Reject
|
||||
VTM map[ValueTextMarshaler]int // Accept
|
||||
VTMPtr map[*ValueTextMarshaler]int // Accept
|
||||
PTM map[PointerTextMarshaler]int // Reject
|
||||
PTMPtr map[*PointerTextMarshaler]int // Accept
|
||||
JTM map[JsonTextMarshaler]int // Accept, hide
|
||||
JTMPtr map[*JsonTextMarshaler]int // Accept, hide
|
||||
|
||||
A map[any]int // Reject
|
||||
APtr map[*any]int // Reject
|
||||
TM map[encoding.TextMarshaler]int // Accept, hide
|
||||
TMPtr map[*encoding.TextMarshaler]int // Reject
|
||||
CI map[CustomInterface]int // Accept, hide
|
||||
CIPtr map[*CustomInterface]int // Reject
|
||||
EI map[EmbeddedInterface]int // Accept, hide
|
||||
EIPtr map[*EmbeddedInterface]int // Reject
|
||||
|
||||
EV map[EmbeddedValue]int // Accept
|
||||
EVPtr map[*EmbeddedValue]int // Accept
|
||||
EVP map[EmbeddedValuePtr]int // Accept
|
||||
EVPPtr map[*EmbeddedValuePtr]int // Accept
|
||||
EP map[EmbeddedPointer]int // Reject
|
||||
EPPtr map[*EmbeddedPointer]int // Accept
|
||||
EPP map[EmbeddedPointerPtr]int // Accept
|
||||
EPPPtr map[*EmbeddedPointerPtr]int // Accept
|
||||
|
||||
ECI map[EmbeddedCustomInterface]int // Accept
|
||||
ECIPtr map[*EmbeddedCustomInterface]int // Accept
|
||||
EOI map[EmbeddedOriginalInterface]int // Accept
|
||||
EOIPtr map[*EmbeddedOriginalInterface]int // Accept
|
||||
|
||||
WT map[WrongType]int // Reject
|
||||
WA map[WrongAlias]int // Reject
|
||||
ST map[StringType]int // Accept
|
||||
SA map[StringAlias]int // Accept
|
||||
IntT map[IntType]int // Accept
|
||||
IntA map[IntAlias]int // Accept
|
||||
|
||||
VT map[ValueType]int // Reject
|
||||
VTPtr map[*ValueType]int // Reject
|
||||
VPT map[ValuePtrType]int // Reject
|
||||
VPTPtr map[*ValuePtrType]int // Reject
|
||||
VA map[ValueAlias]int // Accept
|
||||
VAPtr map[*ValueAlias]int // Accept
|
||||
VPA map[ValuePtrAlias]int // Accept, hide
|
||||
VPAPtr map[*ValuePtrAlias]int // Reject
|
||||
|
||||
PT map[PointerType]int // Reject
|
||||
PTPtr map[*PointerType]int // Reject
|
||||
PPT map[PointerPtrType]int // Reject
|
||||
PPTPtr map[*PointerPtrType]int // Reject
|
||||
PA map[PointerAlias]int // Reject
|
||||
PAPtr map[*PointerAlias]int // Accept
|
||||
PPA map[PointerPtrAlias]int // Accept, hide
|
||||
PPAPtr map[*PointerPtrAlias]int // Reject
|
||||
|
||||
IT map[InterfaceType]int // Accept, hide
|
||||
ITPtr map[*InterfaceType]int // Reject
|
||||
IPT map[InterfacePtrType]int // Reject
|
||||
IPTPtr map[*InterfacePtrType]int // Reject
|
||||
IA map[InterfaceAlias]int // Accept, hide
|
||||
IAPtr map[*InterfaceAlias]int // Reject
|
||||
IPA map[InterfacePtrAlias]int // Reject
|
||||
IPAPtr map[*InterfacePtrAlias]int // Reject
|
||||
|
||||
TPR map[R]int // Soft reject
|
||||
TPRPtr map[*R]int // Soft reject
|
||||
TPS map[S]int // Accept, hide
|
||||
TPSPtr map[*S]int // Soft reject
|
||||
TPT map[T]int // Soft reject
|
||||
TPTPtr map[*T]int // Soft reject
|
||||
TPU map[U]int // Accept, hide
|
||||
TPUPtr map[*U]int // Soft reject
|
||||
TPV map[V]int // Accept, hide
|
||||
TPVPtr map[*V]int // Soft reject
|
||||
TPW map[W]int // Soft reject
|
||||
TPWPtr map[*W]int // Accept, hide
|
||||
TPX map[X]int // Accept, hide
|
||||
TPXPtr map[*X]int // Soft reject
|
||||
TPY map[Y]int // Accept, hide
|
||||
TPYPtr map[*Y]int // Soft reject
|
||||
TPZ map[Z]int // Accept, hide
|
||||
TPZPtr map[*Z]int // Soft reject
|
||||
|
||||
// GAR map[ComparableCstrAlias[R]]int // Soft reject
|
||||
// GARPtr map[ComparableCstrPtrAlias[R]]int // Soft reject
|
||||
// GAS map[BasicCstrAlias[S]]int // Accept, hide
|
||||
// GASPtr map[BasicCstrPtrAlias[S]]int // Soft reject
|
||||
// GAT map[BadTildeCstrAlias[T]]int // Soft reject
|
||||
// GATPtr map[BadTildeCstrPtrAlias[T]]int // Soft reject
|
||||
// GAU map[GoodTildeCstrAlias[U]]int // Accept, hide
|
||||
// GAUPtr map[GoodTildeCstrPtrAlias[U]]int // Soft reject
|
||||
// GAV map[NonBasicCstrAlias[V]]int // Accept, hide
|
||||
// GAVPtr map[NonBasicCstrPtrAlias[V]]int // Soft reject
|
||||
// GAW map[PointableCstrAlias[W]]int // Soft reject
|
||||
// GAWPtr map[PointableCstrPtrAlias[W]]int // Accept, hide
|
||||
// GAX map[MixedCstrAlias[X]]int // Accept, hide
|
||||
// GAXPtr map[MixedCstrPtrAlias[X]]int // Soft reject
|
||||
// GAY map[InterfaceCstrAlias[Y]]int // Accept, hide
|
||||
// GAYPtr map[InterfaceCstrPtrAlias[Y]]int // Soft reject
|
||||
// GAZ map[PointerCstrAlias[R, Z]]int // Accept, hide
|
||||
// GAZPtr map[PointerCstrPtrAlias[R, Z]]int // Soft reject
|
||||
|
||||
// GACi map[ComparableCstrAlias[int]]int // Accept, hide
|
||||
// GACV map[ComparableCstrAlias[ValueTextMarshaler]]int // Accept
|
||||
// GACP map[ComparableCstrAlias[PointerTextMarshaler]]int // Reject
|
||||
// GACiPtr map[ComparableCstrPtrAlias[int]]int // Reject
|
||||
// GACVPtr map[ComparableCstrPtrAlias[ValueTextMarshaler]]int // Accept, hide
|
||||
// GACPPtr map[ComparableCstrPtrAlias[PointerTextMarshaler]]int // Accept, hide
|
||||
// GABi map[BasicCstrAlias[int]]int // Accept, hide
|
||||
// GABs map[BasicCstrAlias[string]]int // Accept
|
||||
// GABiPtr map[BasicCstrPtrAlias[int]]int // Reject
|
||||
// GABT map[BadTildeCstrAlias[struct{}]]int // Reject
|
||||
// GABTPtr map[BadTildeCstrPtrAlias[struct{}]]int // Reject
|
||||
// GAGT map[GoodTildeCstrAlias[ValueTextMarshaler]]int // Accept
|
||||
// GAGTPtr map[GoodTildeCstrPtrAlias[ValueTextMarshaler]]int // Accept, hide
|
||||
// GANBV map[NonBasicCstrAlias[ValueTextMarshaler]]int // Accept
|
||||
// GANBP map[NonBasicCstrAlias[*PointerTextMarshaler]]int // Accept, hide
|
||||
// GANBVPtr map[NonBasicCstrPtrAlias[ValueTextMarshaler]]int // Accept, hide
|
||||
// GANBPPtr map[NonBasicCstrPtrAlias[*PointerTextMarshaler]]int // Reject
|
||||
// GAPlV1 map[PointableCstrAlias[ValueTextMarshaler]]int // Accept
|
||||
// GAPlV2 map[*PointableCstrAlias[ValueTextMarshaler]]int // Accept
|
||||
// GAPlP1 map[PointableCstrAlias[PointerTextMarshaler]]int // Reject
|
||||
// GAPlP2 map[*PointableCstrAlias[PointerTextMarshaler]]int // Accept
|
||||
// GAPlVPtr map[PointableCstrPtrAlias[ValueTextMarshaler]]int // Accept, hide
|
||||
// GAPlPPtr map[PointableCstrPtrAlias[PointerTextMarshaler]]int // Accept, hide
|
||||
// GAMi map[MixedCstrAlias[uint]]int // Accept, hide
|
||||
// GAMS map[MixedCstrAlias[StringType]]int // Accept
|
||||
// GAMV map[MixedCstrAlias[ValueTextMarshaler]]int // Accept
|
||||
// GAMSPtr map[MixedCstrPtrAlias[StringType]]int // Reject
|
||||
// GAMVPtr map[MixedCstrPtrAlias[ValueTextMarshaler]]int // Accept, hide
|
||||
// GAII map[InterfaceCstrAlias[encoding.TextMarshaler]]int // Accept, hide
|
||||
// GAIV map[InterfaceCstrAlias[ValueTextMarshaler]]int // Accept
|
||||
// GAIP map[InterfaceCstrAlias[*PointerTextMarshaler]]int // Accept, hide
|
||||
// GAIIPtr map[InterfaceCstrPtrAlias[encoding.TextMarshaler]]int // Reject
|
||||
// GAIVPtr map[InterfaceCstrPtrAlias[ValueTextMarshaler]]int // Accept, hide
|
||||
// GAIPPtr map[InterfaceCstrPtrAlias[*PointerTextMarshaler]]int // Reject
|
||||
// GAPrV map[PointerCstrAlias[ValueTextMarshaler, *ValueTextMarshaler]]int // Accept, hide
|
||||
// GAPrP map[PointerCstrAlias[PointerTextMarshaler, *PointerTextMarshaler]]int // Accept, hide
|
||||
// GAPrVPtr map[PointerCstrPtrAlias[ValueTextMarshaler, *ValueTextMarshaler]]int // Reject
|
||||
// GAPrPPtr map[PointerCstrPtrAlias[PointerTextMarshaler, *PointerTextMarshaler]]int // Reject
|
||||
}
|
||||
|
||||
func (*Service) Method() (_ Maps[PointerTextMarshaler, int, int, ValueTextMarshaler, *PointerTextMarshaler, ValueTextMarshaler, StringType, ValueTextMarshaler, *PointerTextMarshaler]) {
|
||||
return
|
||||
}
|
||||
|
||||
func main() {
|
||||
app := application.New(application.Options{
|
||||
Services: []application.Service{
|
||||
application.NewService(&Service{}),
|
||||
},
|
||||
})
|
||||
|
||||
app.NewWebviewWindow()
|
||||
|
||||
err := app.Run()
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
[
|
||||
".Service"
|
||||
]
|
209
v3/internal/generator/testcases/marshalers/main.go
Normal file
209
v3/internal/generator/testcases/marshalers/main.go
Normal file
@ -0,0 +1,209 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"log"
|
||||
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
)
|
||||
|
||||
type Service struct{}
|
||||
|
||||
// class {}
|
||||
type NonMarshaler struct{}
|
||||
|
||||
// any
|
||||
type ValueJsonMarshaler struct{}
|
||||
|
||||
func (ValueJsonMarshaler) MarshalJSON() ([]byte, error) { return nil, nil }
|
||||
|
||||
// any
|
||||
type PointerJsonMarshaler struct{}
|
||||
|
||||
func (*PointerJsonMarshaler) MarshalJSON() ([]byte, error) { return nil, nil }
|
||||
|
||||
// string
|
||||
type ValueTextMarshaler struct{}
|
||||
|
||||
func (ValueTextMarshaler) MarshalText() ([]byte, error) { return nil, nil }
|
||||
|
||||
// string
|
||||
type PointerTextMarshaler struct{}
|
||||
|
||||
func (*PointerTextMarshaler) MarshalText() ([]byte, error) { return nil, nil }
|
||||
|
||||
// any
|
||||
type ValueMarshaler struct{}
|
||||
|
||||
func (ValueMarshaler) MarshalJSON() ([]byte, error) { return nil, nil }
|
||||
func (ValueMarshaler) MarshalText() ([]byte, error) { return nil, nil }
|
||||
|
||||
// any
|
||||
type PointerMarshaler struct{}
|
||||
|
||||
func (*PointerMarshaler) MarshalJSON() ([]byte, error) { return nil, nil }
|
||||
func (*PointerMarshaler) MarshalText() ([]byte, error) { return nil, nil }
|
||||
|
||||
// any
|
||||
type UnderlyingJsonMarshaler struct{ json.Marshaler }
|
||||
|
||||
// string
|
||||
type UnderlyingTextMarshaler struct{ encoding.TextMarshaler }
|
||||
|
||||
// any
|
||||
type UnderlyingMarshaler struct {
|
||||
json.Marshaler
|
||||
encoding.TextMarshaler
|
||||
}
|
||||
|
||||
type customJsonMarshaler interface {
|
||||
MarshalJSON() ([]byte, error)
|
||||
}
|
||||
|
||||
type customTextMarshaler interface {
|
||||
MarshalText() ([]byte, error)
|
||||
}
|
||||
|
||||
type customMarshaler interface {
|
||||
MarshalJSON() ([]byte, error)
|
||||
MarshalText() ([]byte, error)
|
||||
}
|
||||
|
||||
// struct{}
|
||||
type AliasNonMarshaler = struct{}
|
||||
|
||||
// any
|
||||
type AliasJsonMarshaler = struct{ json.Marshaler }
|
||||
|
||||
// string
|
||||
type AliasTextMarshaler = struct{ encoding.TextMarshaler }
|
||||
|
||||
// any
|
||||
type AliasMarshaler = struct {
|
||||
json.Marshaler
|
||||
encoding.TextMarshaler
|
||||
}
|
||||
|
||||
// any
|
||||
type ImplicitJsonMarshaler UnderlyingJsonMarshaler
|
||||
|
||||
// string
|
||||
type ImplicitTextMarshaler UnderlyingTextMarshaler
|
||||
|
||||
// any
|
||||
type ImplicitMarshaler UnderlyingMarshaler
|
||||
|
||||
// string
|
||||
type ImplicitNonJson UnderlyingMarshaler
|
||||
|
||||
func (ImplicitNonJson) MarshalJSON() {}
|
||||
|
||||
// any
|
||||
type ImplicitNonText UnderlyingMarshaler
|
||||
|
||||
func (ImplicitNonText) MarshalText() {}
|
||||
|
||||
// class{ Marshaler, TextMarshaler }
|
||||
type ImplicitNonMarshaler UnderlyingMarshaler
|
||||
|
||||
func (ImplicitNonMarshaler) MarshalJSON() {}
|
||||
func (ImplicitNonMarshaler) MarshalText() {}
|
||||
|
||||
// any
|
||||
type ImplicitJsonButText UnderlyingJsonMarshaler
|
||||
|
||||
func (ImplicitJsonButText) MarshalText() ([]byte, error) { return nil, nil }
|
||||
|
||||
// any
|
||||
type ImplicitTextButJson UnderlyingTextMarshaler
|
||||
|
||||
func (ImplicitTextButJson) MarshalJSON() ([]byte, error) { return nil, nil }
|
||||
|
||||
type Data struct {
|
||||
NM NonMarshaler
|
||||
NMPtr *NonMarshaler // NonMarshaler | null
|
||||
|
||||
VJM ValueJsonMarshaler
|
||||
VJMPtr *ValueJsonMarshaler // ValueJsonMarshaler | null
|
||||
PJM PointerJsonMarshaler
|
||||
PJMPtr *PointerJsonMarshaler // PointerJsonMarshaler | null
|
||||
|
||||
VTM ValueTextMarshaler
|
||||
VTMPtr *ValueTextMarshaler // ValueTextMarshaler | null
|
||||
PTM PointerTextMarshaler
|
||||
PTMPtr *PointerTextMarshaler // PointerTextMarshaler | null
|
||||
|
||||
VM ValueMarshaler
|
||||
VMPtr *ValueMarshaler // ValueMarshaler | null
|
||||
PM PointerMarshaler
|
||||
PMPtr *PointerMarshaler // PointerMarshaler | null
|
||||
|
||||
UJM UnderlyingJsonMarshaler
|
||||
UJMPtr *UnderlyingJsonMarshaler // UnderlyingJsonMarshaler | null
|
||||
UTM UnderlyingTextMarshaler
|
||||
UTMPtr *UnderlyingTextMarshaler // UnderlyingTextMarshaler | null
|
||||
UM UnderlyingMarshaler
|
||||
UMPtr *UnderlyingMarshaler // UnderlyingMarshaler | null
|
||||
|
||||
JM struct{ json.Marshaler } // any
|
||||
JMPtr *struct{ json.Marshaler } // any | null
|
||||
TM struct{ encoding.TextMarshaler } // string
|
||||
TMPtr *struct{ encoding.TextMarshaler } // string | null
|
||||
CJM struct{ customJsonMarshaler } // any
|
||||
CJMPtr *struct{ customJsonMarshaler } // any | null
|
||||
CTM struct{ customTextMarshaler } // string
|
||||
CTMPtr *struct{ customTextMarshaler } // string | null
|
||||
CM struct{ customMarshaler } // any
|
||||
CMPtr *struct{ customMarshaler } // any | null
|
||||
|
||||
ANM AliasNonMarshaler
|
||||
ANMPtr *AliasNonMarshaler // AliasNonMarshaler | null
|
||||
AJM AliasJsonMarshaler
|
||||
AJMPtr *AliasJsonMarshaler // AliasJsonMarshaler | null
|
||||
ATM AliasTextMarshaler
|
||||
ATMPtr *AliasTextMarshaler // AliasTextMarshaler | null
|
||||
AM AliasMarshaler
|
||||
AMPtr *AliasMarshaler // AliasMarshaler | null
|
||||
|
||||
ImJM ImplicitJsonMarshaler
|
||||
ImJMPtr *ImplicitJsonMarshaler // ImplicitJsonMarshaler | null
|
||||
ImTM ImplicitTextMarshaler
|
||||
ImTMPtr *ImplicitTextMarshaler // ImplicitTextMarshaler | null
|
||||
ImM ImplicitMarshaler
|
||||
ImMPtr *ImplicitMarshaler // ImplicitMarshaler | null
|
||||
|
||||
ImNJ ImplicitNonJson
|
||||
ImNJPtr *ImplicitNonJson // ImplicitNonJson | null
|
||||
ImNT ImplicitNonText
|
||||
ImNTPtr *ImplicitNonText // ImplicitNonText | null
|
||||
ImNM ImplicitNonMarshaler
|
||||
ImNMPtr *ImplicitNonMarshaler // ImplicitNonMarshaler | null
|
||||
|
||||
ImJbT ImplicitJsonButText
|
||||
ImJbTPtr *ImplicitJsonButText // ImplicitJsonButText | null
|
||||
ImTbJ ImplicitTextButJson
|
||||
ImTbJPtr *ImplicitTextButJson // ImplicitTextButJson | null
|
||||
}
|
||||
|
||||
func (*Service) Method() (_ Data) {
|
||||
return
|
||||
}
|
||||
|
||||
func main() {
|
||||
app := application.New(application.Options{
|
||||
Services: []application.Service{
|
||||
application.NewService(&Service{}),
|
||||
},
|
||||
})
|
||||
|
||||
app.NewWebviewWindow()
|
||||
|
||||
err := app.Run()
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
@ -10,14 +10,14 @@ type Person struct {
|
||||
}
|
||||
|
||||
// Impersonator gets their fields from other people.
|
||||
type Impersonator other.OtherPerson[int]
|
||||
type Impersonator = other.OtherPerson[int]
|
||||
|
||||
// HowDifferent is a curious kind of person
|
||||
// that lets other people decide how they are different.
|
||||
type HowDifferent[How any] other.OtherPerson[map[string]How]
|
||||
|
||||
// PrivatePerson gets their fields from hidden sources.
|
||||
type PrivatePerson personImpl
|
||||
type PrivatePerson = personImpl
|
||||
|
||||
type personImpl struct {
|
||||
// Nickname conceals a person's identity.
|
||||
|
@ -174,7 +174,7 @@ func (GreetService) MapIntInt(in map[int]int) {
|
||||
func (GreetService) PointerMapIntInt(in *map[int]int) {
|
||||
}
|
||||
|
||||
func (GreetService) MapIntPointerInt(in map[*int]int) {
|
||||
func (GreetService) MapIntIntPointer(in map[int]*int) {
|
||||
}
|
||||
|
||||
func (GreetService) MapIntSliceInt(in map[int][]int) {
|
||||
|
@ -174,7 +174,7 @@ func (*GreetService) MapIntInt(in map[int]int) {
|
||||
func (*GreetService) PointerMapIntInt(in *map[int]int) {
|
||||
}
|
||||
|
||||
func (*GreetService) MapIntPointerInt(in map[*int]int) {
|
||||
func (*GreetService) MapIntIntPointer(in map[int]*int) {
|
||||
}
|
||||
|
||||
func (*GreetService) MapIntSliceInt(in map[int][]int) {
|
||||
|
@ -0,0 +1,13 @@
|
||||
// @ts-check
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
import * as $models from "./models.js";
|
||||
|
||||
/**
|
||||
* TextMarshaler is the interface implemented by an object that can
|
||||
* marshal itself into a textual form.
|
||||
*
|
||||
* MarshalText encodes the receiver into UTF-8-encoded text and returns the result.
|
||||
* @typedef {$models.TextMarshaler} TextMarshaler
|
||||
*/
|
@ -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";
|
||||
|
||||
/**
|
||||
* Marshaler is the interface implemented by types that
|
||||
* can marshal themselves into valid JSON.
|
||||
* @typedef {$models.Marshaler} Marshaler
|
||||
*/
|
@ -1,3 +1,4 @@
|
||||
// @ts-check
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
@ -5,8 +6,8 @@
|
||||
// @ts-ignore: Unused imports
|
||||
import {Create as $Create} from "/wails/runtime.js";
|
||||
|
||||
export type Alias = Cyclic | null;
|
||||
|
||||
export type Cyclic = { [_: string]: Alias }[];
|
||||
|
||||
export type GenericCyclic<T> = {"X": GenericCyclic<T | null> | null, "Y": (T | null)[]}[];
|
||||
/**
|
||||
* Marshaler is the interface implemented by types that
|
||||
* can marshal themselves into valid JSON.
|
||||
* @typedef {any} Marshaler
|
||||
*/
|
@ -1,3 +1,4 @@
|
||||
// @ts-check
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
@ -5,18 +6,10 @@
|
||||
// @ts-ignore: Unused imports
|
||||
import {Create as $Create} from "/wails/runtime.js";
|
||||
|
||||
export enum Title {
|
||||
/**
|
||||
* The Go zero value for the underlying type of the enum.
|
||||
*/
|
||||
$zero = "",
|
||||
|
||||
/**
|
||||
* Mister is a title
|
||||
*/
|
||||
Mister = "Mr",
|
||||
Miss = "Miss",
|
||||
Ms = "Ms",
|
||||
Mrs = "Mrs",
|
||||
Dr = "Dr",
|
||||
};
|
||||
/**
|
||||
* TextMarshaler is the interface implemented by an object that can
|
||||
* marshal itself into a textual form.
|
||||
*
|
||||
* MarshalText encodes the receiver into UTF-8-encoded text and returns the result.
|
||||
* @typedef {any} TextMarshaler
|
||||
*/
|
@ -13,7 +13,11 @@ import {Call as $Call, Create as $Create} from "/wails/runtime.js";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import * as $models from "./internal.js";
|
||||
import * as nobindingshere$0 from "../no_bindings_here/models.js";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import * as $models from "./models.js";
|
||||
|
||||
/**
|
||||
* Get someone.
|
||||
@ -56,6 +60,18 @@ export function GetButDifferent() {
|
||||
return $typingPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise<nobindingshere$0.PrivatePerson> & { cancel(): void }}
|
||||
*/
|
||||
export function GetButForeignPrivateAlias() {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(643456960));
|
||||
let $typingPromise = /** @type {any} */($resultPromise.then(($result) => {
|
||||
return $$createType2($result);
|
||||
}));
|
||||
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
|
||||
return $typingPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Greet a lot of unusual things.
|
||||
* @param {$models.EmptyAliasStruct} $0
|
||||
@ -65,7 +81,7 @@ export function GetButDifferent() {
|
||||
export function Greet($0, $1) {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(1411160069, $0, $1));
|
||||
let $typingPromise = /** @type {any} */($resultPromise.then(($result) => {
|
||||
return $$createType5($result);
|
||||
return $$createType6($result);
|
||||
}));
|
||||
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
|
||||
return $typingPromise;
|
||||
@ -74,12 +90,13 @@ export function Greet($0, $1) {
|
||||
// Private type creation functions
|
||||
const $$createType0 = $models.Person.createFrom;
|
||||
const $$createType1 = $models.GenericPerson.createFrom($Create.Any);
|
||||
const $$createType2 = $Create.Array($Create.Any);
|
||||
const $$createType2 = nobindingshere$0.personImpl.createFrom;
|
||||
const $$createType3 = $Create.Array($Create.Any);
|
||||
const $$createType4 = $Create.Struct({
|
||||
"NoMoreIdeas": $$createType3,
|
||||
});
|
||||
const $$createType4 = $Create.Array($Create.Any);
|
||||
const $$createType5 = $Create.Struct({
|
||||
"Foo": $$createType2,
|
||||
"Other": $$createType4,
|
||||
"NoMoreIdeas": $$createType4,
|
||||
});
|
||||
const $$createType6 = $Create.Struct({
|
||||
"Foo": $$createType3,
|
||||
"Other": $$createType5,
|
||||
});
|
||||
|
@ -7,4 +7,33 @@ export {
|
||||
GreetService
|
||||
};
|
||||
|
||||
export * from "./models.js";
|
||||
export {
|
||||
AliasedPerson,
|
||||
EmptyStruct,
|
||||
GenericPerson,
|
||||
Person,
|
||||
StrangelyAliasedPerson
|
||||
} from "./models.js";
|
||||
|
||||
import * as $models from "./models.js";
|
||||
|
||||
/**
|
||||
* A nice type Alias.
|
||||
* @typedef {$models.Alias} Alias
|
||||
*/
|
||||
|
||||
/**
|
||||
* A struct alias.
|
||||
* This should be rendered as a typedef or interface in every mode.
|
||||
* @typedef {$models.AliasStruct} AliasStruct
|
||||
*/
|
||||
|
||||
/**
|
||||
* An empty struct alias.
|
||||
* @typedef {$models.EmptyAliasStruct} EmptyAliasStruct
|
||||
*/
|
||||
|
||||
/**
|
||||
* Another struct alias.
|
||||
* @typedef {$models.OtherAliasStruct} OtherAliasStruct
|
||||
*/
|
||||
|
@ -1,166 +0,0 @@
|
||||
// @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";
|
||||
|
||||
/**
|
||||
* A nice type Alias.
|
||||
* @typedef {number} Alias
|
||||
*/
|
||||
|
||||
/**
|
||||
* A struct alias.
|
||||
* This should be rendered as a typedef or interface in every mode.
|
||||
* @typedef {Object} AliasStruct
|
||||
* @property {number[]} Foo - A field with a comment.
|
||||
* @property {string} [Bar] - Definitely not Foo.
|
||||
* @property {string} [Baz] - Definitely not Foo.
|
||||
* @property {OtherAliasStruct} Other - A nested alias struct.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An empty struct alias.
|
||||
* @typedef { {
|
||||
* } } EmptyAliasStruct
|
||||
*/
|
||||
|
||||
/**
|
||||
* An empty struct.
|
||||
*/
|
||||
export class EmptyStruct {
|
||||
/**
|
||||
* Creates a new EmptyStruct instance.
|
||||
* @param {Partial<EmptyStruct>} [$$source = {}] - The source object to create the EmptyStruct.
|
||||
*/
|
||||
constructor($$source = {}) {
|
||||
|
||||
Object.assign(this, $$source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new EmptyStruct instance from a string or object.
|
||||
* @param {any} [$$source = {}]
|
||||
* @returns {EmptyStruct}
|
||||
*/
|
||||
static createFrom($$source = {}) {
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
return new EmptyStruct(/** @type {Partial<EmptyStruct>} */($$parsedSource));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic struct containing an alias.
|
||||
* @template T
|
||||
*/
|
||||
export class GenericPerson {
|
||||
/**
|
||||
* Creates a new GenericPerson instance.
|
||||
* @param {Partial<GenericPerson<T>>} [$$source = {}] - The source object to create the GenericPerson.
|
||||
*/
|
||||
constructor($$source = {}) {
|
||||
if (!("Name" in $$source)) {
|
||||
/**
|
||||
* @member
|
||||
* @type {T | null}
|
||||
*/
|
||||
this["Name"] = null;
|
||||
}
|
||||
if (!("AliasedField" in $$source)) {
|
||||
/**
|
||||
* @member
|
||||
* @type {Alias}
|
||||
*/
|
||||
this["AliasedField"] = 0;
|
||||
}
|
||||
|
||||
Object.assign(this, $$source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given creation functions for each type parameter,
|
||||
* returns a creation function for a concrete instance
|
||||
* of the generic class GenericPerson.
|
||||
* @template T
|
||||
* @param {(source: any) => T} $$createParamT
|
||||
* @returns {($$source?: any) => GenericPerson<T>}
|
||||
*/
|
||||
static createFrom($$createParamT) {
|
||||
const $$createField0_0 = $$createParamT;
|
||||
return ($$source = {}) => {
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
if ("Name" in $$parsedSource) {
|
||||
$$parsedSource["Name"] = $$createField0_0($$parsedSource["Name"]);
|
||||
}
|
||||
return new GenericPerson(/** @type {Partial<GenericPerson<T>>} */($$parsedSource));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Another struct alias.
|
||||
* @typedef {Object} OtherAliasStruct
|
||||
* @property {number[]} NoMoreIdeas
|
||||
*/
|
||||
|
||||
/**
|
||||
* A non-generic struct containing an alias.
|
||||
*/
|
||||
export class Person {
|
||||
/**
|
||||
* Creates a new Person instance.
|
||||
* @param {Partial<Person>} [$$source = {}] - The source object to create the Person.
|
||||
*/
|
||||
constructor($$source = {}) {
|
||||
if (!("Name" in $$source)) {
|
||||
/**
|
||||
* The Person's name.
|
||||
* @member
|
||||
* @type {string}
|
||||
*/
|
||||
this["Name"] = "";
|
||||
}
|
||||
if (!("AliasedField" in $$source)) {
|
||||
/**
|
||||
* A random alias field.
|
||||
* @member
|
||||
* @type {Alias}
|
||||
*/
|
||||
this["AliasedField"] = 0;
|
||||
}
|
||||
|
||||
Object.assign(this, $$source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Person instance from a string or object.
|
||||
* @param {any} [$$source = {}]
|
||||
* @returns {Person}
|
||||
*/
|
||||
static createFrom($$source = {}) {
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
return new Person(/** @type {Partial<Person>} */($$parsedSource));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A class alias.
|
||||
*/
|
||||
export const AliasedPerson = Person;
|
||||
|
||||
/**
|
||||
* A class alias.
|
||||
* @typedef {Person} AliasedPerson
|
||||
*/
|
||||
|
||||
/**
|
||||
* Another class alias, but ordered after its aliased class.
|
||||
*/
|
||||
export const StrangelyAliasedPerson = Person;
|
||||
|
||||
/**
|
||||
* Another class alias, but ordered after its aliased class.
|
||||
* @typedef {Person} StrangelyAliasedPerson
|
||||
*/
|
@ -2,33 +2,165 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
export {
|
||||
AliasedPerson,
|
||||
EmptyStruct,
|
||||
GenericPerson,
|
||||
Person,
|
||||
StrangelyAliasedPerson
|
||||
} from "./internal.js";
|
||||
|
||||
import * as $models from "./internal.js";
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import {Create as $Create} from "/wails/runtime.js";
|
||||
|
||||
/**
|
||||
* A nice type Alias.
|
||||
* @typedef {$models.Alias} Alias
|
||||
* @typedef {number} Alias
|
||||
*/
|
||||
|
||||
/**
|
||||
* A struct alias.
|
||||
* This should be rendered as a typedef or interface in every mode.
|
||||
* @typedef {$models.AliasStruct} AliasStruct
|
||||
* @typedef {Object} AliasStruct
|
||||
* @property {number[]} Foo - A field with a comment.
|
||||
* @property {string} [Bar] - Definitely not Foo.
|
||||
* @property {string} [Baz] - Definitely not Foo.
|
||||
* @property {OtherAliasStruct} Other - A nested alias struct.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An empty struct alias.
|
||||
* @typedef {$models.EmptyAliasStruct} EmptyAliasStruct
|
||||
* @typedef { {
|
||||
* } } EmptyAliasStruct
|
||||
*/
|
||||
|
||||
/**
|
||||
* Another struct alias.
|
||||
* @typedef {$models.OtherAliasStruct} OtherAliasStruct
|
||||
* An empty struct.
|
||||
*/
|
||||
export class EmptyStruct {
|
||||
/**
|
||||
* Creates a new EmptyStruct instance.
|
||||
* @param {Partial<EmptyStruct>} [$$source = {}] - The source object to create the EmptyStruct.
|
||||
*/
|
||||
constructor($$source = {}) {
|
||||
|
||||
Object.assign(this, $$source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new EmptyStruct instance from a string or object.
|
||||
* @param {any} [$$source = {}]
|
||||
* @returns {EmptyStruct}
|
||||
*/
|
||||
static createFrom($$source = {}) {
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
return new EmptyStruct(/** @type {Partial<EmptyStruct>} */($$parsedSource));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic struct containing an alias.
|
||||
* @template T
|
||||
*/
|
||||
export class GenericPerson {
|
||||
/**
|
||||
* Creates a new GenericPerson instance.
|
||||
* @param {Partial<GenericPerson<T>>} [$$source = {}] - The source object to create the GenericPerson.
|
||||
*/
|
||||
constructor($$source = {}) {
|
||||
if (/** @type {any} */(false)) {
|
||||
/**
|
||||
* @member
|
||||
* @type {T | undefined}
|
||||
*/
|
||||
this["Name"] = undefined;
|
||||
}
|
||||
if (!("AliasedField" in $$source)) {
|
||||
/**
|
||||
* @member
|
||||
* @type {Alias}
|
||||
*/
|
||||
this["AliasedField"] = 0;
|
||||
}
|
||||
|
||||
Object.assign(this, $$source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given creation functions for each type parameter,
|
||||
* returns a creation function for a concrete instance
|
||||
* of the generic class GenericPerson.
|
||||
* @template T
|
||||
* @param {(source: any) => T} $$createParamT
|
||||
* @returns {($$source?: any) => GenericPerson<T>}
|
||||
*/
|
||||
static createFrom($$createParamT) {
|
||||
const $$createField0_0 = $$createParamT;
|
||||
return ($$source = {}) => {
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
if ("Name" in $$parsedSource) {
|
||||
$$parsedSource["Name"] = $$createField0_0($$parsedSource["Name"]);
|
||||
}
|
||||
return new GenericPerson(/** @type {Partial<GenericPerson<T>>} */($$parsedSource));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Another struct alias.
|
||||
* @typedef {Object} OtherAliasStruct
|
||||
* @property {number[]} NoMoreIdeas
|
||||
*/
|
||||
|
||||
/**
|
||||
* A non-generic struct containing an alias.
|
||||
*/
|
||||
export class Person {
|
||||
/**
|
||||
* Creates a new Person instance.
|
||||
* @param {Partial<Person>} [$$source = {}] - The source object to create the Person.
|
||||
*/
|
||||
constructor($$source = {}) {
|
||||
if (!("Name" in $$source)) {
|
||||
/**
|
||||
* The Person's name.
|
||||
* @member
|
||||
* @type {string}
|
||||
*/
|
||||
this["Name"] = "";
|
||||
}
|
||||
if (!("AliasedField" in $$source)) {
|
||||
/**
|
||||
* A random alias field.
|
||||
* @member
|
||||
* @type {Alias}
|
||||
*/
|
||||
this["AliasedField"] = 0;
|
||||
}
|
||||
|
||||
Object.assign(this, $$source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Person instance from a string or object.
|
||||
* @param {any} [$$source = {}]
|
||||
* @returns {Person}
|
||||
*/
|
||||
static createFrom($$source = {}) {
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
return new Person(/** @type {Partial<Person>} */($$parsedSource));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A class alias.
|
||||
*/
|
||||
export const AliasedPerson = Person;
|
||||
|
||||
/**
|
||||
* A class alias.
|
||||
* @typedef {Person} AliasedPerson
|
||||
*/
|
||||
|
||||
/**
|
||||
* Another class alias, but ordered after its aliased class.
|
||||
*/
|
||||
export const StrangelyAliasedPerson = Person;
|
||||
|
||||
/**
|
||||
* Another class alias, but ordered after its aliased class.
|
||||
* @typedef {Person} StrangelyAliasedPerson
|
||||
*/
|
||||
|
@ -13,7 +13,7 @@ import {Call as $Call, Create as $Create} from "/wails/runtime.js";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import * as $models from "./internal.js";
|
||||
import * as $models from "./models.js";
|
||||
|
||||
/**
|
||||
* Greet does XYZ
|
||||
|
@ -7,4 +7,14 @@ export {
|
||||
GreetService
|
||||
};
|
||||
|
||||
export * from "./models.js";
|
||||
export {
|
||||
Embedded1,
|
||||
Person,
|
||||
Title
|
||||
} from "./models.js";
|
||||
|
||||
import * as $models from "./models.js";
|
||||
|
||||
/**
|
||||
* @typedef {$models.Embedded3} Embedded3
|
||||
*/
|
||||
|
@ -1,272 +0,0 @@
|
||||
// @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";
|
||||
|
||||
export class Embedded1 {
|
||||
/**
|
||||
* Creates a new Embedded1 instance.
|
||||
* @param {Partial<Embedded1>} [$$source = {}] - The source object to create the Embedded1.
|
||||
*/
|
||||
constructor($$source = {}) {
|
||||
if (!("Friends" in $$source)) {
|
||||
/**
|
||||
* Friends should be shadowed in Person by a field of lesser depth
|
||||
* @member
|
||||
* @type {number}
|
||||
*/
|
||||
this["Friends"] = 0;
|
||||
}
|
||||
if (!("Vanish" in $$source)) {
|
||||
/**
|
||||
* Vanish should be omitted from Person because there is another field with same depth and no tag
|
||||
* @member
|
||||
* @type {number}
|
||||
*/
|
||||
this["Vanish"] = 0;
|
||||
}
|
||||
if (!("StillThere" in $$source)) {
|
||||
/**
|
||||
* StillThere should be shadowed in Person by other field with same depth and a json tag
|
||||
* @member
|
||||
* @type {string}
|
||||
*/
|
||||
this["StillThere"] = "";
|
||||
}
|
||||
if (!("NamingThingsIsHard" in $$source)) {
|
||||
/**
|
||||
* NamingThingsIsHard is a law of programming
|
||||
* @member
|
||||
* @type {`${boolean}`}
|
||||
*/
|
||||
this["NamingThingsIsHard"] = "false";
|
||||
}
|
||||
|
||||
Object.assign(this, $$source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Embedded1 instance from a string or object.
|
||||
* @param {any} [$$source = {}]
|
||||
* @returns {Embedded1}
|
||||
*/
|
||||
static createFrom($$source = {}) {
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
return new Embedded1(/** @type {Partial<Embedded1>} */($$parsedSource));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {string} Embedded3
|
||||
*/
|
||||
|
||||
/**
|
||||
* Person represents a person
|
||||
*/
|
||||
export class Person {
|
||||
/**
|
||||
* Creates a new Person instance.
|
||||
* @param {Partial<Person>} [$$source = {}] - The source object to create the Person.
|
||||
*/
|
||||
constructor($$source = {}) {
|
||||
if (/** @type {any} */(false)) {
|
||||
/**
|
||||
* Titles is optional in JSON
|
||||
* @member
|
||||
* @type {Title[] | undefined}
|
||||
*/
|
||||
this["Titles"] = [];
|
||||
}
|
||||
if (!("Names" in $$source)) {
|
||||
/**
|
||||
* Names has a
|
||||
* multiline comment
|
||||
* @member
|
||||
* @type {string[]}
|
||||
*/
|
||||
this["Names"] = [];
|
||||
}
|
||||
if (!("Partner" in $$source)) {
|
||||
/**
|
||||
* Partner has a custom and complex JSON key
|
||||
* @member
|
||||
* @type {Person | null}
|
||||
*/
|
||||
this["Partner"] = null;
|
||||
}
|
||||
if (!("Friends" in $$source)) {
|
||||
/**
|
||||
* @member
|
||||
* @type {(Person | null)[]}
|
||||
*/
|
||||
this["Friends"] = [];
|
||||
}
|
||||
if (!("NamingThingsIsHard" in $$source)) {
|
||||
/**
|
||||
* NamingThingsIsHard is a law of programming
|
||||
* @member
|
||||
* @type {`${boolean}`}
|
||||
*/
|
||||
this["NamingThingsIsHard"] = "false";
|
||||
}
|
||||
if (!("StillThere" in $$source)) {
|
||||
/**
|
||||
* StillThereButRenamed should shadow in Person the other field with same depth and no json tag
|
||||
* @member
|
||||
* @type {Embedded3 | null}
|
||||
*/
|
||||
this["StillThere"] = null;
|
||||
}
|
||||
if (!("-" in $$source)) {
|
||||
/**
|
||||
* StrangeNumber maps to "-"
|
||||
* @member
|
||||
* @type {number}
|
||||
*/
|
||||
this["-"] = 0;
|
||||
}
|
||||
if (!("Embedded3" in $$source)) {
|
||||
/**
|
||||
* Embedded3 should appear with key "Embedded3"
|
||||
* @member
|
||||
* @type {Embedded3}
|
||||
*/
|
||||
this["Embedded3"] = (/** @type {Embedded3} */(""));
|
||||
}
|
||||
if (!("StrangerNumber" in $$source)) {
|
||||
/**
|
||||
* StrangerNumber is serialized as a string
|
||||
* @member
|
||||
* @type {`${number}`}
|
||||
*/
|
||||
this["StrangerNumber"] = "0";
|
||||
}
|
||||
if (/** @type {any} */(false)) {
|
||||
/**
|
||||
* StrangestString is optional and serialized as a JSON string
|
||||
* @member
|
||||
* @type {`"${string}"` | undefined}
|
||||
*/
|
||||
this["StrangestString"] = '""';
|
||||
}
|
||||
if (/** @type {any} */(false)) {
|
||||
/**
|
||||
* StringStrangest is serialized as a JSON string and optional
|
||||
* @member
|
||||
* @type {`"${string}"` | undefined}
|
||||
*/
|
||||
this["StringStrangest"] = '""';
|
||||
}
|
||||
if (/** @type {any} */(false)) {
|
||||
/**
|
||||
* embedded4 should be optional and appear with key "emb4"
|
||||
* @member
|
||||
* @type {embedded4 | undefined}
|
||||
*/
|
||||
this["emb4"] = (new embedded4());
|
||||
}
|
||||
|
||||
Object.assign(this, $$source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Person instance from a string or object.
|
||||
* @param {any} [$$source = {}]
|
||||
* @returns {Person}
|
||||
*/
|
||||
static createFrom($$source = {}) {
|
||||
const $$createField0_0 = $$createType0;
|
||||
const $$createField1_0 = $$createType1;
|
||||
const $$createField2_0 = $$createType3;
|
||||
const $$createField3_0 = $$createType4;
|
||||
const $$createField11_0 = $$createType5;
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
if ("Titles" in $$parsedSource) {
|
||||
$$parsedSource["Titles"] = $$createField0_0($$parsedSource["Titles"]);
|
||||
}
|
||||
if ("Names" in $$parsedSource) {
|
||||
$$parsedSource["Names"] = $$createField1_0($$parsedSource["Names"]);
|
||||
}
|
||||
if ("Partner" in $$parsedSource) {
|
||||
$$parsedSource["Partner"] = $$createField2_0($$parsedSource["Partner"]);
|
||||
}
|
||||
if ("Friends" in $$parsedSource) {
|
||||
$$parsedSource["Friends"] = $$createField3_0($$parsedSource["Friends"]);
|
||||
}
|
||||
if ("emb4" in $$parsedSource) {
|
||||
$$parsedSource["emb4"] = $$createField11_0($$parsedSource["emb4"]);
|
||||
}
|
||||
return new Person(/** @type {Partial<Person>} */($$parsedSource));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Title is a title
|
||||
* @readonly
|
||||
* @enum {string}
|
||||
*/
|
||||
export const Title = {
|
||||
/**
|
||||
* The Go zero value for the underlying type of the enum.
|
||||
*/
|
||||
$zero: "",
|
||||
|
||||
/**
|
||||
* Mister is a title
|
||||
*/
|
||||
Mister: "Mr",
|
||||
Miss: "Miss",
|
||||
Ms: "Ms",
|
||||
Mrs: "Mrs",
|
||||
Dr: "Dr",
|
||||
};
|
||||
|
||||
export class embedded4 {
|
||||
/**
|
||||
* Creates a new embedded4 instance.
|
||||
* @param {Partial<embedded4>} [$$source = {}] - The source object to create the embedded4.
|
||||
*/
|
||||
constructor($$source = {}) {
|
||||
if (!("NamingThingsIsHard" in $$source)) {
|
||||
/**
|
||||
* NamingThingsIsHard is a law of programming
|
||||
* @member
|
||||
* @type {`${boolean}`}
|
||||
*/
|
||||
this["NamingThingsIsHard"] = "false";
|
||||
}
|
||||
if (!("Friends" in $$source)) {
|
||||
/**
|
||||
* Friends should not be shadowed in Person as embedded4 is not embedded
|
||||
* from encoding/json's point of view;
|
||||
* however, it should be shadowed in Embedded1
|
||||
* @member
|
||||
* @type {boolean}
|
||||
*/
|
||||
this["Friends"] = false;
|
||||
}
|
||||
|
||||
Object.assign(this, $$source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new embedded4 instance from a string or object.
|
||||
* @param {any} [$$source = {}]
|
||||
* @returns {embedded4}
|
||||
*/
|
||||
static createFrom($$source = {}) {
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
return new embedded4(/** @type {Partial<embedded4>} */($$parsedSource));
|
||||
}
|
||||
}
|
||||
|
||||
// Private type creation functions
|
||||
const $$createType0 = $Create.Array($Create.Any);
|
||||
const $$createType1 = $Create.Array($Create.Any);
|
||||
const $$createType2 = Person.createFrom;
|
||||
const $$createType3 = $Create.Nullable($$createType2);
|
||||
const $$createType4 = $Create.Array($$createType3);
|
||||
const $$createType5 = embedded4.createFrom;
|
@ -2,14 +2,271 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
export {
|
||||
Embedded1,
|
||||
Person,
|
||||
Title
|
||||
} from "./internal.js";
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import {Create as $Create} from "/wails/runtime.js";
|
||||
|
||||
import * as $models from "./internal.js";
|
||||
export class Embedded1 {
|
||||
/**
|
||||
* Creates a new Embedded1 instance.
|
||||
* @param {Partial<Embedded1>} [$$source = {}] - The source object to create the Embedded1.
|
||||
*/
|
||||
constructor($$source = {}) {
|
||||
if (!("Friends" in $$source)) {
|
||||
/**
|
||||
* Friends should be shadowed in Person by a field of lesser depth
|
||||
* @member
|
||||
* @type {number}
|
||||
*/
|
||||
this["Friends"] = 0;
|
||||
}
|
||||
if (!("Vanish" in $$source)) {
|
||||
/**
|
||||
* Vanish should be omitted from Person because there is another field with same depth and no tag
|
||||
* @member
|
||||
* @type {number}
|
||||
*/
|
||||
this["Vanish"] = 0;
|
||||
}
|
||||
if (!("StillThere" in $$source)) {
|
||||
/**
|
||||
* StillThere should be shadowed in Person by other field with same depth and a json tag
|
||||
* @member
|
||||
* @type {string}
|
||||
*/
|
||||
this["StillThere"] = "";
|
||||
}
|
||||
if (!("NamingThingsIsHard" in $$source)) {
|
||||
/**
|
||||
* NamingThingsIsHard is a law of programming
|
||||
* @member
|
||||
* @type {`${boolean}`}
|
||||
*/
|
||||
this["NamingThingsIsHard"] = "false";
|
||||
}
|
||||
|
||||
Object.assign(this, $$source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Embedded1 instance from a string or object.
|
||||
* @param {any} [$$source = {}]
|
||||
* @returns {Embedded1}
|
||||
*/
|
||||
static createFrom($$source = {}) {
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
return new Embedded1(/** @type {Partial<Embedded1>} */($$parsedSource));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {$models.Embedded3} Embedded3
|
||||
* @typedef {string} Embedded3
|
||||
*/
|
||||
|
||||
/**
|
||||
* Person represents a person
|
||||
*/
|
||||
export class Person {
|
||||
/**
|
||||
* Creates a new Person instance.
|
||||
* @param {Partial<Person>} [$$source = {}] - The source object to create the Person.
|
||||
*/
|
||||
constructor($$source = {}) {
|
||||
if (/** @type {any} */(false)) {
|
||||
/**
|
||||
* Titles is optional in JSON
|
||||
* @member
|
||||
* @type {Title[] | undefined}
|
||||
*/
|
||||
this["Titles"] = undefined;
|
||||
}
|
||||
if (!("Names" in $$source)) {
|
||||
/**
|
||||
* Names has a
|
||||
* multiline comment
|
||||
* @member
|
||||
* @type {string[]}
|
||||
*/
|
||||
this["Names"] = [];
|
||||
}
|
||||
if (!("Partner" in $$source)) {
|
||||
/**
|
||||
* Partner has a custom and complex JSON key
|
||||
* @member
|
||||
* @type {Person | null}
|
||||
*/
|
||||
this["Partner"] = null;
|
||||
}
|
||||
if (!("Friends" in $$source)) {
|
||||
/**
|
||||
* @member
|
||||
* @type {(Person | null)[]}
|
||||
*/
|
||||
this["Friends"] = [];
|
||||
}
|
||||
if (!("NamingThingsIsHard" in $$source)) {
|
||||
/**
|
||||
* NamingThingsIsHard is a law of programming
|
||||
* @member
|
||||
* @type {`${boolean}`}
|
||||
*/
|
||||
this["NamingThingsIsHard"] = "false";
|
||||
}
|
||||
if (!("StillThere" in $$source)) {
|
||||
/**
|
||||
* StillThereButRenamed should shadow in Person the other field with same depth and no json tag
|
||||
* @member
|
||||
* @type {Embedded3 | null}
|
||||
*/
|
||||
this["StillThere"] = null;
|
||||
}
|
||||
if (!("-" in $$source)) {
|
||||
/**
|
||||
* StrangeNumber maps to "-"
|
||||
* @member
|
||||
* @type {number}
|
||||
*/
|
||||
this["-"] = 0;
|
||||
}
|
||||
if (!("Embedded3" in $$source)) {
|
||||
/**
|
||||
* Embedded3 should appear with key "Embedded3"
|
||||
* @member
|
||||
* @type {Embedded3}
|
||||
*/
|
||||
this["Embedded3"] = "";
|
||||
}
|
||||
if (!("StrangerNumber" in $$source)) {
|
||||
/**
|
||||
* StrangerNumber is serialized as a string
|
||||
* @member
|
||||
* @type {`${number}`}
|
||||
*/
|
||||
this["StrangerNumber"] = "0";
|
||||
}
|
||||
if (/** @type {any} */(false)) {
|
||||
/**
|
||||
* StrangestString is optional and serialized as a JSON string
|
||||
* @member
|
||||
* @type {`"${string}"` | undefined}
|
||||
*/
|
||||
this["StrangestString"] = undefined;
|
||||
}
|
||||
if (/** @type {any} */(false)) {
|
||||
/**
|
||||
* StringStrangest is serialized as a JSON string and optional
|
||||
* @member
|
||||
* @type {`"${string}"` | undefined}
|
||||
*/
|
||||
this["StringStrangest"] = undefined;
|
||||
}
|
||||
if (/** @type {any} */(false)) {
|
||||
/**
|
||||
* embedded4 should be optional and appear with key "emb4"
|
||||
* @member
|
||||
* @type {embedded4 | undefined}
|
||||
*/
|
||||
this["emb4"] = undefined;
|
||||
}
|
||||
|
||||
Object.assign(this, $$source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Person instance from a string or object.
|
||||
* @param {any} [$$source = {}]
|
||||
* @returns {Person}
|
||||
*/
|
||||
static createFrom($$source = {}) {
|
||||
const $$createField0_0 = $$createType0;
|
||||
const $$createField1_0 = $$createType1;
|
||||
const $$createField2_0 = $$createType3;
|
||||
const $$createField3_0 = $$createType4;
|
||||
const $$createField11_0 = $$createType5;
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
if ("Titles" in $$parsedSource) {
|
||||
$$parsedSource["Titles"] = $$createField0_0($$parsedSource["Titles"]);
|
||||
}
|
||||
if ("Names" in $$parsedSource) {
|
||||
$$parsedSource["Names"] = $$createField1_0($$parsedSource["Names"]);
|
||||
}
|
||||
if ("Partner" in $$parsedSource) {
|
||||
$$parsedSource["Partner"] = $$createField2_0($$parsedSource["Partner"]);
|
||||
}
|
||||
if ("Friends" in $$parsedSource) {
|
||||
$$parsedSource["Friends"] = $$createField3_0($$parsedSource["Friends"]);
|
||||
}
|
||||
if ("emb4" in $$parsedSource) {
|
||||
$$parsedSource["emb4"] = $$createField11_0($$parsedSource["emb4"]);
|
||||
}
|
||||
return new Person(/** @type {Partial<Person>} */($$parsedSource));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Title is a title
|
||||
* @readonly
|
||||
* @enum {string}
|
||||
*/
|
||||
export const Title = {
|
||||
/**
|
||||
* The Go zero value for the underlying type of the enum.
|
||||
*/
|
||||
$zero: "",
|
||||
|
||||
/**
|
||||
* Mister is a title
|
||||
*/
|
||||
Mister: "Mr",
|
||||
Miss: "Miss",
|
||||
Ms: "Ms",
|
||||
Mrs: "Mrs",
|
||||
Dr: "Dr",
|
||||
};
|
||||
|
||||
export class embedded4 {
|
||||
/**
|
||||
* Creates a new embedded4 instance.
|
||||
* @param {Partial<embedded4>} [$$source = {}] - The source object to create the embedded4.
|
||||
*/
|
||||
constructor($$source = {}) {
|
||||
if (!("NamingThingsIsHard" in $$source)) {
|
||||
/**
|
||||
* NamingThingsIsHard is a law of programming
|
||||
* @member
|
||||
* @type {`${boolean}`}
|
||||
*/
|
||||
this["NamingThingsIsHard"] = "false";
|
||||
}
|
||||
if (!("Friends" in $$source)) {
|
||||
/**
|
||||
* Friends should not be shadowed in Person as embedded4 is not embedded
|
||||
* from encoding/json's point of view;
|
||||
* however, it should be shadowed in Embedded1
|
||||
* @member
|
||||
* @type {boolean}
|
||||
*/
|
||||
this["Friends"] = false;
|
||||
}
|
||||
|
||||
Object.assign(this, $$source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new embedded4 instance from a string or object.
|
||||
* @param {any} [$$source = {}]
|
||||
* @returns {embedded4}
|
||||
*/
|
||||
static createFrom($$source = {}) {
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
return new embedded4(/** @type {Partial<embedded4>} */($$parsedSource));
|
||||
}
|
||||
}
|
||||
|
||||
// Private type creation functions
|
||||
const $$createType0 = $Create.Array($Create.Any);
|
||||
const $$createType1 = $Create.Array($Create.Any);
|
||||
const $$createType2 = Person.createFrom;
|
||||
const $$createType3 = $Create.Nullable($$createType2);
|
||||
const $$createType4 = $Create.Array($$createType3);
|
||||
const $$createType5 = embedded4.createFrom;
|
||||
|
@ -13,7 +13,7 @@ import {Call as $Call, Create as $Create} from "/wails/runtime.js";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import * as $models from "./internal.js";
|
||||
import * as $models from "./models.js";
|
||||
|
||||
/**
|
||||
* Greet does XYZ
|
||||
|
@ -7,4 +7,6 @@ export {
|
||||
GreetService
|
||||
};
|
||||
|
||||
export * from "./models.js";
|
||||
export {
|
||||
Person
|
||||
} from "./models.js";
|
||||
|
@ -2,6 +2,37 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
export {
|
||||
Person
|
||||
} from "./internal.js";
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import {Create as $Create} from "/wails/runtime.js";
|
||||
|
||||
/**
|
||||
* Person represents a person
|
||||
*/
|
||||
export class Person {
|
||||
/**
|
||||
* Creates a new Person instance.
|
||||
* @param {Partial<Person>} [$$source = {}] - The source object to create the Person.
|
||||
*/
|
||||
constructor($$source = {}) {
|
||||
if (!("Name" in $$source)) {
|
||||
/**
|
||||
* @member
|
||||
* @type {string}
|
||||
*/
|
||||
this["Name"] = "";
|
||||
}
|
||||
|
||||
Object.assign(this, $$source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Person instance from a string or object.
|
||||
* @param {any} [$$source = {}]
|
||||
* @returns {Person}
|
||||
*/
|
||||
static createFrom($$source = {}) {
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
return new Person(/** @type {Partial<Person>} */($$parsedSource));
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user