├── .github
└── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── .gitignore
├── .npmignore
├── ARCHITECTURE.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── banner.png
├── example
├── basic-noapi
│ ├── .gitignore
│ ├── dist
│ │ └── index.html
│ ├── go.mod
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── api
│ │ │ ├── bridge.go
│ │ │ └── main.go
│ │ └── index.js
│ └── webpack.config.js
└── basic
│ ├── .gitignore
│ ├── dist
│ └── index.html
│ ├── go.mod
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ ├── api
│ │ └── main.go
│ └── index.js
│ └── webpack.config.js
├── package-lock.json
├── package.json
├── src
├── bridge.js
└── index.js
└── wasm
├── error.go
├── function.go
├── go.mod
├── object.go
├── promise.go
├── reflect_from.go
├── reflect_to.go
└── wasm.go
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug:**
11 | A clear and concise description of what the bug is.
12 |
13 | **To reproduce:**
14 | Steps to reproduce the behavior. We encourage sending code snippets and screenshots.
15 | Make sure the steps are easy to follow and reproducible!
16 |
17 | **Expected behavior:**
18 | A clear and concise description of what you expected to happen.
19 |
20 | **Screenshots:**
21 | If applicable, add screenshots to help explain your problem.
22 |
23 | **Browser, OS, Go version and Golang-WASM version:**
24 | - Browser: [e.g. Firefox]
25 | - OS: [e.g. Mint Linux]
26 | - Go: [e.g. v1.16.1]
27 | - Golang-WASM: [e.g. v1.2.3]
28 |
29 | **Additional context:**
30 | Add any other context about the problem here.
31 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...].
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .gocache
3 | wasm_exec.js
4 | *.wasm
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | example
2 | wasm
3 | .gocache
--------------------------------------------------------------------------------
/ARCHITECTURE.md:
--------------------------------------------------------------------------------
1 | # Golang-WASM Architecture
2 |
3 | > Please note that Golang-WASM is still in its initial stages of development and is not at a stable version yet. SemVer will be used when v1.0.0 is released and changes are expected to be potentially breaking and unstable.
4 |
5 | This file gives a mile-high view of the Golang-WASM project and how the different parts interact with each other. We strongly recommend all contributors to read this, as well as [CONTRIBUTING.md](./CONTRIBUTING.md) before getting started with development.
6 |
7 | Go-WASM has 2 primary parts to the project.
8 |
9 | * The Go WASM [bindings](./wasm) and `syscall/js` superset to improve type safety when working in Go.
10 | * The JavaScript caller and wrappers, and the Webpack loader a which can be found in the [src](./src) folder.
11 |
12 | ## Go WASM Bindings
13 |
14 | The Go WASM bindings has three main goals,
15 | 1. Make type checking a non-issue for development.
16 | 2. Seamlessly convert the programming style from Go to JS.
17 | 3. (WIP) Implement a type safe version of the entire DOM API.
18 |
19 | Solving the first two require a healthy usage of reflection and their implementation can be found mostly in [reflect_to.go](./wasm/reflect_to.go) and [reflect_from.go](./wasm/reflect_from.go).
20 |
21 | Interfacing from functions that return errors to Promise resolves and rejections is mostly handled within [function.go](./wasm/function.go). It is worth noting how error handling works when working with calling functions from Go in a type safe manner in [reflect_from](./wasm/reflect_from.go) within `decodeFunc`.
22 |
23 | ### DOM API
24 |
25 | This is still a work in progress. However, basic parts of it have already been implemented. The implementation for the [Promise API](./wasm/promise.go) demonstrates what we have in mind for the rest of the API. The goal of this project is not to dump everything 1:1. If you want to use something like that, you can use a computer generated version [here](https://github.com/brettlangdon/go-dom).
26 |
27 |
28 |
29 | ## JavaScript + Webpack
30 |
31 | The main goal of the JavaScript hook for the project is to seamlessly link Go and JavaScript together and overcome some of the limitations of native Go WASM through wrappers. Read the implementation [here](./src/bridge.js)
32 |
33 | The main difference between writing JavaScript code and Go code is the interactivity with asynchronous code, and error handling. To solve this issue, calling all Go code from JS goes through a [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy). Furthermore, all Go functions that are called from JavaScript are returned via a wrapper functions. Read more about this in the documentation.
34 |
35 | ### Webpack Loader
36 |
37 | The Webpack loader is relatively simple to use. To use it, it is only important for developers to add `GOROOT` to their environment variables when running the command.
38 |
39 | The Webpack loader searches and finds a `go.mod` file in any of the parent directories of an imported Go file. The loader requires the presence of such a file. Webpack then watches for all file changes inside the go.mod directory and **compiles your entire project**, as long as one of the files are imported in the Go project. Read the implementation [here](./src/index.js)
40 |
41 | The Webpack Loader for Golang-Wasm is not in its ideal state. Currently, It does not seamlessly work with Webpack supersets, such as [Craco](https://github.com/gsoft-inc/craco/issues/268).
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Golang-WASM
2 | If you're reading this, thanks for taking a look! We have a couple of guidelines that we encourage you to follow when working on Golang-WASM.
3 |
4 | ## Code of Conduct
5 | If you find any bugs or would like to request any features, please open an issue. Once the issue is open, feel free to put in a pull request to fix the issue. Small corrections, like fixing spelling errors, or updating broken urls are appreciated.
6 |
7 | We encourage an open, friendly, and supportive environment around the development of Golang-WASM. If you disagree with someone for any reason, discuss the issue and express you opinions, don't attack the person. Discrimination of any kind against any person is not permitted. If you detract from this project's collaborative environment, you'll be prevented from participating in the future development of this project until you prove you can behave yourself adequately.
8 |
9 | > Please use sound reasoning to support your suggestions - don't rely on arguments based on 'years of experience,' supposed skill, job title, etc. to get your points across.
10 |
11 | # General Guidelines
12 | All exported functions, variables, and constants must contain documentation. Readable code with clear behavior works better than illegible optimized code. Use comments for unexported functions when their purpose is non-trivial.
13 |
14 | Each commit should denote exactly one thing, whether it be a bug fix, or a feature addition. Try not to do both at the same time - it makes code harder to review. Once the codebase is stable, the contributing flow should be:
15 |
16 | 1. Check for issues and discussion on a bug/feature.
17 | 2. If none found, open an issue about.
18 | 3. Fork and develop the feature.
19 | 4. Open a pull request. If an issue is related, tag the issue number in the commit message
20 | 5. Merge the code into the project.
21 |
22 | Once the API for Golang-WASM reaches a stable level, SemVer will be used for tagging new bug fixes, features, and breaking changes.
23 |
24 | > Our project uses the Conventional Commits standard for writing commit messages. Commits that do not follow this will not be merged into the code base. Read more about Conventional Commits [here](https://conventionalcommits.org)
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Hamza Ali and Chan Wen Xu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | A bridge and bindings for JS DOM API with Go WebAssembly.
7 | Written by Team Ortix - Hamza Ali and Chan Wen Xu .
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | ```
20 | GOOS=js GOARCH=wasm go get -u github.com/teamortix/golang-wasm/wasm
21 | ```
22 | ```bash
23 | npm install golang-wasm
24 | ```
25 |
26 | # ⚠️ The documentation is still work in progress.
27 |
28 | ## Why Golang-WASM?
29 |
30 | Golang-WASM provides a simple idiomatic, and comprehensive (soon™️) API and bindings for working with WebAssembly.
31 |
32 | Golang-WASM also comes with a [webpack](https://npmjs.com/golang-wasm) loader that wraps the entire API so that it is idiomatic for JavaScript developers as well as Go developers.
33 |
34 | Here is a small snippet:
35 | ```go
36 | // main.go
37 | // Automatically handled with Promise rejects when returning an error!
38 | func divide(x int, y int) (int, error) {
39 | if y == 0 {
40 | return 0, errors.New("cannot divide by zero")
41 | }
42 | return x / y, nil
43 | }
44 |
45 | func main() {
46 | wasm.Expose("divide", divide)
47 | wasm.Ready()
48 | }
49 | ```
50 | ```js
51 | // index.js
52 | import { divide } from "main.go";
53 |
54 | const result = await divide(6, 2);
55 | console.log(result); // 3
56 |
57 | // Exception thrown: Unhandled rejection in promise: cannot divide by zero.
58 | const error = await divide(6, 0);
59 | ```
60 |
61 | When using the webpack loader, everything is bundled for you, and you can directly import the Go file.
62 |
63 | > Note: the webpack loader expects you to have a valid Go installation on your system, and a valid GOROOT passed.
64 |
65 | ## JS Interop
66 |
67 | ### Examples
68 |
69 | You can find our examples in the [examples](./example) directory.
70 | Currently, we have two examples available.
71 |
72 | * [basic](./example/basic): Simple usage of the API with the WASM library. This example shows automatically casting types from JS to Go, and how returning errors works.
73 |
74 | * [basic (no api)](./example/basic-noapi): A standalone example of using the JS bridge without any third party libraries in Go. Forces developers to manually type check all parameters and use the unsafe `syscall/js` directly.
75 |
76 | * (WIP) [promises](./example/promises): An example showing how Go can work with functions that call promises, and return its own promises. This example puts an emphasis on the importance of idiomatic code in both languages.
77 |
78 | * (WIP) [craco + ReactJS](./example/craco): A simple example demonstrating how Golang-WASM and React can work together, using [craco]https://github.com/gsoft-inc/craco).
79 |
80 | ### Retrieving constants and values from JavaScript
81 |
82 | For more information about how Golang-WASM converts Go data to JS, read [Auto type casting](#auto-type-casting).
83 |
84 | ```go
85 | type User struct {
86 | Name string `wasm:"name"`
87 | Email string `wasm:"emailAddr"`
88 | Age int `wasm:"age"`
89 | password string // ignored (unexported)
90 | }
91 |
92 | const Nothing = nil // Exposed as 'nothing'.
93 | const Username = "TeamOrtix" // exposed as username.
94 | const Age = 3
95 |
96 | var hhhapz = User { // exposed as hhhapz.
97 | Name: "Hamza Ali",
98 | Email: "me (at) hamzantal dot pw",
99 | Age: 17,
100 | password: "wouldn't_you_like_to_know"
101 | }
102 | var goodPromise = wasm.NewPromise(func() (interface{}, error) {
103 | return "success", nil
104 | })
105 | var badPromise = wasm.NewPromise(func() (interface{}, error) {
106 | return nil, errors.New("failure")
107 | })
108 | ```
109 |
110 | ```js
111 | import wasm from ...;
112 |
113 | await wasm.nothing(); // null
114 | await wasm.username(); // "TeamOrtix"
115 | await wasm.age(); // 3
116 | await wasm.hhhapz(); /* {
117 | name: "Hamza Ali",
118 | emailAddr: "me (at) hamzantal dot pw",
119 | age: 17
120 | } */
121 | await wasm.goodPromise(); // Promise(fulfilled: "success")
122 | await wasm.badPromise(); // Promise(rejected: Error("failure"))
123 | ```
124 |
125 | > Note: For the last two, The resulting value of calling `goodPromise` or `badPromise` will be a Promise wrapped inside a Promise.
126 |
127 | > If Go returns multiple promises embedded within each other, the stack will automatically flatten like it does in JS.
128 |
129 | ---
130 |
131 | ### Working with functions
132 |
133 | When a Go function returns a value, they are handled identically to constants and variables.
134 |
135 | **⚠️ For functions that can also fail/return errors, please do not use panics!**
136 |
137 | The [working with errors](#working-with-errors) section covers how errors can be sent to JavaScript.
138 |
139 | **Brief Overview**:
140 |
141 | ```go
142 | func ZeroParamFunc() {
143 | } // await call() => undefined
144 |
145 |
146 | func StringReturnFunc() string {
147 | return "Team Ortix"
148 | } // await call() => "Team Ortix"
149 |
150 |
151 | func StringOrErrorReturnFunc() (string, error) {
152 | return "Team Ortix", nil
153 | } // await call() => "Team Ortix"
154 |
155 |
156 | func FailOrNil() (error) {
157 | return nil
158 | } // await call() => undefined
159 |
160 |
161 | func FailingFunc() error {
162 | return errors.New("fail")
163 | } // await call() => Error("fail")
164 |
165 |
166 | func FailingFunc() (string, error) {
167 | return "", errors.New("fail")
168 | } // await call() => fail
169 |
170 |
171 | func SingleParam(str string) string {
172 | return str
173 | }
174 | // await call() => Rejected Promise: Error("invalid argument passed into Go function")
175 | // await call("Team Ortix", "fail") => Rejected Promise: Error("invalid argument passed into Go function")
176 | // await call("Team Ortix") => "Team Ortix"
177 |
178 |
179 | func TakeAnything(v interface{}) interface{} {
180 | return v
181 | }
182 | // call(3) => 3
183 | // call(() => {}) => (() => {})
184 | // call({}) => {}
185 |
186 |
187 | func HigherOrderFunction(f func() string) string {
188 | return f()
189 | }
190 | // await call(() => {}) // Go will panic and shut down. Higher order functions like this MUST return the same type.
191 | // await call("invalid") => Rejected Promise: Error("invalid argument passed into Go function")
192 | // await call(() => "test") => "test"
193 |
194 |
195 | func HigherOrderFunctionSafe(f func() (string, error)) string {
196 | str, err := f()
197 | if err != nil {
198 | return "invalid return value!"
199 | }
200 | return str
201 | }
202 | // call(() => {}) => "invalid return value!"
203 | // call(() => "Team Ortix") => "Team Ortix"
204 |
205 |
206 | func FunctionThatThrows(f func()) {
207 | f()
208 | }
209 | // call(() => { throw new Error("fail")}) // Go will panic in this situation.
210 |
211 |
212 | // Not implemented yet.
213 | func DidFunctionSucceed(f func() error) bool {
214 | res := f()
215 | return res == nil
216 | }
217 | // call(() => {}) => true
218 | // call(() => { throw new Error("fail") }) => false
219 | ```
220 |
221 | ### Auto type casting
222 |
223 | * If a `nil` value is found, it is converted to JavaScript's `null`.
224 |
225 | * For Go primitives, marshalling to JS works as one would expect.
226 |
227 | | Go Type | JS Type |
228 | |:-------------------------:|:----------------------------:|
229 | | string | String |
230 | | uint | Number |
231 | | int | Number |
232 | | float | Number |
233 | | complex | {real: Number, imag: Number} |
234 | | Symbol | unimplemented |
235 | | map[string]T | Object |
236 | | [size]T (array) | Array |
237 | | []T (slice) | Array |
238 |
239 | * For Go structs, unexported values inside structs will NOT be marshalled.
240 |
241 | * If a struct has a tag (with the wasm namespace), that will be used as the key.
242 |
243 | * If two properties have the identical key, the value that is declared second in the struct deceleration will overwrite the former value.
244 |
245 | * When converting a Go Map (`map[K]V`), all keys must be a `uint`, `int` or a `string`.
246 |
247 | * **⚠️ If a different kind of key is found, WASM will panic.**
248 |
249 | * If a pointer is found, the pointer is unwrapped till the raw value is found.
250 |
251 | * Slices and arrays are automatically converted to the JavaScript Array object.
252 |
253 | * Marshalling function parameters to Go values has slightly different functionality.
254 |
255 | * If a function parameter is not a concrete type (`interface{}`), Go returns types in the following fashion:
256 | | JS Type | Go Type |
257 | |:---------:|:-----------------------------------------:|
258 | | undefined | nil |
259 | | null | nil |
260 | | Boolean | bool |
261 | | Number | float64 |
262 | | String | string |
263 | | Symbol | unimplemented |
264 | | Array | [size]interface{} (Go array) |
265 | | Object | map[string]interface{} |
266 | | Function | func(...interface{}) (interface{}, error) |
267 |
268 |
269 | * Go pointers will result in the basic value.
270 |
271 | * Structs will be filled.
272 |
273 | * All of the keys in the struct must be keys in the object.
274 |
275 | * If there are keys in the object but not in the struct, they will be skipped.
276 |
277 | * Currently, even if a struct value is a pointer to a type, the value will be nil.
278 |
279 | * You can use this functionality for optional values in structs.
280 |
281 | * Providing a `map[string]interface{}` will directly fill the map as expected with the keys of the object and the respective values.
282 |
283 | * If a function parameter is a concrete type, Golang-WASM will try to convert the JS Value to the Go type using the table above.
284 |
285 | * If the types do not match, The caller will receive a rejection promise and the function will never be called.
286 |
287 | * Apart from `float64`, `Number` will be safely casted to all `uint` types, `int` types, and `float32`.
288 |
289 | * Decoding into `complex64` and `complex128` is similar to when they are encoded. A JS Object with a `real` and `imag` property (type Number) are expected.
290 |
291 |
292 | ### Working with errors
293 |
294 | * Functions can only return 0, 1, or 2 values.
295 |
296 | * If the function's last return value is of type error, and the error is non-nil, it will reject with the provided error message.
297 |
298 | * Functions that only return `error` will return `undefined` when `nil` as well.
299 |
300 | * If the second return value is not `error`, Go will not call the function and instead return an error with the following message:
301 |
302 | > a JS function can only return one value
303 |
304 |
305 | ### DOM API
306 |
307 | Currently, little to none of the DOM-API has been implemented in Go.
308 |
309 | The goal for Golang-WASM is to eventually implement a comprehensive section of the DOM-API that will be able to be used in a type safe manner from Go.
310 |
311 | When converting the API over, Golang-WASM will make slight modifications to attempt to maintain idiomatic code when writing Go.
312 |
313 | ### Promise API
314 |
315 | Here is how Go implements the Promise API:
316 |
317 | ```go
318 | // Create a new promise and resolve or reject it, based on what the function returns.
319 | func ExpensiveOperation() wasm.Promise {
320 | // Code is automatically called in a goroutine, similar to how JS does it.
321 | return wasm.NewPromise(func() (interface{}, error) {
322 | result, err := // Expensive operation.
323 | if err != nil {
324 | return nil, err // Reject the Promise.
325 | }
326 | return result, nil // Resolve the Promise.
327 | })
328 | }
329 |
330 | // Wait for a promise to be fulfilled or rejected.
331 | // Note: this must be called inside a goroutine.
332 | // If called within the main thread, Go will deadlock and shut down.
333 | // out: the value that will be set when the promise is fulfilled.
334 | // rej: the value that will be set when the promise is rejected.
335 | // success: whether the promise was fulfilled (true) or rejected (false).
336 | promise := AnotherOperation()
337 | var out int
338 | var rej error
339 | success, err := promise.Await(&out, &rej)
340 | if err != nil {
341 | // Something went wrong with converting types or interacting with JS.
342 | }
343 |
344 |
345 | // Run multiple asynchronous operations at once and wait for them to all end.
346 | promise = wasm.PromiseAllSettled(ExpensiveOperation(), AnotherOperation())
347 |
348 | // If you want to make sure all are fulfilled and not rejected, you can use.
349 | promise = wasm.PromiseAll(ExpensiveOperation(), AnotherOperation())
350 |
351 | // Wait for any of the promises to fulfill. If none of them fulfill and all reject, this promise will also reject.
352 | promise = wasm.PromiseAny(ExpensiveOperation(), AnotherOperation())
353 |
354 | // Run all operations in asynchronous and return the first one to either fulfill or reject.
355 | promise = wasm.PromiseRace(ExpensiveOperation(), AnotherOperation())
356 | ```
357 |
358 | ### How it works
359 |
360 | Golang-WASM uses reflection to marshal to and from JS.
361 | To understand the different modules of the project, we suggest reading [ARCHITECTURE.md](./ARCHITECTURE.md).
362 |
363 | The implementation of things such as throwing errors from Go and catching thrown errors in JS from Go happen through the usage of wrapper functions.
364 | Here is one of such functions that is wrapped when calling a JS function from Go:
365 | ```js
366 | const callSafe = (f) => ((...args) => {
367 | try {
368 | return {result: f(...args)};
369 | } catch (e) {
370 | return {error: e};
371 | }
372 | })
373 | ```
374 |
375 | Go is able to marshal this into a struct:
376 | ```go
377 | type SafeCallResult struct {
378 | Result js.Value `wasm:"result"`
379 | Error js.Value `wasm:"error"`
380 | }
381 | ```
382 |
383 | ---
384 |
385 | ## Webpack Configuration
386 |
387 | See the example [basic](./example/basic/webpack.config.js) project for a full configuration.
388 |
389 | ```js
390 | // webpack.config.js:
391 | module.exports = {
392 | module: {
393 | rules: [
394 | {
395 | test: /\.go$/,
396 | use: [ 'golang-wasm' ]
397 | }
398 | ]
399 | },
400 | ignoreWarnings: [
401 | {
402 | module: /wasm_exec.js$/
403 | }
404 | ]
405 | };
406 | ```
407 |
408 | ### Hotcode Reload
409 |
410 | To ensure that hotcode reloading works, the Webpack loader expects a `go.mod` to be in the directory of the imported file, or a parent directory.
411 |
412 | Go will call `go build [directory]` where the file is imported.
413 |
414 | Given the following directory structure from this project's basic example:
415 |
416 | ```ls
417 | basic
418 | ├── dist
419 | │ └── index.html
420 | ├── go.mod
421 | ├── go.sum
422 | ├── package.json
423 | ├── package-lock.json
424 | ├── src
425 | │ ├── api
426 | │ │ └── main.go
427 | │ └── index.js
428 | └── webpack.config.js
429 | ```
430 |
431 | * Golang-WASM webpack will look for a `go.mod` file in `api/`, then `src/`, and then `basic`, till the root directory.
432 |
433 | * When it finds a `go.mod`, the loader will start looking in the directory for changes to any file for hotcode reload.
434 |
435 | * If no `go.mod` is found, the loader will fail.
436 |
437 | * The loader runs build in the `api` directory:
438 |
439 | > ```
440 | > go build .../basic/src/api
441 | > ```
442 |
443 |
444 | ## FAQ
445 |
446 | ### Is it possible to use multiple instances of Web Assembly in the same project
447 |
448 | At the moment, this is not supported.
449 |
450 | ### When will the DOM API be implemented?
451 |
452 | The DOM API is expanse and large. We can't give a particular date or time. You are free to monitor our progress in this repository.
453 |
454 |
455 | ### When will the API be stable?
456 |
457 | Once we have comprehensive tests and the confidence that the project can be used in production with reasonable stability, we will push v1.0.0 for the project.
458 |
459 | We encourage everyone to submit any errors they may come across and help us with the development process :).
460 |
461 | ## License
462 |
463 | **MIT**.
464 |
465 | ---
466 | Created by [hhhapz](https://github.com/hhhapz) and [chanbakjsd](https://github.com/chanbakjsd).
467 |
--------------------------------------------------------------------------------
/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/teamortix/golang-wasm/5d000994c833b0a2b066d997eadd40cc90341b02/banner.png
--------------------------------------------------------------------------------
/example/basic-noapi/.gitignore:
--------------------------------------------------------------------------------
1 | dist/main.js
2 |
--------------------------------------------------------------------------------
/example/basic-noapi/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Golang-WASM Example
7 |
8 |
9 |
10 | This is an example Golang-WASM Project.
11 |
16 |
17 | Value from Go:
18 |
19 |
20 | Call function from Go:
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/basic-noapi/go.mod:
--------------------------------------------------------------------------------
1 | module example
2 |
3 | go 1.16
4 |
--------------------------------------------------------------------------------
/example/basic-noapi/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "version": "1.0.0",
4 | "description": "",
5 | "private": true,
6 | "scripts": {
7 | "start": "GOROOT=`go env GOROOT` webpack serve"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "devDependencies": {
12 | "webpack": "^5.42.0",
13 | "webpack-cli": "^4.7.2",
14 | "webpack-dev-server": "^4.9.3"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/example/basic-noapi/src/api/bridge.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "syscall/js"
4 |
5 | var (
6 | // bridgeName is the namesace for all functions and values set.
7 | //
8 | // The returning JavaScript proxy via the webpack loader will look for functions and values under this namespace.
9 | bridgeName = "__go_wasm__"
10 |
11 | // The JS object of the __go_wasm__ value.
12 | bridge js.Value
13 |
14 | // Wrapper is a simple JS function that when called with a Go Function, will return a new function that will throw
15 | // if the property `error` is an instance of JavaScript's `error`.
16 | //
17 | // All Go functions in the bridgeName proxy are expected to be the result of calling wrapper with the Go function.
18 | wrapper js.Value
19 | )
20 |
21 | // newReturnValue creates an object with the value as the result.
22 | // See wrapGoFunc for the reasoning behind style style of returning values from Go functions.
23 | func newReturnValue(value interface{}) js.Value {
24 | jsObject := js.Global().Get("Object").New()
25 | jsObject.Set("result", value)
26 |
27 | return jsObject
28 | }
29 |
30 | // newReturnError creates an object with the goError's message and creates a Javascript Error object with the message.
31 | //
32 | // See wrapGoFunc for the reasoning behind style style of returning values from Go functions.
33 | func newReturnError(goErr error) js.Value {
34 | jsObject := js.Global().Get("Object").New()
35 | jsError := js.Global().Get("Error")
36 | jsObject.Set("error", jsError.New(goErr.Error()))
37 |
38 | return jsObject
39 | }
40 |
41 | // Using this wrapper makes it possible to throw errors in go-fashion.
42 | // This means that all wrapped functions must return value and an error (respectively).
43 | //
44 | // The __wrapper__ function from JS will automatically throw if the returned object has an 'error' property.
45 | // Inversely, it will automatically give the result value if that property exists.
46 | // All Go functions directly returned via wasm should keep this in mind.
47 | func wrapGoFunc(f func(js.Value, []js.Value) (interface{}, error)) js.Func {
48 | return js.FuncOf(func(this js.Value, args []js.Value) interface{} {
49 | res, err := f(this, args)
50 | if err != nil {
51 | return newReturnError(err)
52 | }
53 |
54 | return newReturnValue(res)
55 | })
56 | }
57 |
58 | func setFunc(name string, f func(js.Value, []js.Value) (interface{}, error)) {
59 | bridge.Set(name, wrapper.Invoke(wrapGoFunc(f)))
60 | }
61 |
62 | func setValue(name string, value interface{}) {
63 | bridge.Set(name, value)
64 | }
65 |
66 | // Toggling the __ready__ value in the bridge lets JS know that everything is setup.
67 | // Setting __ready__ to true can help prevent possible race conditions of Wasm being called before everything is
68 | // registered, and potentially crashing applications.
69 | func ready() {
70 | bridge.Set("__ready__", true)
71 | <-make(chan bool, 0) // To use anything from Go WASM, the program may not exit.
72 | }
73 |
74 | // We want to make sure that this is always ran first. This means that we can make sure that whenever functions are
75 | // initialized, they are able to be set to the bridge and wrapper.
76 | func init() {
77 | bridge = js.Global().Get(bridgeName)
78 | wrapper = bridge.Get("__wrapper__")
79 | }
80 |
--------------------------------------------------------------------------------
/example/basic-noapi/src/api/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "syscall/js"
6 | )
7 |
8 | const hello = "Hello!"
9 |
10 | // helloName's first value is JavaScript's `this`.
11 | // However, the way that the JS bridge is written, it will always be JavaScript's undefined.
12 | //
13 | // If returning a non-nil error value, the resulting promise will be rejected by API consumers.
14 | // The rejected value will JavaScript's Error, with the message being the go error's message.
15 | //
16 | // See other examples which use the Go WASM bridge api, which show more flexibility and type safety when interacting
17 | // with JavaScript.
18 | func helloName(_ js.Value, args []js.Value) (interface{}, error) {
19 | return fmt.Sprintf("Hello, %s!", args[0].String()), nil
20 | }
21 |
22 | func main() {
23 | fmt.Println("golang-wasm initialized")
24 |
25 | setFunc("helloName", helloName)
26 | setValue("hello", hello)
27 | ready()
28 | }
29 |
--------------------------------------------------------------------------------
/example/basic-noapi/src/index.js:
--------------------------------------------------------------------------------
1 | import wasm from './api/main.go';
2 |
3 | const { hello, helloName } = wasm;
4 |
5 | const value = document.getElementById("value");
6 | const input = document.getElementById("input");
7 | const funcValue = document.getElementById("funcValue");
8 |
9 | const run = async () => {
10 | value.innerText = await hello();
11 |
12 | funcValue.innerText = await helloName(input.value);
13 | input.addEventListener("keyup", async (e) => {
14 | funcValue.innerText = await helloName(e.target.value);
15 | })
16 | }
17 |
18 | run()
19 |
--------------------------------------------------------------------------------
/example/basic-noapi/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | entry: './src/index.js',
5 | devServer: {
6 | static: {
7 | directory: path.resolve(__dirname, 'dist'),
8 | },
9 | compress: true,
10 | port: 3000,
11 | },
12 | mode: "development",
13 | output: {
14 | filename: 'main.js',
15 | path: path.resolve(__dirname, 'dist'),
16 | },
17 | resolve: {
18 | extensions: [".js", ".go"],
19 | fallback: {
20 | "fs": false,
21 | "os": false,
22 | "util": false,
23 | "tls": false,
24 | "net": false,
25 | "path": false,
26 | "zlib": false,
27 | "http": false,
28 | "https": false,
29 | "stream": false,
30 | "crypto": false,
31 | }
32 | },
33 | module: {
34 | rules: [
35 | {
36 | test: /\.go$/,
37 | use: [
38 | {
39 | loader: path.resolve(__dirname, '../../src/index.js')
40 | }
41 | ]
42 | }
43 | ]
44 | },
45 | performance: {
46 | assetFilter: (file) => {
47 | return !/(\.wasm|.map)$/.test(file)
48 | }
49 | },
50 | ignoreWarnings: [
51 | {
52 | module: /wasm_exec.js$/
53 | }
54 | ]
55 | };
56 |
--------------------------------------------------------------------------------
/example/basic/.gitignore:
--------------------------------------------------------------------------------
1 | dist/main.js
--------------------------------------------------------------------------------
/example/basic/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Golang-WASM Example
7 |
8 |
9 |
10 | This example project uses the Golang-WASM api.
11 |
16 |
17 | Value from Go:
18 |
19 |
20 | Call function from Go:
21 |
22 |
23 |
24 | Call function that can fail from Go:
25 |
26 | ÷
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/example/basic/go.mod:
--------------------------------------------------------------------------------
1 | module example
2 |
3 | go 1.16
4 |
5 | replace github.com/teamortix/golang-wasm/wasm => ../../wasm
6 |
7 | require github.com/teamortix/golang-wasm/wasm v0.0.0-WORKING-TREE
--------------------------------------------------------------------------------
/example/basic/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "version": "1.0.0",
4 | "description": "",
5 | "private": true,
6 | "scripts": {
7 | "start": "GOROOT=`go env GOROOT` webpack serve"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "devDependencies": {
12 | "webpack": "^5.42.0",
13 | "webpack-cli": "^4.7.2",
14 | "webpack-dev-server": "^4.9.3"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/example/basic/src/api/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 |
7 | "github.com/teamortix/golang-wasm/wasm"
8 | )
9 |
10 | const hello = "Hello!"
11 |
12 | // The Golang-WASM API automatically ports calls to this function calls from JavaScript over to call this function.
13 | // This helps gain a level of type safety that is otherwise not possible when using syscall/js.
14 | // If this function is called from JavaScript with invalid arguments, the promise is simply rejected.
15 | // Explore further how error handling works in the documentation.
16 | func helloName(name string) string {
17 | return fmt.Sprintf("Hello, %s!", name)
18 | }
19 |
20 | // This call is automatically converted to a promise resolve or rejection.
21 | // This is similar to the example in the README, however it uses float64 instead so division results are not truncated.
22 | //
23 | // If this function's second return value is a non-value nil, Golang-WASM will reject the promise of the JS call using
24 | // the error message from calling Error().
25 | func divide(x float64, y float64) (float64, error) {
26 | if y == 0 {
27 | return 0, errors.New("cannot divide by zero")
28 | }
29 | return x / y, nil
30 | }
31 |
32 | func main() {
33 | fmt.Println("golang-wasm initialized")
34 |
35 | wasm.Expose("hello", hello)
36 | wasm.Expose("helloName", helloName)
37 | wasm.Expose("divide", divide)
38 | wasm.Ready()
39 | <-make(chan bool) // To use anything from Go WASM, the program may not exit.
40 | }
41 |
--------------------------------------------------------------------------------
/example/basic/src/index.js:
--------------------------------------------------------------------------------
1 | import wasm from './api/main.go';
2 |
3 | const { hello, helloName, divide } = wasm;
4 |
5 | const value = document.getElementById("hello");
6 |
7 | const inputName = document.getElementById("inputName");
8 | const name = document.getElementById("name");
9 |
10 | const inputX = document.getElementById("inputX");
11 | const inputY = document.getElementById("inputY");
12 | const divideElem = document.getElementById("divide");
13 |
14 |
15 | const doDivision = async (x, y) => divideElem.innerText =
16 | await divide(Number(x), Number(y))
17 | .catch(err => err.toString());
18 |
19 | const run = async () => {
20 | value.innerText = await hello();
21 |
22 | name.innerText = await helloName(inputName.value);
23 | doDivision(inputX.value, inputY.value);
24 |
25 | inputName.addEventListener("keyup", async (e) => name.innerText = await helloName(e.target.value));
26 | inputX.addEventListener("change", (e) => doDivision(e.target.value, inputY.value));
27 | inputY.addEventListener("change", (e) => doDivision(inputX.value, e.target.value, inputY.value));
28 | }
29 |
30 | run()
31 |
--------------------------------------------------------------------------------
/example/basic/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | entry: './src/index.js',
5 | devServer: {
6 | static: {
7 | directory: path.resolve(__dirname, 'dist'),
8 | },
9 | compress: true,
10 | port: 3000,
11 | },
12 | mode: "development",
13 | output: {
14 | filename: 'main.js',
15 | path: path.resolve(__dirname, 'dist'),
16 | },
17 | resolve: {
18 | extensions: [".js", ".go"],
19 | fallback: {
20 | "fs": false,
21 | "os": false,
22 | "util": false,
23 | "tls": false,
24 | "net": false,
25 | "path": false,
26 | "zlib": false,
27 | "http": false,
28 | "https": false,
29 | "stream": false,
30 | "crypto": false,
31 | }
32 | },
33 | module: {
34 | rules: [
35 | {
36 | test: /\.go$/,
37 | use: [
38 | {
39 | loader: path.resolve(__dirname, '../../src/index.js')
40 | }
41 | ]
42 | }
43 | ]
44 | },
45 | performance: {
46 | assetFilter: (file) => {
47 | return !/(\.wasm|.map)$/.test(file)
48 | }
49 | },
50 | ignoreWarnings: [
51 | {
52 | module: /wasm_exec.js$/
53 | }
54 | ]
55 | };
56 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "golang-wasm",
3 | "version": "0.0.1",
4 | "lockfileVersion": 2,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "golang-wasm",
9 | "version": "0.0.1",
10 | "license": "MIT",
11 | "dependencies": {
12 | "lookpath": "^1.2.0",
13 | "webpack": "^5.27.0"
14 | }
15 | },
16 | "node_modules/@types/eslint": {
17 | "version": "7.2.13",
18 | "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.13.tgz",
19 | "integrity": "sha512-LKmQCWAlnVHvvXq4oasNUMTJJb2GwSyTY8+1C7OH5ILR8mPLaljv1jxL1bXW3xB3jFbQxTKxJAvI8PyjB09aBg==",
20 | "dependencies": {
21 | "@types/estree": "*",
22 | "@types/json-schema": "*"
23 | }
24 | },
25 | "node_modules/@types/eslint-scope": {
26 | "version": "3.7.0",
27 | "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.0.tgz",
28 | "integrity": "sha512-O/ql2+rrCUe2W2rs7wMR+GqPRcgB6UiqN5RhrR5xruFlY7l9YLMn0ZkDzjoHLeiFkR8MCQZVudUuuvQ2BLC9Qw==",
29 | "dependencies": {
30 | "@types/eslint": "*",
31 | "@types/estree": "*"
32 | }
33 | },
34 | "node_modules/@types/estree": {
35 | "version": "0.0.48",
36 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.48.tgz",
37 | "integrity": "sha512-LfZwXoGUDo0C3me81HXgkBg5CTQYb6xzEl+fNmbO4JdRiSKQ8A0GD1OBBvKAIsbCUgoyAty7m99GqqMQe784ew=="
38 | },
39 | "node_modules/@types/json-schema": {
40 | "version": "7.0.7",
41 | "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz",
42 | "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA=="
43 | },
44 | "node_modules/@types/node": {
45 | "version": "16.0.0",
46 | "resolved": "https://registry.npmjs.org/@types/node/-/node-16.0.0.tgz",
47 | "integrity": "sha512-TmCW5HoZ2o2/z2EYi109jLqIaPIi9y/lc2LmDCWzuCi35bcaQ+OtUh6nwBiFK7SOu25FAU5+YKdqFZUwtqGSdg=="
48 | },
49 | "node_modules/@webassemblyjs/ast": {
50 | "version": "1.11.0",
51 | "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.0.tgz",
52 | "integrity": "sha512-kX2W49LWsbthrmIRMbQZuQDhGtjyqXfEmmHyEi4XWnSZtPmxY0+3anPIzsnRb45VH/J55zlOfWvZuY47aJZTJg==",
53 | "dependencies": {
54 | "@webassemblyjs/helper-numbers": "1.11.0",
55 | "@webassemblyjs/helper-wasm-bytecode": "1.11.0"
56 | }
57 | },
58 | "node_modules/@webassemblyjs/floating-point-hex-parser": {
59 | "version": "1.11.0",
60 | "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.0.tgz",
61 | "integrity": "sha512-Q/aVYs/VnPDVYvsCBL/gSgwmfjeCb4LW8+TMrO3cSzJImgv8lxxEPM2JA5jMrivE7LSz3V+PFqtMbls3m1exDA=="
62 | },
63 | "node_modules/@webassemblyjs/helper-api-error": {
64 | "version": "1.11.0",
65 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.0.tgz",
66 | "integrity": "sha512-baT/va95eXiXb2QflSx95QGT5ClzWpGaa8L7JnJbgzoYeaA27FCvuBXU758l+KXWRndEmUXjP0Q5fibhavIn8w=="
67 | },
68 | "node_modules/@webassemblyjs/helper-buffer": {
69 | "version": "1.11.0",
70 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.0.tgz",
71 | "integrity": "sha512-u9HPBEl4DS+vA8qLQdEQ6N/eJQ7gT7aNvMIo8AAWvAl/xMrcOSiI2M0MAnMCy3jIFke7bEee/JwdX1nUpCtdyA=="
72 | },
73 | "node_modules/@webassemblyjs/helper-numbers": {
74 | "version": "1.11.0",
75 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.0.tgz",
76 | "integrity": "sha512-DhRQKelIj01s5IgdsOJMKLppI+4zpmcMQ3XboFPLwCpSNH6Hqo1ritgHgD0nqHeSYqofA6aBN/NmXuGjM1jEfQ==",
77 | "dependencies": {
78 | "@webassemblyjs/floating-point-hex-parser": "1.11.0",
79 | "@webassemblyjs/helper-api-error": "1.11.0",
80 | "@xtuc/long": "4.2.2"
81 | }
82 | },
83 | "node_modules/@webassemblyjs/helper-wasm-bytecode": {
84 | "version": "1.11.0",
85 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.0.tgz",
86 | "integrity": "sha512-MbmhvxXExm542tWREgSFnOVo07fDpsBJg3sIl6fSp9xuu75eGz5lz31q7wTLffwL3Za7XNRCMZy210+tnsUSEA=="
87 | },
88 | "node_modules/@webassemblyjs/helper-wasm-section": {
89 | "version": "1.11.0",
90 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.0.tgz",
91 | "integrity": "sha512-3Eb88hcbfY/FCukrg6i3EH8H2UsD7x8Vy47iVJrP967A9JGqgBVL9aH71SETPx1JrGsOUVLo0c7vMCN22ytJew==",
92 | "dependencies": {
93 | "@webassemblyjs/ast": "1.11.0",
94 | "@webassemblyjs/helper-buffer": "1.11.0",
95 | "@webassemblyjs/helper-wasm-bytecode": "1.11.0",
96 | "@webassemblyjs/wasm-gen": "1.11.0"
97 | }
98 | },
99 | "node_modules/@webassemblyjs/ieee754": {
100 | "version": "1.11.0",
101 | "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.0.tgz",
102 | "integrity": "sha512-KXzOqpcYQwAfeQ6WbF6HXo+0udBNmw0iXDmEK5sFlmQdmND+tr773Ti8/5T/M6Tl/413ArSJErATd8In3B+WBA==",
103 | "dependencies": {
104 | "@xtuc/ieee754": "^1.2.0"
105 | }
106 | },
107 | "node_modules/@webassemblyjs/leb128": {
108 | "version": "1.11.0",
109 | "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.0.tgz",
110 | "integrity": "sha512-aqbsHa1mSQAbeeNcl38un6qVY++hh8OpCOzxhixSYgbRfNWcxJNJQwe2rezK9XEcssJbbWIkblaJRwGMS9zp+g==",
111 | "dependencies": {
112 | "@xtuc/long": "4.2.2"
113 | }
114 | },
115 | "node_modules/@webassemblyjs/utf8": {
116 | "version": "1.11.0",
117 | "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.0.tgz",
118 | "integrity": "sha512-A/lclGxH6SpSLSyFowMzO/+aDEPU4hvEiooCMXQPcQFPPJaYcPQNKGOCLUySJsYJ4trbpr+Fs08n4jelkVTGVw=="
119 | },
120 | "node_modules/@webassemblyjs/wasm-edit": {
121 | "version": "1.11.0",
122 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.0.tgz",
123 | "integrity": "sha512-JHQ0damXy0G6J9ucyKVXO2j08JVJ2ntkdJlq1UTiUrIgfGMmA7Ik5VdC/L8hBK46kVJgujkBIoMtT8yVr+yVOQ==",
124 | "dependencies": {
125 | "@webassemblyjs/ast": "1.11.0",
126 | "@webassemblyjs/helper-buffer": "1.11.0",
127 | "@webassemblyjs/helper-wasm-bytecode": "1.11.0",
128 | "@webassemblyjs/helper-wasm-section": "1.11.0",
129 | "@webassemblyjs/wasm-gen": "1.11.0",
130 | "@webassemblyjs/wasm-opt": "1.11.0",
131 | "@webassemblyjs/wasm-parser": "1.11.0",
132 | "@webassemblyjs/wast-printer": "1.11.0"
133 | }
134 | },
135 | "node_modules/@webassemblyjs/wasm-gen": {
136 | "version": "1.11.0",
137 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.0.tgz",
138 | "integrity": "sha512-BEUv1aj0WptCZ9kIS30th5ILASUnAPEvE3tVMTrItnZRT9tXCLW2LEXT8ezLw59rqPP9klh9LPmpU+WmRQmCPQ==",
139 | "dependencies": {
140 | "@webassemblyjs/ast": "1.11.0",
141 | "@webassemblyjs/helper-wasm-bytecode": "1.11.0",
142 | "@webassemblyjs/ieee754": "1.11.0",
143 | "@webassemblyjs/leb128": "1.11.0",
144 | "@webassemblyjs/utf8": "1.11.0"
145 | }
146 | },
147 | "node_modules/@webassemblyjs/wasm-opt": {
148 | "version": "1.11.0",
149 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.0.tgz",
150 | "integrity": "sha512-tHUSP5F4ywyh3hZ0+fDQuWxKx3mJiPeFufg+9gwTpYp324mPCQgnuVKwzLTZVqj0duRDovnPaZqDwoyhIO8kYg==",
151 | "dependencies": {
152 | "@webassemblyjs/ast": "1.11.0",
153 | "@webassemblyjs/helper-buffer": "1.11.0",
154 | "@webassemblyjs/wasm-gen": "1.11.0",
155 | "@webassemblyjs/wasm-parser": "1.11.0"
156 | }
157 | },
158 | "node_modules/@webassemblyjs/wasm-parser": {
159 | "version": "1.11.0",
160 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.0.tgz",
161 | "integrity": "sha512-6L285Sgu9gphrcpDXINvm0M9BskznnzJTE7gYkjDbxET28shDqp27wpruyx3C2S/dvEwiigBwLA1cz7lNUi0kw==",
162 | "dependencies": {
163 | "@webassemblyjs/ast": "1.11.0",
164 | "@webassemblyjs/helper-api-error": "1.11.0",
165 | "@webassemblyjs/helper-wasm-bytecode": "1.11.0",
166 | "@webassemblyjs/ieee754": "1.11.0",
167 | "@webassemblyjs/leb128": "1.11.0",
168 | "@webassemblyjs/utf8": "1.11.0"
169 | }
170 | },
171 | "node_modules/@webassemblyjs/wast-printer": {
172 | "version": "1.11.0",
173 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.0.tgz",
174 | "integrity": "sha512-Fg5OX46pRdTgB7rKIUojkh9vXaVN6sGYCnEiJN1GYkb0RPwShZXp6KTDqmoMdQPKhcroOXh3fEzmkWmCYaKYhQ==",
175 | "dependencies": {
176 | "@webassemblyjs/ast": "1.11.0",
177 | "@xtuc/long": "4.2.2"
178 | }
179 | },
180 | "node_modules/@xtuc/ieee754": {
181 | "version": "1.2.0",
182 | "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
183 | "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA=="
184 | },
185 | "node_modules/@xtuc/long": {
186 | "version": "4.2.2",
187 | "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
188 | "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="
189 | },
190 | "node_modules/acorn": {
191 | "version": "8.4.1",
192 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.4.1.tgz",
193 | "integrity": "sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA==",
194 | "bin": {
195 | "acorn": "bin/acorn"
196 | },
197 | "engines": {
198 | "node": ">=0.4.0"
199 | }
200 | },
201 | "node_modules/ajv": {
202 | "version": "6.12.6",
203 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
204 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
205 | "dependencies": {
206 | "fast-deep-equal": "^3.1.1",
207 | "fast-json-stable-stringify": "^2.0.0",
208 | "json-schema-traverse": "^0.4.1",
209 | "uri-js": "^4.2.2"
210 | },
211 | "funding": {
212 | "type": "github",
213 | "url": "https://github.com/sponsors/epoberezkin"
214 | }
215 | },
216 | "node_modules/ajv-keywords": {
217 | "version": "3.5.2",
218 | "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
219 | "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
220 | "peerDependencies": {
221 | "ajv": "^6.9.1"
222 | }
223 | },
224 | "node_modules/browserslist": {
225 | "version": "4.16.6",
226 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz",
227 | "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==",
228 | "dependencies": {
229 | "caniuse-lite": "^1.0.30001219",
230 | "colorette": "^1.2.2",
231 | "electron-to-chromium": "^1.3.723",
232 | "escalade": "^3.1.1",
233 | "node-releases": "^1.1.71"
234 | },
235 | "bin": {
236 | "browserslist": "cli.js"
237 | },
238 | "engines": {
239 | "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
240 | },
241 | "funding": {
242 | "type": "opencollective",
243 | "url": "https://opencollective.com/browserslist"
244 | }
245 | },
246 | "node_modules/buffer-from": {
247 | "version": "1.1.1",
248 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
249 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
250 | },
251 | "node_modules/caniuse-lite": {
252 | "version": "1.0.30001241",
253 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001241.tgz",
254 | "integrity": "sha512-1uoSZ1Pq1VpH0WerIMqwptXHNNGfdl7d1cJUFs80CwQ/lVzdhTvsFZCeNFslze7AjsQnb4C85tzclPa1VShbeQ==",
255 | "funding": {
256 | "type": "opencollective",
257 | "url": "https://opencollective.com/browserslist"
258 | }
259 | },
260 | "node_modules/chrome-trace-event": {
261 | "version": "1.0.3",
262 | "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
263 | "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==",
264 | "engines": {
265 | "node": ">=6.0"
266 | }
267 | },
268 | "node_modules/colorette": {
269 | "version": "1.2.2",
270 | "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz",
271 | "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w=="
272 | },
273 | "node_modules/commander": {
274 | "version": "2.20.3",
275 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
276 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
277 | },
278 | "node_modules/electron-to-chromium": {
279 | "version": "1.3.766",
280 | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.766.tgz",
281 | "integrity": "sha512-u2quJ862q9reRKh/je3GXis3w38+RoXH1J9N3XjtsS6NzmUAosNsyZgUVFZPN/ZlJ3v6T0rTyZR3q/J5c6Sy5w=="
282 | },
283 | "node_modules/enhanced-resolve": {
284 | "version": "5.8.2",
285 | "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.2.tgz",
286 | "integrity": "sha512-F27oB3WuHDzvR2DOGNTaYy0D5o0cnrv8TeI482VM4kYgQd/FT9lUQwuNsJ0oOHtBUq7eiW5ytqzp7nBFknL+GA==",
287 | "dependencies": {
288 | "graceful-fs": "^4.2.4",
289 | "tapable": "^2.2.0"
290 | },
291 | "engines": {
292 | "node": ">=10.13.0"
293 | }
294 | },
295 | "node_modules/es-module-lexer": {
296 | "version": "0.6.0",
297 | "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.6.0.tgz",
298 | "integrity": "sha512-f8kcHX1ArhllUtb/wVSyvygoKCznIjnxhLxy7TCvIiMdT7fL4ZDTIKaadMe6eLvOXg6Wk02UeoFgUoZ2EKZZUA=="
299 | },
300 | "node_modules/escalade": {
301 | "version": "3.1.1",
302 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
303 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
304 | "engines": {
305 | "node": ">=6"
306 | }
307 | },
308 | "node_modules/eslint-scope": {
309 | "version": "5.1.1",
310 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
311 | "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
312 | "dependencies": {
313 | "esrecurse": "^4.3.0",
314 | "estraverse": "^4.1.1"
315 | },
316 | "engines": {
317 | "node": ">=8.0.0"
318 | }
319 | },
320 | "node_modules/esrecurse": {
321 | "version": "4.3.0",
322 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
323 | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
324 | "dependencies": {
325 | "estraverse": "^5.2.0"
326 | },
327 | "engines": {
328 | "node": ">=4.0"
329 | }
330 | },
331 | "node_modules/esrecurse/node_modules/estraverse": {
332 | "version": "5.2.0",
333 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
334 | "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
335 | "engines": {
336 | "node": ">=4.0"
337 | }
338 | },
339 | "node_modules/estraverse": {
340 | "version": "4.3.0",
341 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
342 | "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
343 | "engines": {
344 | "node": ">=4.0"
345 | }
346 | },
347 | "node_modules/events": {
348 | "version": "3.3.0",
349 | "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
350 | "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
351 | "engines": {
352 | "node": ">=0.8.x"
353 | }
354 | },
355 | "node_modules/fast-deep-equal": {
356 | "version": "3.1.3",
357 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
358 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
359 | },
360 | "node_modules/fast-json-stable-stringify": {
361 | "version": "2.1.0",
362 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
363 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
364 | },
365 | "node_modules/glob-to-regexp": {
366 | "version": "0.4.1",
367 | "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
368 | "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="
369 | },
370 | "node_modules/graceful-fs": {
371 | "version": "4.2.6",
372 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
373 | "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ=="
374 | },
375 | "node_modules/has-flag": {
376 | "version": "4.0.0",
377 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
378 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
379 | "engines": {
380 | "node": ">=8"
381 | }
382 | },
383 | "node_modules/jest-worker": {
384 | "version": "27.0.6",
385 | "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.0.6.tgz",
386 | "integrity": "sha512-qupxcj/dRuA3xHPMUd40gr2EaAurFbkwzOh7wfPaeE9id7hyjURRQoqNfHifHK3XjJU6YJJUQKILGUnwGPEOCA==",
387 | "dependencies": {
388 | "@types/node": "*",
389 | "merge-stream": "^2.0.0",
390 | "supports-color": "^8.0.0"
391 | },
392 | "engines": {
393 | "node": ">= 10.13.0"
394 | }
395 | },
396 | "node_modules/json-parse-better-errors": {
397 | "version": "1.0.2",
398 | "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
399 | "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="
400 | },
401 | "node_modules/json-schema-traverse": {
402 | "version": "0.4.1",
403 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
404 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
405 | },
406 | "node_modules/loader-runner": {
407 | "version": "4.2.0",
408 | "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz",
409 | "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==",
410 | "engines": {
411 | "node": ">=6.11.5"
412 | }
413 | },
414 | "node_modules/lookpath": {
415 | "version": "1.2.1",
416 | "resolved": "https://registry.npmjs.org/lookpath/-/lookpath-1.2.1.tgz",
417 | "integrity": "sha512-dMlL1UqJmBNoXLxRM2lZICttyf9U2+5leFewVRWujybSoL9HAWfDw53NwIffnc5uPHmBiP5EosR/R8lkB4jftQ==",
418 | "bin": {
419 | "lookpath": "bin/lookpath.js"
420 | },
421 | "engines": {
422 | "npm": ">=6.13.4"
423 | }
424 | },
425 | "node_modules/merge-stream": {
426 | "version": "2.0.0",
427 | "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
428 | "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="
429 | },
430 | "node_modules/mime-db": {
431 | "version": "1.48.0",
432 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz",
433 | "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==",
434 | "engines": {
435 | "node": ">= 0.6"
436 | }
437 | },
438 | "node_modules/mime-types": {
439 | "version": "2.1.31",
440 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz",
441 | "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==",
442 | "dependencies": {
443 | "mime-db": "1.48.0"
444 | },
445 | "engines": {
446 | "node": ">= 0.6"
447 | }
448 | },
449 | "node_modules/neo-async": {
450 | "version": "2.6.2",
451 | "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
452 | "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
453 | },
454 | "node_modules/node-releases": {
455 | "version": "1.1.73",
456 | "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz",
457 | "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg=="
458 | },
459 | "node_modules/p-limit": {
460 | "version": "3.1.0",
461 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
462 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
463 | "dependencies": {
464 | "yocto-queue": "^0.1.0"
465 | },
466 | "engines": {
467 | "node": ">=10"
468 | },
469 | "funding": {
470 | "url": "https://github.com/sponsors/sindresorhus"
471 | }
472 | },
473 | "node_modules/punycode": {
474 | "version": "2.1.1",
475 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
476 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
477 | "engines": {
478 | "node": ">=6"
479 | }
480 | },
481 | "node_modules/randombytes": {
482 | "version": "2.1.0",
483 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
484 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
485 | "dependencies": {
486 | "safe-buffer": "^5.1.0"
487 | }
488 | },
489 | "node_modules/safe-buffer": {
490 | "version": "5.2.1",
491 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
492 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
493 | "funding": [
494 | {
495 | "type": "github",
496 | "url": "https://github.com/sponsors/feross"
497 | },
498 | {
499 | "type": "patreon",
500 | "url": "https://www.patreon.com/feross"
501 | },
502 | {
503 | "type": "consulting",
504 | "url": "https://feross.org/support"
505 | }
506 | ]
507 | },
508 | "node_modules/schema-utils": {
509 | "version": "3.0.0",
510 | "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz",
511 | "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==",
512 | "dependencies": {
513 | "@types/json-schema": "^7.0.6",
514 | "ajv": "^6.12.5",
515 | "ajv-keywords": "^3.5.2"
516 | },
517 | "engines": {
518 | "node": ">= 10.13.0"
519 | },
520 | "funding": {
521 | "type": "opencollective",
522 | "url": "https://opencollective.com/webpack"
523 | }
524 | },
525 | "node_modules/serialize-javascript": {
526 | "version": "6.0.0",
527 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
528 | "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
529 | "dependencies": {
530 | "randombytes": "^2.1.0"
531 | }
532 | },
533 | "node_modules/source-list-map": {
534 | "version": "2.0.1",
535 | "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
536 | "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw=="
537 | },
538 | "node_modules/source-map": {
539 | "version": "0.6.1",
540 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
541 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
542 | "engines": {
543 | "node": ">=0.10.0"
544 | }
545 | },
546 | "node_modules/source-map-support": {
547 | "version": "0.5.19",
548 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
549 | "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
550 | "dependencies": {
551 | "buffer-from": "^1.0.0",
552 | "source-map": "^0.6.0"
553 | }
554 | },
555 | "node_modules/supports-color": {
556 | "version": "8.1.1",
557 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
558 | "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
559 | "dependencies": {
560 | "has-flag": "^4.0.0"
561 | },
562 | "engines": {
563 | "node": ">=10"
564 | },
565 | "funding": {
566 | "url": "https://github.com/chalk/supports-color?sponsor=1"
567 | }
568 | },
569 | "node_modules/tapable": {
570 | "version": "2.2.0",
571 | "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz",
572 | "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==",
573 | "engines": {
574 | "node": ">=6"
575 | }
576 | },
577 | "node_modules/terser": {
578 | "version": "5.7.1",
579 | "resolved": "https://registry.npmjs.org/terser/-/terser-5.7.1.tgz",
580 | "integrity": "sha512-b3e+d5JbHAe/JSjwsC3Zn55wsBIM7AsHLjKxT31kGCldgbpFePaFo+PiddtO6uwRZWRw7sPXmAN8dTW61xmnSg==",
581 | "dependencies": {
582 | "commander": "^2.20.0",
583 | "source-map": "~0.7.2",
584 | "source-map-support": "~0.5.19"
585 | },
586 | "bin": {
587 | "terser": "bin/terser"
588 | },
589 | "engines": {
590 | "node": ">=10"
591 | }
592 | },
593 | "node_modules/terser-webpack-plugin": {
594 | "version": "5.1.4",
595 | "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.1.4.tgz",
596 | "integrity": "sha512-C2WkFwstHDhVEmsmlCxrXUtVklS+Ir1A7twrYzrDrQQOIMOaVAYykaoo/Aq1K0QRkMoY2hhvDQY1cm4jnIMFwA==",
597 | "dependencies": {
598 | "jest-worker": "^27.0.2",
599 | "p-limit": "^3.1.0",
600 | "schema-utils": "^3.0.0",
601 | "serialize-javascript": "^6.0.0",
602 | "source-map": "^0.6.1",
603 | "terser": "^5.7.0"
604 | },
605 | "engines": {
606 | "node": ">= 10.13.0"
607 | },
608 | "funding": {
609 | "type": "opencollective",
610 | "url": "https://opencollective.com/webpack"
611 | },
612 | "peerDependencies": {
613 | "webpack": "^5.1.0"
614 | }
615 | },
616 | "node_modules/terser/node_modules/source-map": {
617 | "version": "0.7.3",
618 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
619 | "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
620 | "engines": {
621 | "node": ">= 8"
622 | }
623 | },
624 | "node_modules/uri-js": {
625 | "version": "4.4.1",
626 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
627 | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
628 | "dependencies": {
629 | "punycode": "^2.1.0"
630 | }
631 | },
632 | "node_modules/watchpack": {
633 | "version": "2.2.0",
634 | "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.2.0.tgz",
635 | "integrity": "sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==",
636 | "dependencies": {
637 | "glob-to-regexp": "^0.4.1",
638 | "graceful-fs": "^4.1.2"
639 | },
640 | "engines": {
641 | "node": ">=10.13.0"
642 | }
643 | },
644 | "node_modules/webpack": {
645 | "version": "5.42.0",
646 | "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.42.0.tgz",
647 | "integrity": "sha512-Ln8HL0F831t1x/yPB/qZEUVmZM4w9BnHZ1EQD/sAUHv8m22hthoPniWTXEzFMh/Sf84mhrahut22TX5KxWGuyQ==",
648 | "dependencies": {
649 | "@types/eslint-scope": "^3.7.0",
650 | "@types/estree": "^0.0.48",
651 | "@webassemblyjs/ast": "1.11.0",
652 | "@webassemblyjs/wasm-edit": "1.11.0",
653 | "@webassemblyjs/wasm-parser": "1.11.0",
654 | "acorn": "^8.4.1",
655 | "browserslist": "^4.14.5",
656 | "chrome-trace-event": "^1.0.2",
657 | "enhanced-resolve": "^5.8.0",
658 | "es-module-lexer": "^0.6.0",
659 | "eslint-scope": "5.1.1",
660 | "events": "^3.2.0",
661 | "glob-to-regexp": "^0.4.1",
662 | "graceful-fs": "^4.2.4",
663 | "json-parse-better-errors": "^1.0.2",
664 | "loader-runner": "^4.2.0",
665 | "mime-types": "^2.1.27",
666 | "neo-async": "^2.6.2",
667 | "schema-utils": "^3.0.0",
668 | "tapable": "^2.1.1",
669 | "terser-webpack-plugin": "^5.1.3",
670 | "watchpack": "^2.2.0",
671 | "webpack-sources": "^2.3.0"
672 | },
673 | "bin": {
674 | "webpack": "bin/webpack.js"
675 | },
676 | "engines": {
677 | "node": ">=10.13.0"
678 | },
679 | "funding": {
680 | "type": "opencollective",
681 | "url": "https://opencollective.com/webpack"
682 | },
683 | "peerDependenciesMeta": {
684 | "webpack-cli": {
685 | "optional": true
686 | }
687 | }
688 | },
689 | "node_modules/webpack-sources": {
690 | "version": "2.3.0",
691 | "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.0.tgz",
692 | "integrity": "sha512-WyOdtwSvOML1kbgtXbTDnEW0jkJ7hZr/bDByIwszhWd/4XX1A3XMkrbFMsuH4+/MfLlZCUzlAdg4r7jaGKEIgQ==",
693 | "dependencies": {
694 | "source-list-map": "^2.0.1",
695 | "source-map": "^0.6.1"
696 | },
697 | "engines": {
698 | "node": ">=10.13.0"
699 | }
700 | },
701 | "node_modules/yocto-queue": {
702 | "version": "0.1.0",
703 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
704 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
705 | "engines": {
706 | "node": ">=10"
707 | },
708 | "funding": {
709 | "url": "https://github.com/sponsors/sindresorhus"
710 | }
711 | }
712 | },
713 | "dependencies": {
714 | "@types/eslint": {
715 | "version": "7.2.13",
716 | "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.13.tgz",
717 | "integrity": "sha512-LKmQCWAlnVHvvXq4oasNUMTJJb2GwSyTY8+1C7OH5ILR8mPLaljv1jxL1bXW3xB3jFbQxTKxJAvI8PyjB09aBg==",
718 | "requires": {
719 | "@types/estree": "*",
720 | "@types/json-schema": "*"
721 | }
722 | },
723 | "@types/eslint-scope": {
724 | "version": "3.7.0",
725 | "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.0.tgz",
726 | "integrity": "sha512-O/ql2+rrCUe2W2rs7wMR+GqPRcgB6UiqN5RhrR5xruFlY7l9YLMn0ZkDzjoHLeiFkR8MCQZVudUuuvQ2BLC9Qw==",
727 | "requires": {
728 | "@types/eslint": "*",
729 | "@types/estree": "*"
730 | }
731 | },
732 | "@types/estree": {
733 | "version": "0.0.48",
734 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.48.tgz",
735 | "integrity": "sha512-LfZwXoGUDo0C3me81HXgkBg5CTQYb6xzEl+fNmbO4JdRiSKQ8A0GD1OBBvKAIsbCUgoyAty7m99GqqMQe784ew=="
736 | },
737 | "@types/json-schema": {
738 | "version": "7.0.7",
739 | "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz",
740 | "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA=="
741 | },
742 | "@types/node": {
743 | "version": "16.0.0",
744 | "resolved": "https://registry.npmjs.org/@types/node/-/node-16.0.0.tgz",
745 | "integrity": "sha512-TmCW5HoZ2o2/z2EYi109jLqIaPIi9y/lc2LmDCWzuCi35bcaQ+OtUh6nwBiFK7SOu25FAU5+YKdqFZUwtqGSdg=="
746 | },
747 | "@webassemblyjs/ast": {
748 | "version": "1.11.0",
749 | "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.0.tgz",
750 | "integrity": "sha512-kX2W49LWsbthrmIRMbQZuQDhGtjyqXfEmmHyEi4XWnSZtPmxY0+3anPIzsnRb45VH/J55zlOfWvZuY47aJZTJg==",
751 | "requires": {
752 | "@webassemblyjs/helper-numbers": "1.11.0",
753 | "@webassemblyjs/helper-wasm-bytecode": "1.11.0"
754 | }
755 | },
756 | "@webassemblyjs/floating-point-hex-parser": {
757 | "version": "1.11.0",
758 | "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.0.tgz",
759 | "integrity": "sha512-Q/aVYs/VnPDVYvsCBL/gSgwmfjeCb4LW8+TMrO3cSzJImgv8lxxEPM2JA5jMrivE7LSz3V+PFqtMbls3m1exDA=="
760 | },
761 | "@webassemblyjs/helper-api-error": {
762 | "version": "1.11.0",
763 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.0.tgz",
764 | "integrity": "sha512-baT/va95eXiXb2QflSx95QGT5ClzWpGaa8L7JnJbgzoYeaA27FCvuBXU758l+KXWRndEmUXjP0Q5fibhavIn8w=="
765 | },
766 | "@webassemblyjs/helper-buffer": {
767 | "version": "1.11.0",
768 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.0.tgz",
769 | "integrity": "sha512-u9HPBEl4DS+vA8qLQdEQ6N/eJQ7gT7aNvMIo8AAWvAl/xMrcOSiI2M0MAnMCy3jIFke7bEee/JwdX1nUpCtdyA=="
770 | },
771 | "@webassemblyjs/helper-numbers": {
772 | "version": "1.11.0",
773 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.0.tgz",
774 | "integrity": "sha512-DhRQKelIj01s5IgdsOJMKLppI+4zpmcMQ3XboFPLwCpSNH6Hqo1ritgHgD0nqHeSYqofA6aBN/NmXuGjM1jEfQ==",
775 | "requires": {
776 | "@webassemblyjs/floating-point-hex-parser": "1.11.0",
777 | "@webassemblyjs/helper-api-error": "1.11.0",
778 | "@xtuc/long": "4.2.2"
779 | }
780 | },
781 | "@webassemblyjs/helper-wasm-bytecode": {
782 | "version": "1.11.0",
783 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.0.tgz",
784 | "integrity": "sha512-MbmhvxXExm542tWREgSFnOVo07fDpsBJg3sIl6fSp9xuu75eGz5lz31q7wTLffwL3Za7XNRCMZy210+tnsUSEA=="
785 | },
786 | "@webassemblyjs/helper-wasm-section": {
787 | "version": "1.11.0",
788 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.0.tgz",
789 | "integrity": "sha512-3Eb88hcbfY/FCukrg6i3EH8H2UsD7x8Vy47iVJrP967A9JGqgBVL9aH71SETPx1JrGsOUVLo0c7vMCN22ytJew==",
790 | "requires": {
791 | "@webassemblyjs/ast": "1.11.0",
792 | "@webassemblyjs/helper-buffer": "1.11.0",
793 | "@webassemblyjs/helper-wasm-bytecode": "1.11.0",
794 | "@webassemblyjs/wasm-gen": "1.11.0"
795 | }
796 | },
797 | "@webassemblyjs/ieee754": {
798 | "version": "1.11.0",
799 | "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.0.tgz",
800 | "integrity": "sha512-KXzOqpcYQwAfeQ6WbF6HXo+0udBNmw0iXDmEK5sFlmQdmND+tr773Ti8/5T/M6Tl/413ArSJErATd8In3B+WBA==",
801 | "requires": {
802 | "@xtuc/ieee754": "^1.2.0"
803 | }
804 | },
805 | "@webassemblyjs/leb128": {
806 | "version": "1.11.0",
807 | "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.0.tgz",
808 | "integrity": "sha512-aqbsHa1mSQAbeeNcl38un6qVY++hh8OpCOzxhixSYgbRfNWcxJNJQwe2rezK9XEcssJbbWIkblaJRwGMS9zp+g==",
809 | "requires": {
810 | "@xtuc/long": "4.2.2"
811 | }
812 | },
813 | "@webassemblyjs/utf8": {
814 | "version": "1.11.0",
815 | "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.0.tgz",
816 | "integrity": "sha512-A/lclGxH6SpSLSyFowMzO/+aDEPU4hvEiooCMXQPcQFPPJaYcPQNKGOCLUySJsYJ4trbpr+Fs08n4jelkVTGVw=="
817 | },
818 | "@webassemblyjs/wasm-edit": {
819 | "version": "1.11.0",
820 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.0.tgz",
821 | "integrity": "sha512-JHQ0damXy0G6J9ucyKVXO2j08JVJ2ntkdJlq1UTiUrIgfGMmA7Ik5VdC/L8hBK46kVJgujkBIoMtT8yVr+yVOQ==",
822 | "requires": {
823 | "@webassemblyjs/ast": "1.11.0",
824 | "@webassemblyjs/helper-buffer": "1.11.0",
825 | "@webassemblyjs/helper-wasm-bytecode": "1.11.0",
826 | "@webassemblyjs/helper-wasm-section": "1.11.0",
827 | "@webassemblyjs/wasm-gen": "1.11.0",
828 | "@webassemblyjs/wasm-opt": "1.11.0",
829 | "@webassemblyjs/wasm-parser": "1.11.0",
830 | "@webassemblyjs/wast-printer": "1.11.0"
831 | }
832 | },
833 | "@webassemblyjs/wasm-gen": {
834 | "version": "1.11.0",
835 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.0.tgz",
836 | "integrity": "sha512-BEUv1aj0WptCZ9kIS30th5ILASUnAPEvE3tVMTrItnZRT9tXCLW2LEXT8ezLw59rqPP9klh9LPmpU+WmRQmCPQ==",
837 | "requires": {
838 | "@webassemblyjs/ast": "1.11.0",
839 | "@webassemblyjs/helper-wasm-bytecode": "1.11.0",
840 | "@webassemblyjs/ieee754": "1.11.0",
841 | "@webassemblyjs/leb128": "1.11.0",
842 | "@webassemblyjs/utf8": "1.11.0"
843 | }
844 | },
845 | "@webassemblyjs/wasm-opt": {
846 | "version": "1.11.0",
847 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.0.tgz",
848 | "integrity": "sha512-tHUSP5F4ywyh3hZ0+fDQuWxKx3mJiPeFufg+9gwTpYp324mPCQgnuVKwzLTZVqj0duRDovnPaZqDwoyhIO8kYg==",
849 | "requires": {
850 | "@webassemblyjs/ast": "1.11.0",
851 | "@webassemblyjs/helper-buffer": "1.11.0",
852 | "@webassemblyjs/wasm-gen": "1.11.0",
853 | "@webassemblyjs/wasm-parser": "1.11.0"
854 | }
855 | },
856 | "@webassemblyjs/wasm-parser": {
857 | "version": "1.11.0",
858 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.0.tgz",
859 | "integrity": "sha512-6L285Sgu9gphrcpDXINvm0M9BskznnzJTE7gYkjDbxET28shDqp27wpruyx3C2S/dvEwiigBwLA1cz7lNUi0kw==",
860 | "requires": {
861 | "@webassemblyjs/ast": "1.11.0",
862 | "@webassemblyjs/helper-api-error": "1.11.0",
863 | "@webassemblyjs/helper-wasm-bytecode": "1.11.0",
864 | "@webassemblyjs/ieee754": "1.11.0",
865 | "@webassemblyjs/leb128": "1.11.0",
866 | "@webassemblyjs/utf8": "1.11.0"
867 | }
868 | },
869 | "@webassemblyjs/wast-printer": {
870 | "version": "1.11.0",
871 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.0.tgz",
872 | "integrity": "sha512-Fg5OX46pRdTgB7rKIUojkh9vXaVN6sGYCnEiJN1GYkb0RPwShZXp6KTDqmoMdQPKhcroOXh3fEzmkWmCYaKYhQ==",
873 | "requires": {
874 | "@webassemblyjs/ast": "1.11.0",
875 | "@xtuc/long": "4.2.2"
876 | }
877 | },
878 | "@xtuc/ieee754": {
879 | "version": "1.2.0",
880 | "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
881 | "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA=="
882 | },
883 | "@xtuc/long": {
884 | "version": "4.2.2",
885 | "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
886 | "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="
887 | },
888 | "acorn": {
889 | "version": "8.4.1",
890 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.4.1.tgz",
891 | "integrity": "sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA=="
892 | },
893 | "ajv": {
894 | "version": "6.12.6",
895 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
896 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
897 | "requires": {
898 | "fast-deep-equal": "^3.1.1",
899 | "fast-json-stable-stringify": "^2.0.0",
900 | "json-schema-traverse": "^0.4.1",
901 | "uri-js": "^4.2.2"
902 | }
903 | },
904 | "ajv-keywords": {
905 | "version": "3.5.2",
906 | "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
907 | "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
908 | "requires": {}
909 | },
910 | "browserslist": {
911 | "version": "4.16.6",
912 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz",
913 | "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==",
914 | "requires": {
915 | "caniuse-lite": "^1.0.30001219",
916 | "colorette": "^1.2.2",
917 | "electron-to-chromium": "^1.3.723",
918 | "escalade": "^3.1.1",
919 | "node-releases": "^1.1.71"
920 | }
921 | },
922 | "buffer-from": {
923 | "version": "1.1.1",
924 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
925 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
926 | },
927 | "caniuse-lite": {
928 | "version": "1.0.30001241",
929 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001241.tgz",
930 | "integrity": "sha512-1uoSZ1Pq1VpH0WerIMqwptXHNNGfdl7d1cJUFs80CwQ/lVzdhTvsFZCeNFslze7AjsQnb4C85tzclPa1VShbeQ=="
931 | },
932 | "chrome-trace-event": {
933 | "version": "1.0.3",
934 | "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
935 | "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg=="
936 | },
937 | "colorette": {
938 | "version": "1.2.2",
939 | "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz",
940 | "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w=="
941 | },
942 | "commander": {
943 | "version": "2.20.3",
944 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
945 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
946 | },
947 | "electron-to-chromium": {
948 | "version": "1.3.766",
949 | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.766.tgz",
950 | "integrity": "sha512-u2quJ862q9reRKh/je3GXis3w38+RoXH1J9N3XjtsS6NzmUAosNsyZgUVFZPN/ZlJ3v6T0rTyZR3q/J5c6Sy5w=="
951 | },
952 | "enhanced-resolve": {
953 | "version": "5.8.2",
954 | "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.2.tgz",
955 | "integrity": "sha512-F27oB3WuHDzvR2DOGNTaYy0D5o0cnrv8TeI482VM4kYgQd/FT9lUQwuNsJ0oOHtBUq7eiW5ytqzp7nBFknL+GA==",
956 | "requires": {
957 | "graceful-fs": "^4.2.4",
958 | "tapable": "^2.2.0"
959 | }
960 | },
961 | "es-module-lexer": {
962 | "version": "0.6.0",
963 | "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.6.0.tgz",
964 | "integrity": "sha512-f8kcHX1ArhllUtb/wVSyvygoKCznIjnxhLxy7TCvIiMdT7fL4ZDTIKaadMe6eLvOXg6Wk02UeoFgUoZ2EKZZUA=="
965 | },
966 | "escalade": {
967 | "version": "3.1.1",
968 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
969 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
970 | },
971 | "eslint-scope": {
972 | "version": "5.1.1",
973 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
974 | "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
975 | "requires": {
976 | "esrecurse": "^4.3.0",
977 | "estraverse": "^4.1.1"
978 | }
979 | },
980 | "esrecurse": {
981 | "version": "4.3.0",
982 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
983 | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
984 | "requires": {
985 | "estraverse": "^5.2.0"
986 | },
987 | "dependencies": {
988 | "estraverse": {
989 | "version": "5.2.0",
990 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
991 | "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ=="
992 | }
993 | }
994 | },
995 | "estraverse": {
996 | "version": "4.3.0",
997 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
998 | "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="
999 | },
1000 | "events": {
1001 | "version": "3.3.0",
1002 | "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
1003 | "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="
1004 | },
1005 | "fast-deep-equal": {
1006 | "version": "3.1.3",
1007 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
1008 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
1009 | },
1010 | "fast-json-stable-stringify": {
1011 | "version": "2.1.0",
1012 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
1013 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
1014 | },
1015 | "glob-to-regexp": {
1016 | "version": "0.4.1",
1017 | "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
1018 | "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="
1019 | },
1020 | "graceful-fs": {
1021 | "version": "4.2.6",
1022 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
1023 | "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ=="
1024 | },
1025 | "has-flag": {
1026 | "version": "4.0.0",
1027 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
1028 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
1029 | },
1030 | "jest-worker": {
1031 | "version": "27.0.6",
1032 | "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.0.6.tgz",
1033 | "integrity": "sha512-qupxcj/dRuA3xHPMUd40gr2EaAurFbkwzOh7wfPaeE9id7hyjURRQoqNfHifHK3XjJU6YJJUQKILGUnwGPEOCA==",
1034 | "requires": {
1035 | "@types/node": "*",
1036 | "merge-stream": "^2.0.0",
1037 | "supports-color": "^8.0.0"
1038 | }
1039 | },
1040 | "json-parse-better-errors": {
1041 | "version": "1.0.2",
1042 | "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
1043 | "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="
1044 | },
1045 | "json-schema-traverse": {
1046 | "version": "0.4.1",
1047 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
1048 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
1049 | },
1050 | "loader-runner": {
1051 | "version": "4.2.0",
1052 | "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz",
1053 | "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw=="
1054 | },
1055 | "lookpath": {
1056 | "version": "1.2.1",
1057 | "resolved": "https://registry.npmjs.org/lookpath/-/lookpath-1.2.1.tgz",
1058 | "integrity": "sha512-dMlL1UqJmBNoXLxRM2lZICttyf9U2+5leFewVRWujybSoL9HAWfDw53NwIffnc5uPHmBiP5EosR/R8lkB4jftQ=="
1059 | },
1060 | "merge-stream": {
1061 | "version": "2.0.0",
1062 | "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
1063 | "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="
1064 | },
1065 | "mime-db": {
1066 | "version": "1.48.0",
1067 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz",
1068 | "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ=="
1069 | },
1070 | "mime-types": {
1071 | "version": "2.1.31",
1072 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz",
1073 | "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==",
1074 | "requires": {
1075 | "mime-db": "1.48.0"
1076 | }
1077 | },
1078 | "neo-async": {
1079 | "version": "2.6.2",
1080 | "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
1081 | "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
1082 | },
1083 | "node-releases": {
1084 | "version": "1.1.73",
1085 | "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz",
1086 | "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg=="
1087 | },
1088 | "p-limit": {
1089 | "version": "3.1.0",
1090 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
1091 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
1092 | "requires": {
1093 | "yocto-queue": "^0.1.0"
1094 | }
1095 | },
1096 | "punycode": {
1097 | "version": "2.1.1",
1098 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
1099 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
1100 | },
1101 | "randombytes": {
1102 | "version": "2.1.0",
1103 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
1104 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
1105 | "requires": {
1106 | "safe-buffer": "^5.1.0"
1107 | }
1108 | },
1109 | "safe-buffer": {
1110 | "version": "5.2.1",
1111 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
1112 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
1113 | },
1114 | "schema-utils": {
1115 | "version": "3.0.0",
1116 | "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz",
1117 | "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==",
1118 | "requires": {
1119 | "@types/json-schema": "^7.0.6",
1120 | "ajv": "^6.12.5",
1121 | "ajv-keywords": "^3.5.2"
1122 | }
1123 | },
1124 | "serialize-javascript": {
1125 | "version": "6.0.0",
1126 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
1127 | "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
1128 | "requires": {
1129 | "randombytes": "^2.1.0"
1130 | }
1131 | },
1132 | "source-list-map": {
1133 | "version": "2.0.1",
1134 | "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
1135 | "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw=="
1136 | },
1137 | "source-map": {
1138 | "version": "0.6.1",
1139 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
1140 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
1141 | },
1142 | "source-map-support": {
1143 | "version": "0.5.19",
1144 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
1145 | "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
1146 | "requires": {
1147 | "buffer-from": "^1.0.0",
1148 | "source-map": "^0.6.0"
1149 | }
1150 | },
1151 | "supports-color": {
1152 | "version": "8.1.1",
1153 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
1154 | "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
1155 | "requires": {
1156 | "has-flag": "^4.0.0"
1157 | }
1158 | },
1159 | "tapable": {
1160 | "version": "2.2.0",
1161 | "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz",
1162 | "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw=="
1163 | },
1164 | "terser": {
1165 | "version": "5.7.1",
1166 | "resolved": "https://registry.npmjs.org/terser/-/terser-5.7.1.tgz",
1167 | "integrity": "sha512-b3e+d5JbHAe/JSjwsC3Zn55wsBIM7AsHLjKxT31kGCldgbpFePaFo+PiddtO6uwRZWRw7sPXmAN8dTW61xmnSg==",
1168 | "requires": {
1169 | "commander": "^2.20.0",
1170 | "source-map": "~0.7.2",
1171 | "source-map-support": "~0.5.19"
1172 | },
1173 | "dependencies": {
1174 | "source-map": {
1175 | "version": "0.7.3",
1176 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
1177 | "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ=="
1178 | }
1179 | }
1180 | },
1181 | "terser-webpack-plugin": {
1182 | "version": "5.1.4",
1183 | "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.1.4.tgz",
1184 | "integrity": "sha512-C2WkFwstHDhVEmsmlCxrXUtVklS+Ir1A7twrYzrDrQQOIMOaVAYykaoo/Aq1K0QRkMoY2hhvDQY1cm4jnIMFwA==",
1185 | "requires": {
1186 | "jest-worker": "^27.0.2",
1187 | "p-limit": "^3.1.0",
1188 | "schema-utils": "^3.0.0",
1189 | "serialize-javascript": "^6.0.0",
1190 | "source-map": "^0.6.1",
1191 | "terser": "^5.7.0"
1192 | }
1193 | },
1194 | "uri-js": {
1195 | "version": "4.4.1",
1196 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
1197 | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
1198 | "requires": {
1199 | "punycode": "^2.1.0"
1200 | }
1201 | },
1202 | "watchpack": {
1203 | "version": "2.2.0",
1204 | "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.2.0.tgz",
1205 | "integrity": "sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==",
1206 | "requires": {
1207 | "glob-to-regexp": "^0.4.1",
1208 | "graceful-fs": "^4.1.2"
1209 | }
1210 | },
1211 | "webpack": {
1212 | "version": "5.42.0",
1213 | "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.42.0.tgz",
1214 | "integrity": "sha512-Ln8HL0F831t1x/yPB/qZEUVmZM4w9BnHZ1EQD/sAUHv8m22hthoPniWTXEzFMh/Sf84mhrahut22TX5KxWGuyQ==",
1215 | "requires": {
1216 | "@types/eslint-scope": "^3.7.0",
1217 | "@types/estree": "^0.0.48",
1218 | "@webassemblyjs/ast": "1.11.0",
1219 | "@webassemblyjs/wasm-edit": "1.11.0",
1220 | "@webassemblyjs/wasm-parser": "1.11.0",
1221 | "acorn": "^8.4.1",
1222 | "browserslist": "^4.14.5",
1223 | "chrome-trace-event": "^1.0.2",
1224 | "enhanced-resolve": "^5.8.0",
1225 | "es-module-lexer": "^0.6.0",
1226 | "eslint-scope": "5.1.1",
1227 | "events": "^3.2.0",
1228 | "glob-to-regexp": "^0.4.1",
1229 | "graceful-fs": "^4.2.4",
1230 | "json-parse-better-errors": "^1.0.2",
1231 | "loader-runner": "^4.2.0",
1232 | "mime-types": "^2.1.27",
1233 | "neo-async": "^2.6.2",
1234 | "schema-utils": "^3.0.0",
1235 | "tapable": "^2.1.1",
1236 | "terser-webpack-plugin": "^5.1.3",
1237 | "watchpack": "^2.2.0",
1238 | "webpack-sources": "^2.3.0"
1239 | }
1240 | },
1241 | "webpack-sources": {
1242 | "version": "2.3.0",
1243 | "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.0.tgz",
1244 | "integrity": "sha512-WyOdtwSvOML1kbgtXbTDnEW0jkJ7hZr/bDByIwszhWd/4XX1A3XMkrbFMsuH4+/MfLlZCUzlAdg4r7jaGKEIgQ==",
1245 | "requires": {
1246 | "source-list-map": "^2.0.1",
1247 | "source-map": "^0.6.1"
1248 | }
1249 | },
1250 | "yocto-queue": {
1251 | "version": "0.1.0",
1252 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
1253 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
1254 | }
1255 | }
1256 | }
1257 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "golang-wasm",
3 | "version": "0.0.1",
4 | "description": "A webpack-based configuration to work with wasm using Go.",
5 | "main": "src/index.js",
6 | "repository": {
7 | "type": "git",
8 | "url": "https://gitea.teamortix.com/Team-Ortix/golang-wasm"
9 | },
10 | "keywords": [
11 | "golang",
12 | "wasm",
13 | "modules",
14 | "loader",
15 | "webpack"
16 | ],
17 | "author": "hhhapz, chanbakjsd",
18 | "license": "MIT",
19 | "dependencies": {
20 | "lookpath": "^1.2.0",
21 | "webpack": "^5.27.0"
22 | }
23 | }
--------------------------------------------------------------------------------
/src/bridge.js:
--------------------------------------------------------------------------------
1 | // Initially, the __go_wasm__ object will be an empty object.
2 | const g = global || window || self;
3 | if (!g.__go_wasm__) {
4 | g.__go_wasm__ = {};
5 | }
6 |
7 | /**
8 | * The maximum amount of time that we would expect Wasm to take to initialize.
9 | * If it doesn't initialize after this time, we send a warning to console.
10 | * Most likely something has gone wrong if it takes more than 3 seconds to initialize.
11 | */
12 | const maxTime = 3 * 1000;
13 |
14 | /**
15 | * bridge is an easier way to refer to the Go WASM object.
16 | */
17 | const bridge = g.__go_wasm__;
18 |
19 | /**
20 | * Wrapper is used by Go to run all Go functions in JS.
21 | *
22 | * @param {Function} goFunc a function that is expected to return an object of the following specification:
23 | * {
24 | * result: undefined | any // undefined when error is returned, or function returns undefined.
25 | * error: Error | undefined // undefined when no error is present.
26 | * }
27 | *
28 | * @returns {Function} returns a function that take arguments which are used to call the Go function.
29 | */
30 | function wrapper(goFunc) {
31 | return (...args) => {
32 | const result = goFunc.apply(undefined, args);
33 | if (result.error instanceof Error) {
34 | throw result.error;
35 | }
36 | return result.result;
37 | }
38 | }
39 |
40 | /**
41 | * Sleep is used when awaiting for Go Wasm to initialize.
42 | * It uses the lowest possible sane delay time (via requestAnimationFrame).
43 | * However, if the window is not focused, requestAnimationFrame never returns.
44 | * A timeout will ensure to be called after 50 ms, regardless of whether or not the tab is in focus.
45 | *
46 | * @returns {Promise} an always-resolving promise when a tick has been completed.
47 | */
48 | function sleep() {
49 | return new Promise((res) => {
50 | requestAnimationFrame(() => res());
51 | setTimeout(() => {
52 | res();
53 | }, 50);
54 | });
55 | }
56 |
57 | /**
58 | * @param {ArrayBuffer} getBytes a promise that is bytes of the Go Wasm object.
59 | *
60 | * @returns {Proxy} an object that can be used to call WASM's objects and properly parse their results.
61 | *
62 | * All values that want to be retrieved from the proxy, regardless of if they are a function or not, must be retrieved
63 | * as if they are from a function call.
64 | *
65 | * If a non-function value is returned however arguments are provided, a warning will be printed.
66 | */
67 | export default function (getBytes) {
68 | let proxy;
69 | let go;
70 |
71 | async function init() {
72 | bridge.__wrapper__ = wrapper;
73 |
74 | go = new g.Go();
75 | let bytes = await getBytes;
76 | let result = await WebAssembly.instantiate(bytes, go.importObject);
77 | go.run(result.instance);
78 | }
79 |
80 | init();
81 | setTimeout(() => {
82 | if (bridge.__ready__ !== true) {
83 | console.warn("Golang WASM Bridge (__go_wasm__.__ready__) still not true after max time");
84 | }
85 | }, maxTime);
86 |
87 |
88 | proxy = new Proxy(
89 | {},
90 | {
91 | get: (_, key) => {
92 | return (...args) => {
93 | return new Promise(async (res, rej) => {
94 | if (!go || go.exited) {
95 | return rej(new Error("The Go instance is not active."));
96 | }
97 | while (bridge.__ready__ !== true) {
98 | await sleep();
99 | }
100 |
101 | if (typeof bridge[key] !== 'function') {
102 | res(bridge[key]);
103 |
104 | if (args.length !== 0) {
105 | console.warn("Retrieved value from WASM returned function type, however called with arguments.")
106 | }
107 | return;
108 | }
109 |
110 | try {
111 | res(bridge[key].apply(undefined, args));
112 | } catch (e) {
113 | rej(e);
114 | }
115 | })
116 | };
117 | }
118 | }
119 | );
120 |
121 | bridge.__proxy__ = proxy;
122 | return proxy;
123 | }
124 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | const fs = require("fs/promises");
2 | const util = require("util");
3 | const execFile = util.promisify(require("child_process").execFile);
4 | const path = require("path");
5 | const { lookpath } = require("lookpath");
6 |
7 | module.exports = function (source) {
8 | const cb = this.async();
9 | var gb;
10 | lookpath("go").then((v) => {
11 | gb=v;
12 | }).catch((e)=> {
13 | return cb(e);
14 | });
15 |
16 | if (!process.env.GOROOT) {
17 | return cb(new Error("Could not find GOROOT in environment.\n" +
18 | "Please try adding this to your script:\n" +
19 | "GOROOT=`go env GOROOT` npm run ..."));
20 | }
21 |
22 | const parent = path.dirname(this.resourcePath);
23 | const outFile = this.resourcePath.slice(0, -2) + "wasm";
24 | let modDir = parent;
25 |
26 | const opts = {
27 | cwd: parent,
28 | env: {
29 | GOPATH: process.env.GOPATH || path.join(process.env.HOME, "go"),
30 | GOROOT: process.env.GOROOT,
31 | GOCACHE: path.join(__dirname, ".gocache"),
32 | GOOS: "js",
33 | GOARCH: "wasm",
34 | },
35 | };
36 |
37 | (async () => {
38 | let found = false;
39 | const root = path.resolve(path.sep);
40 | while (path.resolve(modDir) != root) {
41 | found = await fs.access(path.join(modDir, 'go.mod')).then(() => true).catch(() => false);
42 | if (found) {
43 | break;
44 | }
45 | modDir = path.join(modDir, "..");
46 | }
47 | if (!found) {
48 | return cb(new Error("Could not find go.mod in any parent directory of " + this.resourcePath));
49 | }
50 |
51 | // Having context dependency before compilation means if any file apart from the imported one fails in
52 | // compilation, the updates are still watched.
53 | this.addContextDependency(modDir);
54 |
55 | const wasmOrigPath = path.join(process.env.GOROOT, "misc", "wasm", "wasm_exec.js");
56 | const wasmSavePath = path.join(__dirname, 'wasm_exec.js');
57 | const errorPaths = ["\t" + wasmOrigPath, "\t" + wasmSavePath];
58 | if (!(await fs.access(wasmOrigPath).then(() => true).catch(() => false)) &&
59 | !(await fs.access(wasmSavePath).then(() => true).catch(() => false))) {
60 | return cb(new Error("Could not find wasm_exec.js file. Invalid GOROOT? Searched paths:\n" +
61 | errorPaths.join(",\n") + "\n"));
62 | }
63 |
64 |
65 | const result = await execFile(gb, ["build", "-o", outFile, parent], opts)
66 | .then(() => true)
67 | .catch(e => e);
68 | if (result instanceof Error) {
69 | return cb(result);
70 | }
71 |
72 | found = await fs.access(wasmSavePath).then(() => true).catch(() => false);
73 | if (!found) fs.copyFile(wasmOrigPath, wasmSavePath);
74 |
75 | const contents = await fs.readFile(outFile);
76 | fs.unlink(outFile);
77 |
78 | const emitPath = path.basename(outFile);
79 | this.emitFile(emitPath, contents);
80 |
81 | cb(null,
82 | `require('!${wasmSavePath}');
83 | import goWasm from '${path.join(__dirname, 'bridge.js')}';
84 |
85 | const wasm = fetch('${emitPath}').then(response => response.arrayBuffer());
86 | export default goWasm(wasm);`);
87 | })();
88 | }
89 |
--------------------------------------------------------------------------------
/wasm/error.go:
--------------------------------------------------------------------------------
1 | package wasm
2 |
3 | import "syscall/js"
4 |
5 | // NewError returns a JS Error with the provided Go error's error message.
6 | func NewError(goErr error) js.Value {
7 | errConstructor, err := Global().Expect(js.TypeFunction, "Error")
8 | if err != nil {
9 | panic("Error constructor not found")
10 | }
11 |
12 | return errConstructor.New(goErr.Error())
13 | }
14 |
--------------------------------------------------------------------------------
/wasm/function.go:
--------------------------------------------------------------------------------
1 | package wasm
2 |
3 | import (
4 | "errors"
5 | "reflect"
6 | "syscall/js"
7 | )
8 |
9 | // ErrInvalidArgumentType is returned when a generated Go function wrapper receives invalid argument types from JS.
10 | var ErrInvalidArgumentType = errors.New("invalid argument passed into Go function")
11 |
12 | var errorType = reflect.TypeOf((*error)(nil)).Elem()
13 |
14 | type goThrowable struct {
15 | Result js.Value `wasm:"result"`
16 | Error js.Value `wasm:"error"`
17 | }
18 |
19 | // toJSFunc takes a reflect.Value of a Go function and converts it to a JS function that:
20 | // Errors if the parameter types do not conform to the Go function signature,
21 | // Throws an error if the last returned value is an error and is non-nil,
22 | // Return an array if there's multiple non-error return values.
23 | func toJSFunc(x reflect.Value) js.Value {
24 | funcType := x.Type()
25 | var hasError bool
26 | if funcType.NumOut() != 0 {
27 | hasError = funcType.Out(funcType.NumOut()-1) == errorType
28 | }
29 |
30 | return funcWrapper.Invoke(js.FuncOf(func(this js.Value, args []js.Value) interface{} {
31 | in, err := conformJSValueToType(funcType, this, args)
32 | if err != nil {
33 | return ToJSValue(goThrowable{
34 | Error: NewError(err),
35 | })
36 | }
37 |
38 | out := x.Call(in)
39 |
40 | if !hasError {
41 | return ToJSValue(goThrowable{
42 | Result: returnValue(out),
43 | })
44 | }
45 |
46 | lastParam := out[len(out)-1]
47 | if !lastParam.IsNil() {
48 | return ToJSValue(goThrowable{
49 | Error: NewError(lastParam.Interface().(error)),
50 | })
51 | }
52 | return ToJSValue(goThrowable{
53 | Result: returnValue(out[:len(out)-1]),
54 | })
55 | }))
56 | }
57 |
58 | var jsValueType = reflect.TypeOf(js.Value{})
59 |
60 | // conformJSValueToType attempts to convert the provided JS values to reflect.Values that match the
61 | // types expected for the parameters of funcType.
62 | func conformJSValueToType(funcType reflect.Type, this js.Value, values []js.Value) ([]reflect.Value, error) {
63 | if funcType.NumIn() == 0 {
64 | if len(values) != 0 {
65 | return nil, ErrInvalidArgumentType
66 | }
67 | return []reflect.Value{}, nil
68 | }
69 |
70 | if funcType.In(0) == jsValueType {
71 | // If the first parameter is a js.Value, it is assumed to be the value of `this`.
72 | values = append([]js.Value{this}, values...)
73 | }
74 |
75 | if funcType.IsVariadic() && funcType.NumIn()-1 > len(values) {
76 | return nil, ErrInvalidArgumentType
77 | }
78 |
79 | if !funcType.IsVariadic() && funcType.NumIn() != len(values) {
80 | return nil, ErrInvalidArgumentType
81 | }
82 |
83 | in := make([]reflect.Value, 0, len(values))
84 | for i, v := range values {
85 | paramType := funcType.In(i)
86 | ptrX := reflect.New(paramType).Interface()
87 | err := FromJSValue(v, ptrX)
88 | if err != nil {
89 | return nil, err
90 | }
91 |
92 | in = append(in, reflect.ValueOf(ptrX).Elem())
93 | }
94 |
95 | return in, nil
96 | }
97 |
98 | // returnValue wraps returned values by Go in a JS-friendly way.
99 | // If there are no returned values, it returns undefined.
100 | // If there is exactly one, it returns the JS equivalent.
101 | // If there is more than one, it returns an array containing the JS equivalent of every returned value.
102 | func returnValue(x []reflect.Value) js.Value {
103 | switch len(x) {
104 | case 0:
105 | return js.Undefined()
106 | case 1:
107 | return ToJSValue(x[0].Interface())
108 | }
109 |
110 | xInterface := make([]interface{}, 0, len(x))
111 | for _, v := range x {
112 | xInterface = append(xInterface, v.Interface())
113 | }
114 |
115 | return ToJSValue(xInterface)
116 | }
117 |
--------------------------------------------------------------------------------
/wasm/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/teamortix/golang-wasm/wasm
2 |
3 | go 1.16
4 |
--------------------------------------------------------------------------------
/wasm/object.go:
--------------------------------------------------------------------------------
1 | package wasm
2 |
3 | import (
4 | "fmt"
5 | "syscall/js"
6 | )
7 |
8 | // TypeMismatchError is returned when a function is called with a js.Value that has the incorrect type.
9 | type TypeMismatchError struct {
10 | Expected js.Type
11 | Actual js.Type
12 | }
13 |
14 | func (e TypeMismatchError) Error() string {
15 | return fmt.Sprintf("expected %v type, got %v type instead", e.Expected, e.Actual)
16 | }
17 |
18 | // Global returns the global object as a Object.
19 | // If the global object is not an object, it panics.
20 | func Global() Object {
21 | global, err := NewObject(js.Global())
22 | if err != nil {
23 | panic(err)
24 | }
25 | return global
26 | }
27 |
28 | // Object is a statically typed Object instance of js.Value.
29 | // It should be instantiated with NewObject where it is checked for type instead of directly.
30 | // Calling methods on a zero Object is undefined behaviour.
31 | type Object struct {
32 | value js.Value
33 | }
34 |
35 | // NewObject instantiates a new Object with the provided js.Value.
36 | // If the js.Value is not an Object, it returns a TypeMismatchError.
37 | func NewObject(raw js.Value) (Object, error) {
38 | if raw.Type() != js.TypeObject {
39 | return Object{}, TypeMismatchError{
40 | Expected: js.TypeObject,
41 | Actual: raw.Type(),
42 | }
43 | }
44 |
45 | return Object{raw}, nil
46 | }
47 |
48 | // Get recursively gets the Object's properties, returning a TypeMismatchError if it encounters a non-object while
49 | // descending through the object.
50 | func (o Object) Get(path ...string) (js.Value, error) {
51 | current := o.value
52 | for _, v := range path {
53 | if current.Type() != js.TypeObject {
54 | return js.Value{}, TypeMismatchError{
55 | Expected: js.TypeObject,
56 | Actual: current.Type(),
57 | }
58 | }
59 |
60 | current = current.Get(v)
61 | }
62 | return current, nil
63 | }
64 |
65 | // Expect is a helper function that calls Get and checks the type of the final result.
66 | // It returns a TypeMismatchError if a non-object is encountered while descending the path or the final type does not
67 | // match with the provided expected type.
68 | func (o Object) Expect(expectedType js.Type, path ...string) (js.Value, error) {
69 | value, err := o.Get(path...)
70 | if err != nil {
71 | return js.Value{}, err
72 | }
73 |
74 | if value.Type() != expectedType {
75 | return js.Value{}, TypeMismatchError{
76 | Expected: expectedType,
77 | Actual: value.Type(),
78 | }
79 | }
80 |
81 | return value, nil
82 | }
83 |
84 | // Delete removes property p from the object.
85 | func (o Object) Delete(p string) {
86 | o.value.Delete(p)
87 | }
88 |
89 | // Equal checks if the object is equal to another value.
90 | // It is equivalent to JS's === operator.
91 | func (o Object) Equal(v js.Value) bool {
92 | return o.value.Equal(v)
93 | }
94 |
95 | // Index indexes into the object.
96 | func (o Object) Index(i int) js.Value {
97 | return o.value.Index(i)
98 | }
99 |
100 | // InstanceOf implements the instanceof operator in JavaScript.
101 | // If t is not a constructor, this function returns false.
102 | func (o Object) InstanceOf(t js.Value) bool {
103 | if t.Type() != js.TypeFunction {
104 | return false
105 | }
106 | return o.value.InstanceOf(t)
107 | }
108 |
109 | // JSValue implements the js.Wrapper interface.
110 | func (o Object) JSValue() js.Value {
111 | return o.value
112 | }
113 |
114 | // Length returns the "length" property of the object.
115 | func (o Object) Length() int {
116 | return o.value.Length()
117 | }
118 |
119 | // Set sets the property p to the value of ToJSValue(x).
120 | func (o Object) Set(p string, x interface{}) {
121 | o.value.Set(p, ToJSValue(x))
122 | }
123 |
124 | // SetIndex sets the index i to the value of ToJSValue(x).
125 | func (o Object) SetIndex(i int, x interface{}) {
126 | o.value.SetIndex(i, ToJSValue(x))
127 | }
128 |
129 | // String returns the object marshalled as a JSON string for debugging purposes.
130 | func (o Object) String() string {
131 | stringify, err := Global().Expect(js.TypeFunction, "JSON", "stringify")
132 | if err != nil {
133 | panic(err)
134 | }
135 |
136 | jsonStr := stringify.Invoke(o)
137 | if jsonStr.Type() != js.TypeString {
138 | panic("JSON.stringify returned a " + jsonStr.Type().String())
139 | }
140 |
141 | return jsonStr.String()
142 | }
143 |
--------------------------------------------------------------------------------
/wasm/promise.go:
--------------------------------------------------------------------------------
1 | package wasm
2 |
3 | import (
4 | "errors"
5 | "syscall/js"
6 | )
7 |
8 | // Promise is an instance of a JS promise.
9 | // The zero value of this struct is not a valid Promise.
10 | type Promise struct {
11 | Object
12 | }
13 |
14 | // FromJSValue turns a JS value to a Promise.
15 | func (p *Promise) FromJSValue(value js.Value) error {
16 | var err error
17 | p.Object, err = NewObject(value)
18 | return err
19 | }
20 |
21 | // NewPromise returns a promise that is fulfilled or rejected when the provided handler returns.
22 | // The handler is spawned in its own goroutine.
23 | func NewPromise(handler func() (interface{}, error)) Promise {
24 | resultChan := make(chan interface{})
25 | errChan := make(chan error)
26 |
27 | // Invoke the handler in a new goroutine.
28 | go func() {
29 | result, err := handler()
30 | if err != nil {
31 | errChan <- err
32 | return
33 | }
34 | resultChan <- result
35 | }()
36 |
37 | // Create a JS promise handler.
38 | var jsHandler js.Func
39 | jsHandler = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
40 | if len(args) < 2 {
41 | panic("not enough arguments are passed to the Promise constructor handler")
42 | }
43 |
44 | resolve := args[0]
45 | reject := args[1]
46 |
47 | if resolve.Type() != js.TypeFunction || reject.Type() != js.TypeFunction {
48 | panic("invalid type passed to Promise constructor handler")
49 | }
50 |
51 | go func() {
52 | select {
53 | case r := <-resultChan:
54 | resolve.Invoke(ToJSValue(r))
55 | case err := <-errChan:
56 | reject.Invoke(NewError(err))
57 | }
58 |
59 | // Free up resources now that we are done.
60 | jsHandler.Release()
61 | }()
62 |
63 | return nil
64 | })
65 |
66 | promise, err := Global().Expect(js.TypeFunction, "Promise")
67 | if err != nil {
68 | panic("Promise constructor not found")
69 | }
70 |
71 | return mustJSValueToPromise(promise.New(jsHandler))
72 | }
73 |
74 | // Await waits for the Promise. It unmarshals the resolved value to v. An error
75 | // will be returned if unmarshalling is unsuccessful or the Promise rejects.
76 | // It is implemented by calling then and catch on JS.
77 | func (p Promise) Await(v interface{}) error {
78 | err := make(chan error)
79 | p.value.Call("then", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
80 | if len(args) > 0 && v != nil {
81 | err <- FromJSValue(args[0], v)
82 | return nil
83 | }
84 | err <- nil
85 | return nil
86 | }))
87 | p.value.Call("catch", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
88 | err <- errors.New(args[0].Call("toString").String())
89 | return nil
90 | }))
91 | return <-err
92 | }
93 |
94 | // PromiseAll creates a promise that is fulfilled when all the provided promises have been fulfilled.
95 | // The promise is rejected when any of the promises provided rejects.
96 | // It is implemented by calling Promise.all on JS.
97 | func PromiseAll(promise ...Promise) Promise {
98 | promiseAll, err := Global().Expect(js.TypeFunction, "Promise", "all")
99 | if err != nil {
100 | panic("Promise.all not found")
101 | }
102 |
103 | pInterface := make([]interface{}, 0, len(promise))
104 | for _, v := range promise {
105 | pInterface = append(pInterface, v)
106 | }
107 |
108 | return mustJSValueToPromise(promiseAll.Invoke(pInterface))
109 | }
110 |
111 | // PromiseAllSettled creates a promise that is fulfilled when all the provided promises have been fulfilled or rejected.
112 | // It is implemented by calling Promise.allSettled on JS.
113 | func PromiseAllSettled(promise ...Promise) Promise {
114 | promiseAllSettled, err := Global().Expect(js.TypeFunction, "Promise", "allSettled")
115 | if err != nil {
116 | panic("Promise.allSettled not found")
117 | }
118 |
119 | pInterface := make([]interface{}, 0, len(promise))
120 | for _, v := range promise {
121 | pInterface = append(pInterface, v)
122 | }
123 |
124 | return mustJSValueToPromise(promiseAllSettled.Invoke(pInterface))
125 | }
126 |
127 | // PromiseAny creates a promise that is fulfilled when any of the provided promises have been fulfilled.
128 | // The promise is rejected when all of the provided promises gets rejected.
129 | // It is implemented by calling Promise.any on JS.
130 | func PromiseAny(promise ...Promise) Promise {
131 | promiseAny, err := Global().Expect(js.TypeFunction, "Promise", "any")
132 | if err != nil {
133 | panic("Promise.any not found")
134 | }
135 |
136 | pInterface := make([]interface{}, 0, len(promise))
137 | for _, v := range promise {
138 | pInterface = append(pInterface, v)
139 | }
140 |
141 | return mustJSValueToPromise(promiseAny.Invoke(pInterface))
142 | }
143 |
144 | // PromiseRace creates a promise that is fulfilled or rejected when one of the provided promises fulfill or reject.
145 | // It is implemented by calling Promise.race on JS.
146 | func PromiseRace(promise ...Promise) Promise {
147 | promiseRace, err := Global().Expect(js.TypeFunction, "Promise", "race")
148 | if err != nil {
149 | panic("Promise.race not found")
150 | }
151 |
152 | pInterface := make([]interface{}, 0, len(promise))
153 | for _, v := range promise {
154 | pInterface = append(pInterface, v)
155 | }
156 |
157 | return mustJSValueToPromise(promiseRace.Invoke(pInterface))
158 | }
159 |
160 | func mustJSValueToPromise(v js.Value) Promise {
161 | var p Promise
162 | err := p.FromJSValue(v)
163 | if err != nil {
164 | panic("Expected a Promise from JS standard library")
165 | }
166 |
167 | return p
168 | }
169 |
--------------------------------------------------------------------------------
/wasm/reflect_from.go:
--------------------------------------------------------------------------------
1 | package wasm
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "reflect"
7 | "syscall/js"
8 | "time"
9 | )
10 |
11 | // ErrMultipleReturnValue is an error where a JS function is attempted to be unmarshalled into a Go function with
12 | // multiple return values.
13 | var ErrMultipleReturnValue = errors.New("a JS function can only return one value")
14 |
15 | // InvalidFromJSValueError is an error where an invalid argument is passed to FromJSValue.
16 | // The argument to Unmarshal must be a non-nil pointer.
17 | type InvalidFromJSValueError struct {
18 | Type reflect.Type
19 | }
20 |
21 | // Error implements error.
22 | func (e InvalidFromJSValueError) Error() string {
23 | return "invalid argument passed to FromJSValue. Got type " + e.Type.String()
24 | }
25 |
26 | // InvalidTypeError is an error where the JS value cannot be unmarshalled into the provided Go type.
27 | type InvalidTypeError struct {
28 | JSType js.Type
29 | GoType reflect.Type
30 | }
31 |
32 | // Error implements error.
33 | func (e InvalidTypeError) Error() string {
34 | return "invalid unmarshalling: cannot unmarshal " + e.JSType.String() + " into " + e.GoType.String()
35 | }
36 |
37 | // InvalidArrayError is an error where the JS's array length do not match Go's array length.
38 | type InvalidArrayError struct {
39 | Expected int
40 | Actual int
41 | }
42 |
43 | // Error implements error.
44 | func (e InvalidArrayError) Error() string {
45 | return fmt.Sprintf(
46 | "invalid unmarshalling: expected array of length %d to match Go array but got JS array of length %d",
47 | e.Expected, e.Actual,
48 | )
49 | }
50 |
51 | // Decoder is an interface which manually decodes js.Value on its own.
52 | // It overrides in FromJSValue.
53 | type Decoder interface {
54 | FromJSValue(js.Value) error
55 | }
56 |
57 | // FromJSValue converts a given js.Value to the Go equivalent.
58 | // The new value of 'out' is undefined if FromJSValue returns an error.
59 | //
60 | // When a JS function is unmarshalled into a Go function with only one return value, the returned JS value is casted
61 | // into the type of the return value. If the conversion fails, the function call panics.
62 | //
63 | // When a JS function is unmarshalled into a Go function with two return values, the second one being error, the
64 | // conversion error is returned instead.
65 | func FromJSValue(x js.Value, out interface{}) error {
66 | v := reflect.ValueOf(out)
67 | if v.Kind() != reflect.Ptr || v.IsNil() {
68 | return &InvalidFromJSValueError{reflect.TypeOf(v)}
69 | }
70 |
71 | return decodeValue(x, v.Elem())
72 | }
73 |
74 | // decodeValue decodes the provided js.Value into the provided reflect.Value.
75 | func decodeValue(x js.Value, v reflect.Value) error {
76 | // If we have undefined or null, we need to be able to set to the pointer itself.
77 | // All code beyond this point are pointer-unaware so we handle undefined or null first.
78 | switch x.Type() {
79 | case js.TypeUndefined:
80 | // Keep the existing value if it is undefined.
81 | return nil
82 | case js.TypeNull:
83 | return decodeNothing(v)
84 | }
85 |
86 | // Implementations of Decoder are probably on pointer so do it before pointer code.
87 | if d, ok := v.Addr().Interface().(Decoder); ok {
88 | return d.FromJSValue(x)
89 | }
90 |
91 | // Make sure everything is initialized and indirect it.
92 | // This prevents other decode functions from having to handle pointers.
93 | if v.Kind() == reflect.Ptr {
94 | initializePointerIfNil(v)
95 | v = reflect.Indirect(v)
96 | }
97 |
98 | if v.Kind() == reflect.Interface && v.NumMethod() == 0 {
99 | // It's a interface{} so we just create the easiest Go representation we can in createInterface.
100 | res := createInterface(x)
101 | if res != nil {
102 | v.Set(reflect.ValueOf(res))
103 | }
104 | return nil
105 | }
106 |
107 | // Directly set v if it's a js.Value.
108 | if _, ok := v.Interface().(js.Value); ok {
109 | v.Set(reflect.ValueOf(x))
110 | return nil
111 | }
112 |
113 | // Go the reflection route.
114 | switch x.Type() {
115 | case js.TypeBoolean:
116 | return decodeBoolean(x, v)
117 | case js.TypeNumber:
118 | return decodeNumber(x, v)
119 | case js.TypeString:
120 | return decodeString(x, v)
121 | case js.TypeSymbol:
122 | return decodeSymbol(x, v)
123 | case js.TypeObject:
124 | if isArray(x) {
125 | return decodeArray(x, v)
126 | }
127 | if isDate(x) {
128 | return decodeDate(x, v)
129 | }
130 | return decodeObject(x, v)
131 | case js.TypeFunction:
132 | return decodeFunction(x, v)
133 | default:
134 | panic("unknown JS type: " + x.Type().String())
135 | }
136 | }
137 |
138 | // decodeNothing decodes an undefined or a null into the provided reflect.Value.
139 | func decodeNothing(v reflect.Value) error {
140 | if v.Kind() != reflect.Ptr && v.Kind() != reflect.Interface {
141 | return InvalidTypeError{js.TypeNull, v.Type()}
142 | }
143 | v.Set(reflect.Zero(v.Type()))
144 | return nil
145 | }
146 |
147 | // decodeBoolean decodes a bool into the provided reflect.Value.
148 | func decodeBoolean(x js.Value, v reflect.Value) error {
149 | if v.Kind() != reflect.Bool {
150 | return InvalidTypeError{js.TypeBoolean, v.Type()}
151 | }
152 | v.SetBool(x.Bool())
153 | return nil
154 | }
155 |
156 | // decodeNumber decodes a JS number into the provided reflect.Value, truncating as necessary.
157 | func decodeNumber(x js.Value, v reflect.Value) error {
158 | switch v.Kind() {
159 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
160 | v.SetInt(int64(x.Float()))
161 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
162 | v.SetUint(uint64(x.Float()))
163 | case reflect.Float32, reflect.Float64:
164 | v.SetFloat(x.Float())
165 | default:
166 | return InvalidTypeError{js.TypeNumber, v.Type()}
167 | }
168 | return nil
169 | }
170 |
171 | // decodeString decodes a JS string into the provided reflect.Value.
172 | func decodeString(x js.Value, v reflect.Value) error {
173 | if v.Kind() != reflect.String {
174 | return InvalidTypeError{js.TypeString, v.Type()}
175 | }
176 | v.SetString(x.String())
177 | return nil
178 | }
179 |
180 | // decodeSymbol decodes a JS symbol into the provided reflect.Value.
181 | func decodeSymbol(x js.Value, v reflect.Value) error {
182 | // TODO Decode it into a symbol type.
183 | return InvalidTypeError{js.TypeSymbol, v.Type()}
184 | }
185 |
186 | // decodeArray decodes a JS array into the provided reflect.Value.
187 | func decodeArray(x js.Value, v reflect.Value) error {
188 | jsLen := x.Length()
189 |
190 | switch v.Kind() {
191 | case reflect.Array:
192 | if jsLen != v.Len() {
193 | return InvalidArrayError{v.Len(), jsLen}
194 | }
195 | case reflect.Slice:
196 | newSlice := reflect.MakeSlice(v.Type(), jsLen, jsLen)
197 | v.Set(newSlice)
198 | default:
199 | return InvalidTypeError{js.TypeObject, v.Type()}
200 | }
201 |
202 | for i := 0; i < jsLen; i++ {
203 | err := FromJSValue(x.Index(i), v.Index(i).Addr().Interface())
204 | if err != nil {
205 | return err
206 | }
207 | }
208 | return nil
209 | }
210 |
211 | // decodeDate decodes a JS date into the provided reflect.Value.
212 | func decodeDate(x js.Value, v reflect.Value) error {
213 | t, ok := v.Addr().Interface().(*time.Time)
214 | if !ok {
215 | return InvalidTypeError{js.TypeObject, v.Type()}
216 | }
217 | millis := x.Call("getTime").Int()
218 | *t = time.UnixMilli(int64(millis))
219 | return nil
220 | }
221 |
222 | // decodeObject decodes a JS object into the provided reflect.Value.
223 | func decodeObject(x js.Value, v reflect.Value) error {
224 | switch v.Kind() {
225 | case reflect.Struct:
226 | return decodeObjectIntoStruct(x, v)
227 | case reflect.Map:
228 | return decodeObjectIntoMap(x, v)
229 | case reflect.Complex64, reflect.Complex128:
230 | return decodeObjectIntoComplex(x, v)
231 | default:
232 | return InvalidTypeError{js.TypeObject, v.Type()}
233 | }
234 | }
235 |
236 | // decodeObject decodes a JS object into the provided reflect.Value struct.
237 | func decodeObjectIntoStruct(x js.Value, v reflect.Value) error {
238 | for i := 0; i < v.Type().NumField(); i++ {
239 | fieldType := v.Type().Field(i)
240 | if fieldType.PkgPath != "" {
241 | continue
242 | }
243 |
244 | name := fieldType.Name
245 | tagName, tagOK := fieldType.Tag.Lookup("wasm")
246 |
247 | if tagOK {
248 | if tagName == "-" {
249 | continue
250 | }
251 | name = tagName
252 | }
253 |
254 | err := decodeValue(x.Get(name), v.Field(i))
255 | if err != nil {
256 | if tagOK {
257 | return fmt.Errorf("in field %s (JS %s): %w", fieldType.Name, tagName, err)
258 | }
259 | return fmt.Errorf("in field %s: %w", fieldType.Name, err)
260 | }
261 | }
262 |
263 | return nil
264 | }
265 |
266 | func decodeObjectIntoMap(x js.Value, v reflect.Value) error {
267 | mapType := v.Type()
268 | keyType := mapType.Key()
269 | valType := mapType.Elem()
270 |
271 | switch keyType.Kind() {
272 | case reflect.String:
273 | case reflect.Interface:
274 | if keyType.NumMethod() != 0 {
275 | return InvalidTypeError{js.TypeObject, mapType}
276 | }
277 | default:
278 | return InvalidTypeError{js.TypeObject, mapType}
279 | }
280 |
281 | // TODO: Use Object API
282 | obj, err := Global().Get("Object")
283 | if err != nil {
284 | panic("Object not found")
285 | }
286 |
287 | var keys []string
288 | err = FromJSValue(obj.Call("keys", x), &keys)
289 | if err != nil {
290 | panic("Object.keys returned non-string-array.")
291 | }
292 |
293 | v.Set(reflect.MakeMapWithSize(mapType, len(keys)))
294 |
295 | for _, k := range keys {
296 | valuePtr := reflect.New(valType).Interface()
297 | err := FromJSValue(x.Get(k), valuePtr)
298 | if err != nil {
299 | return err
300 | }
301 |
302 | v.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(valuePtr).Elem())
303 | }
304 | return nil
305 | }
306 |
307 | // decodeObjectIntoComplex decodes the provided object into a complex number.
308 | func decodeObjectIntoComplex(x js.Value, v reflect.Value) error {
309 | var r, i float64
310 | err := FromJSValue(x.Get("real"), &r)
311 | if err != nil {
312 | return err
313 | }
314 | err = FromJSValue(x.Get("imag"), &i)
315 | if err != nil {
316 | return err
317 | }
318 |
319 | v.SetComplex(complex(r, i))
320 | return nil
321 | }
322 |
323 | // decodeFunction decodes a JS function into the provided reflect.Value.
324 | func decodeFunction(x js.Value, v reflect.Value) error {
325 | funcType := v.Type()
326 | outCount := funcType.NumOut()
327 |
328 | switch outCount {
329 | case 0, 1:
330 | case 2:
331 | if funcType.Out(1) != errorType {
332 | return ErrMultipleReturnValue
333 | }
334 | default:
335 | return ErrMultipleReturnValue
336 | }
337 |
338 | v.Set(reflect.MakeFunc(funcType, func(args []reflect.Value) []reflect.Value {
339 | argsJS := make([]interface{}, 0, len(args))
340 | for _, v := range args {
341 | argsJS = append(argsJS, ToJSValue(v.Interface()))
342 | }
343 |
344 | jsReturn := x.Invoke(argsJS...)
345 | if outCount == 0 {
346 | return []reflect.Value{}
347 | }
348 |
349 | returnPtr := reflect.New(funcType.Out(0)).Interface()
350 | err := FromJSValue(jsReturn, returnPtr)
351 |
352 | returnVal := reflect.ValueOf(returnPtr).Elem()
353 | if err != nil {
354 | if outCount == 1 {
355 | panic("error decoding JS return value: " + err.Error())
356 | }
357 |
358 | return []reflect.Value{returnVal, reflect.ValueOf(err)}
359 | }
360 |
361 | switch outCount {
362 | case 1:
363 | return []reflect.Value{returnVal}
364 | case 2:
365 | return []reflect.Value{returnVal, reflect.Zero(v.Type())}
366 | default:
367 | panic("unexpected amount of return values")
368 | }
369 | }))
370 | return nil
371 | }
372 |
373 | // createInterface creates a representation of the provided js.Value.
374 | func createInterface(x js.Value) interface{} {
375 | switch x.Type() {
376 | case js.TypeUndefined, js.TypeNull:
377 | return nil
378 | case js.TypeBoolean:
379 | return x.Bool()
380 | case js.TypeNumber:
381 | return x.Float()
382 | case js.TypeString:
383 | return x.String()
384 | case js.TypeSymbol:
385 | // We can't convert it to a Go value in a meaningful way.
386 | return x
387 | case js.TypeObject:
388 | if isArray(x) {
389 | return createArray(x)
390 | }
391 | return createObject(x)
392 | case js.TypeFunction:
393 | var a func(...interface{}) (interface{}, error)
394 | err := FromJSValue(x, &a)
395 | if err != nil {
396 | panic("error creating function: " + err.Error())
397 | }
398 | return a
399 | default:
400 | panic("unknown JS type: " + x.Type().String())
401 | }
402 | }
403 |
404 | // createArray creates a slice of interface representing the js.Value.
405 | func createArray(x js.Value) interface{} {
406 | result := make([]interface{}, x.Length())
407 | for i := range result {
408 | result[i] = createInterface(x.Index(i))
409 | }
410 | return result
411 | }
412 |
413 | // createObject creates a representation of the provided JS object.
414 | func createObject(x js.Value) interface{} {
415 | // TODO: Use Object API
416 | obj, err := Global().Get("Object")
417 | if err != nil {
418 | panic("Object not found")
419 | }
420 |
421 | var keys []string
422 | err = FromJSValue(obj.Call("keys", x), &keys)
423 | if err != nil {
424 | panic("Object.keys returned non-string-array.")
425 | }
426 |
427 | result := make(map[string]interface{}, len(keys))
428 | for _, v := range keys {
429 | result[v] = createInterface(x.Get(v))
430 | }
431 | return result
432 | }
433 |
434 | // isArray calls the JS function Array.isArray to check if the provided js.Value is an array.
435 | func isArray(x js.Value) bool {
436 | arr, err := Global().Get("Array")
437 | if err != nil {
438 | panic("Array not found")
439 | }
440 |
441 | return arr.Call("isArray", x).Bool()
442 | }
443 |
444 | // isDate uses x instanceof Date to check if the provided js.Value is a Date.
445 | func isDate(x js.Value) bool {
446 | date, err := Global().Get("Date")
447 | if err != nil {
448 | panic("Date not found")
449 | }
450 |
451 | return x.InstanceOf(date)
452 | }
453 |
454 | // initializePointerIfNil checks if the pointer is nil and initializes it as necessary.
455 | func initializePointerIfNil(v reflect.Value) {
456 | if v.Kind() != reflect.Ptr {
457 | return
458 | }
459 | if v.IsNil() {
460 | v.Set(reflect.New(v.Type().Elem()))
461 | }
462 | initializePointerIfNil(v.Elem())
463 | }
464 |
--------------------------------------------------------------------------------
/wasm/reflect_to.go:
--------------------------------------------------------------------------------
1 | package wasm
2 |
3 | import (
4 | "fmt"
5 | "reflect"
6 | "syscall/js"
7 | "time"
8 | "unsafe"
9 | )
10 |
11 | // Wrapper is an interface which manually encodes to js.Value.
12 | // It overrides in ToJSValue.
13 | type Wrapper interface {
14 | JSValue() js.Value
15 | }
16 |
17 | // ToJSValue converts a given Go value into its equivalent JS form.
18 | //
19 | // One special case is that complex numbers (complex64 and complex128) are converted into objects with a real and imag
20 | // property holding a number each.
21 | //
22 | // A function is converted into a JS function where the function returns an error if the provided arguments do not conform
23 | // to the Go equivalent but otherwise calls the Go function.
24 | //
25 | // The "this" argument of a function is always passed to the Go function if its first parameter is of type js.Value.
26 | // Otherwise, it is simply ignored.
27 | //
28 | // If the last return value of a function is an error, it will be thrown in JS if it's non-nil.
29 | // If the function returns multiple non-error values, it is converted to an array when returning to JS.
30 | //
31 | // It panics when a channel or a map with keys other than string and integers are passed in.
32 | func ToJSValue(x interface{}) js.Value {
33 | if x == nil {
34 | return js.Null()
35 | }
36 |
37 | // Fast path for basic types that do not require reflection.
38 | switch x := x.(type) {
39 | case Wrapper:
40 | return x.JSValue()
41 | case js.Value:
42 | return x
43 | case bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr,
44 | unsafe.Pointer, float32, float64, string:
45 | return js.ValueOf(x)
46 | case complex64:
47 | return js.ValueOf(map[string]interface{}{
48 | "real": real(x),
49 | "imag": imag(x),
50 | })
51 | case complex128:
52 | return js.ValueOf(map[string]interface{}{
53 | "real": real(x),
54 | "imag": imag(x),
55 | })
56 | case time.Time:
57 | date, err := Global().Get("Date")
58 | if err != nil {
59 | panic("Date constructor not found")
60 | }
61 | return date.New(x.Format(time.RFC3339))
62 | }
63 |
64 | value := reflect.ValueOf(x)
65 |
66 | if value.Kind() == reflect.Ptr {
67 | value = reflect.Indirect(value)
68 | if !value.IsValid() {
69 | return js.Undefined()
70 | }
71 | }
72 |
73 | switch k := value.Kind(); k {
74 | case reflect.Bool:
75 | return js.ValueOf(value.Bool())
76 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
77 | return js.ValueOf(value.Int())
78 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
79 | return js.ValueOf(value.Uint())
80 | case reflect.Uintptr:
81 | return js.ValueOf(value.Pointer())
82 | case reflect.Float32, reflect.Float64:
83 | return js.ValueOf(value.Float())
84 | case reflect.String:
85 | return js.ValueOf(value.String())
86 | case reflect.Array, reflect.Slice:
87 | return toJSArray(value)
88 | case reflect.Func:
89 | return toJSFunc(value)
90 | case reflect.Map:
91 | return mapToJSObject(value)
92 | case reflect.Struct:
93 | return structToJSObject(value)
94 | default:
95 | panic(fmt.Sprintf("cannot convert %T to a JS value (kind %s)", x, k))
96 | }
97 | }
98 |
99 | // toJSArray converts the provided array or slice to a JS array.
100 | func toJSArray(x reflect.Value) js.Value {
101 | arrayConstructor, err := Global().Get("Array")
102 | if err != nil {
103 | panic("Array constructor not found")
104 | }
105 |
106 | array := arrayConstructor.New()
107 | for i := 0; i < x.Len(); i++ {
108 | array.SetIndex(i, ToJSValue(x.Index(i).Interface()))
109 | }
110 |
111 | return array
112 | }
113 |
114 | // mapToJSObject converts the provided map to a JS object.
115 | func mapToJSObject(x reflect.Value) js.Value {
116 | objectConstructor, err := Global().Get("Object")
117 | if err != nil {
118 | panic("Object constructor not found")
119 | }
120 |
121 | obj := objectConstructor.New()
122 | iter := x.MapRange()
123 | for iter.Next() {
124 | key := iter.Key()
125 | value := iter.Value().Interface()
126 | switch key := key.Interface().(type) {
127 | case int:
128 | obj.SetIndex(key, ToJSValue(value))
129 | case int8:
130 | obj.SetIndex(int(key), ToJSValue(value))
131 | case int16:
132 | obj.SetIndex(int(key), ToJSValue(value))
133 | case int32:
134 | obj.SetIndex(int(key), ToJSValue(value))
135 | case int64:
136 | obj.SetIndex(int(key), ToJSValue(value))
137 | case uint:
138 | obj.SetIndex(int(key), ToJSValue(value))
139 | case uint8:
140 | obj.SetIndex(int(key), ToJSValue(value))
141 | case uint16:
142 | obj.SetIndex(int(key), ToJSValue(value))
143 | case uint32:
144 | obj.SetIndex(int(key), ToJSValue(value))
145 | case uint64:
146 | obj.SetIndex(int(key), ToJSValue(value))
147 | case uintptr:
148 | obj.SetIndex(int(key), ToJSValue(value))
149 | case string:
150 | obj.Set(key, ToJSValue(value))
151 | default:
152 | panic(fmt.Sprintf("cannot convert %T into a JS value as its key is not a string or an integer",
153 | x.Interface()))
154 | }
155 | }
156 |
157 | return obj
158 | }
159 |
160 | // structToJSObject converts a struct to a JS object.
161 | func structToJSObject(x reflect.Value) js.Value {
162 | objectConstructor, err := Global().Get("Object")
163 | if err != nil {
164 | panic("Object constructor not found")
165 | }
166 |
167 | obj := objectConstructor.New()
168 |
169 | structType := x.Type()
170 | for i := 0; i < structType.NumField(); i++ {
171 | field := structType.Field(i)
172 | if field.PkgPath != "" {
173 | continue
174 | }
175 |
176 | name := field.Name
177 | if tagName, ok := field.Tag.Lookup("wasm"); ok {
178 | if tagName == "-" {
179 | continue
180 | }
181 | name = tagName
182 | }
183 |
184 | obj.Set(name, ToJSValue(x.Field(i).Interface()))
185 | }
186 |
187 | for i := 0; i < structType.NumMethod(); i++ {
188 | method := structType.Method(i)
189 | obj.Set(method.Name, toJSFunc(x.Method(i)))
190 | }
191 |
192 | if x.CanAddr() {
193 | structPtr := reflect.PointerTo(structType)
194 | for i := 0; i < structPtr.NumMethod(); i++ {
195 | method := structPtr.Method(i)
196 | obj.Set(method.Name, toJSFunc(x.Addr().Method(i)))
197 | }
198 | }
199 |
200 | return obj
201 | }
202 |
--------------------------------------------------------------------------------
/wasm/wasm.go:
--------------------------------------------------------------------------------
1 | package wasm
2 |
3 | import "syscall/js"
4 |
5 | // Magic values to communicate with the JS library.
6 | const (
7 | globalIdent = "__go_wasm__"
8 | readyHint = "__ready__"
9 | funcWrapperName = "__wrapper__"
10 | )
11 |
12 | var (
13 | bridge Object
14 | funcWrapper js.Value
15 | )
16 |
17 | func init() {
18 | bridgeJS, err := Global().Get(globalIdent)
19 | if err != nil {
20 | panic("JS wrapper " + globalIdent + " not found")
21 | }
22 |
23 | bridge, err = NewObject(bridgeJS)
24 | if err != nil {
25 | panic("JS wrapper " + globalIdent + " is not an object")
26 | }
27 |
28 | funcWrapper, err = bridge.Get(funcWrapperName)
29 | if err != nil {
30 | panic("JS wrapper " + globalIdent + "." + funcWrapperName + " not found")
31 | }
32 | }
33 |
34 | // Ready notifies the JS bridge that the WASM is ready.
35 | // It should be called when every value and function is exposed.
36 | func Ready() {
37 | Expose(readyHint, true)
38 | }
39 |
40 | // Expose exposes a copy of the provided value in JS.
41 | func Expose(property string, x interface{}) {
42 | bridge.Set(property, x)
43 | }
44 |
--------------------------------------------------------------------------------