From 73abe7d63a33ecc37b920d0acaa9e18cc8a1e694 Mon Sep 17 00:00:00 2001 From: Hasan <45375125+hasanaburayyan@users.noreply.github.com> Date: Wed, 12 Jun 2024 12:17:06 -0400 Subject: [PATCH] feat(docs): test doc examples (#6149) Closes: https://github.com/winglang/wing/issues/552 ## Summary This PR introduces doc example testing. In its current state you can include the keyword `example` in the Markdown code block identifier similar to how we use the `playground` ability. If you create a Wing example in the docs and want to have it tested in CI when code changes are made, then all you need to do is something like `"```javascript example" ` and this will mark the code block for testing. You can also mark an example for failure if you expect it to not compile by using example meta data like so `"```javascript example{valid: false"` I started adding this to many of our doc examples and found quite a few were broken, so a good chunk of the changes in this PR fix broken examples - You can also run `pnpm turbo test:doc_examples` from the root of the project to only generate and run doc example tests. ## Further considerations - How to test examples that require other examples? (I.E. library examples) - How to test typescript examples ## Checklist - [x] Title matches [Winglang's style guide](https://www.winglang.io/contributing/start-here/pull_requests#how-are-pull-request-titles-formatted) - [x] Description explains motivation and solution - [x] Tests added (always) - [x] Docs updated (only required for features) - [ ] Added `pr/e2e-full` label if this feature requires end-to-end testing *By submitting this pull request, I confirm that my contribution is made under the terms of the [Wing Cloud Contribution License](https://github.com/winglang/wing/blob/main/CONTRIBUTION_LICENSE.md)*. --- docs/docs/01-start-here/02-getting-started.md | 2 +- .../00-cloud-oriented-programming.md | 2 +- .../02-concepts/01-preflight-and-inflight.md | 32 +- docs/docs/02-concepts/02-application-tree.md | 26 +- docs/docs/02-concepts/03-platforms.md | 2 +- docs/docs/02-concepts/04-tests.md | 10 +- docs/docs/04-standard-library/cloud/api.md | 2 +- docs/docs/04-standard-library/cloud/bucket.md | 8 +- .../docs/04-standard-library/cloud/counter.md | 6 +- .../04-standard-library/cloud/endpoint.md | 4 +- .../04-standard-library/cloud/function.md | 10 +- .../04-standard-library/cloud/on-deploy.md | 4 +- docs/docs/04-standard-library/cloud/queue.md | 13 +- .../04-standard-library/cloud/schedule.md | 6 +- docs/docs/04-standard-library/cloud/secret.md | 4 +- docs/docs/04-standard-library/cloud/topic.md | 12 +- docs/docs/06-tools/01-cli.md | 4 +- .../07-examples/01-variable-declaration.md | 10 +- docs/docs/07-examples/02-primitives.md | 8 +- docs/docs/07-examples/03-functions.md | 12 +- docs/docs/07-examples/04-flow-controls.md | 8 +- docs/docs/07-examples/05-optionality.md | 12 +- docs/docs/07-examples/06-json.md | 26 +- docs/docs/07-examples/07-structs.md | 8 +- docs/docs/07-examples/08-classes.md | 46 +- docs/docs/07-examples/10-using-javascript.md | 2 +- docs/docs/07-examples/13-api-gateway.md | 6 +- docs/docs/07-examples/80-singletons.md | 2 +- docs/package-lock.json | 113 ++++ docs/package.json | 17 + docs/src/generate_examples_files.ts | 93 +++ docs/turbo.json | 14 + examples/tests/doc_examples/.gitattributes | 1 + .../main.w | 12 + .../main.w | 13 + .../main.w | 9 + .../main.w | 7 + .../main.w | 4 + .../main.w | 9 + .../invalid/04-tests.md_example_5/main.w | 21 + examples/tests/doc_examples/package.json | 6 + examples/tests/doc_examples/turbo.json | 7 + .../main.w | 13 + .../valid/01-cli.md_example_1/main.w | 16 + .../valid/01-cli.md_example_2/main.w | 6 + .../main.w | 5 + .../main.w | 20 + .../main.w | 20 + .../main.w | 6 + .../main.w | 7 + .../main.w | 6 + .../main.w | 4 + .../main.w | 5 + .../main.w | 10 + .../main.w | 7 + .../main.w | 32 ++ .../main.w | 4 + .../main.w | 4 + .../main.w | 9 + .../02-application-tree.md_example_1/main.w | 6 + .../02-application-tree.md_example_2/main.w | 19 + .../02-application-tree.md_example_3/main.w | 22 + .../02-application-tree.md_example_4/main.w | 6 + .../02-application-tree.md_example_5/main.w | 22 + .../02-application-tree.md_example_6/main.w | 23 + .../02-application-tree.md_example_7/main.w | 18 + .../02-getting-started.md_example_1/main.w | 22 + .../valid/02-primitives.md_example_1/main.w | 8 + .../valid/02-primitives.md_example_2/main.w | 25 + .../valid/02-primitives.md_example_3/main.w | 19 + .../valid/02-primitives.md_example_4/main.w | 8 + .../valid/03-functions.md_example_1/main.w | 6 + .../valid/03-functions.md_example_2/main.w | 13 + .../valid/03-functions.md_example_3/main.w | 17 + .../valid/03-platforms.md_example_1/main.w | 26 + .../04-flow-controls.md_example_1/main.w | 22 + .../04-flow-controls.md_example_2/main.w | 16 + .../04-flow-controls.md_example_3/main.w | 23 + .../04-flow-controls.md_example_4/main.w | 28 + .../valid/04-tests.md_example_1/main.w | 5 + .../valid/04-tests.md_example_2/main.w | 8 + .../valid/04-tests.md_example_3/main.w | 16 + .../valid/04-tests.md_example_4/main.w | 23 + .../valid/05-optionality.md_example_1/main.w | 4 + .../valid/05-optionality.md_example_2/main.w | 11 + .../valid/05-optionality.md_example_3/main.w | 18 + .../valid/05-optionality.md_example_4/main.w | 5 + .../valid/05-optionality.md_example_5/main.w | 20 + .../valid/05-optionality.md_example_6/main.w | 23 + .../valid/06-json.md_example_1/main.w | 23 + .../valid/06-json.md_example_2/main.w | 12 + .../valid/06-json.md_example_3/main.w | 10 + .../valid/06-json.md_example_4/main.w | 9 + .../valid/06-json.md_example_5/main.w | 6 + .../valid/06-json.md_example_6/main.w | 7 + .../valid/06-json.md_example_7/main.w | 6 + .../valid/06-json.md_example_8/main.w | 6 + .../valid/06-json.md_example_9/main.w | 13 + .../valid/07-structs.md_example_1/main.w | 10 + .../valid/07-structs.md_example_2/main.w | 12 + .../valid/07-structs.md_example_3/main.w | 21 + .../valid/07-structs.md_example_4/main.w | 17 + .../valid/08-classes.md_example_1/main.w | 40 ++ .../valid/08-classes.md_example_2/main.w | 21 + .../valid/08-classes.md_example_3/main.w | 24 + .../valid/08-classes.md_example_4/main.w | 62 ++ .../10-using-javascript.md_example_1/main.w | 9 + .../valid/13-api-gateway.md_example_1/main.w | 30 + .../valid/13-api-gateway.md_example_2/main.w | 16 + .../valid/13-api-gateway.md_example_3/main.w | 19 + .../valid/80-singletons.md_example_1/main.w | 12 + .../valid/api.md_example_1/main.w | 70 +++ .../valid/bucket.md_example_1/main.w | 7 + .../valid/bucket.md_example_2/main.w | 7 + .../valid/bucket.md_example_3/main.w | 24 + .../valid/bucket.md_example_4/main.w | 18 + .../valid/counter.md_example_1/main.w | 7 + .../valid/counter.md_example_2/main.w | 18 + .../valid/counter.md_example_3/main.w | 18 + .../valid/endpoint.md_example_1/main.w | 5 + .../valid/endpoint.md_example_2/main.w | 5 + .../valid/function.md_example_1/main.w | 24 + .../valid/function.md_example_2/main.w | 27 + .../valid/function.md_example_3/main.w | 17 + .../valid/function.md_example_4/main.w | 14 + .../valid/on-deploy.md_example_1/main.w | 12 + .../valid/on-deploy.md_example_2/main.w | 12 + .../valid/queue.md_example_1/main.w | 14 + .../valid/queue.md_example_2/main.w | 16 + .../valid/queue.md_example_3/main.w | 11 + .../valid/queue.md_example_4/main.w | 10 + .../valid/schedule.md_example_1/main.w | 9 + .../valid/schedule.md_example_2/main.w | 9 + .../valid/secret.md_example_1/main.w | 7 + .../valid/secret.md_example_2/main.w | 12 + .../valid/topic.md_example_1/main.w | 5 + .../valid/topic.md_example_2/main.w | 9 + .../valid/topic.md_example_3/main.w | 11 + .../valid/topic.md_example_4/main.w | 12 + .../valid/topic.md_example_5/main.w | 25 + libs/wingsdk/src/cloud/api.md | 2 +- libs/wingsdk/src/cloud/bucket.md | 8 +- libs/wingsdk/src/cloud/counter.md | 6 +- libs/wingsdk/src/cloud/endpoint.md | 4 +- libs/wingsdk/src/cloud/function.md | 10 +- libs/wingsdk/src/cloud/on-deploy.md | 4 +- libs/wingsdk/src/cloud/queue.md | 13 +- libs/wingsdk/src/cloud/schedule.md | 6 +- libs/wingsdk/src/cloud/secret.md | 4 +- libs/wingsdk/src/cloud/topic.md | 12 +- pnpm-lock.yaml | 530 +++++++++++++++--- pnpm-workspace.yaml | 1 + tools/hangar/package.json | 1 + tools/hangar/src/generate_tests.ts | 19 +- tools/hangar/src/generated_test_targets.ts | 16 +- tools/hangar/src/invalid.test.ts | 22 +- tools/hangar/src/paths.ts | 9 + tools/hangar/turbo.json | 11 +- 158 files changed, 2527 insertions(+), 240 deletions(-) create mode 100644 docs/package-lock.json create mode 100644 docs/package.json create mode 100644 docs/src/generate_examples_files.ts create mode 100644 docs/turbo.json create mode 100644 examples/tests/doc_examples/.gitattributes create mode 100644 examples/tests/doc_examples/invalid/01-preflight-and-inflight.md_example_12/main.w create mode 100644 examples/tests/doc_examples/invalid/01-preflight-and-inflight.md_example_15/main.w create mode 100644 examples/tests/doc_examples/invalid/01-preflight-and-inflight.md_example_7/main.w create mode 100644 examples/tests/doc_examples/invalid/01-preflight-and-inflight.md_example_8/main.w create mode 100644 examples/tests/doc_examples/invalid/01-variable-declaration.md_example_1/main.w create mode 100644 examples/tests/doc_examples/invalid/01-variable-declaration.md_example_4/main.w create mode 100644 examples/tests/doc_examples/invalid/04-tests.md_example_5/main.w create mode 100644 examples/tests/doc_examples/package.json create mode 100644 examples/tests/doc_examples/turbo.json create mode 100644 examples/tests/doc_examples/valid/00-cloud-oriented-programming.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/01-cli.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/01-cli.md_example_2/main.w create mode 100644 examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_10/main.w create mode 100644 examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_11/main.w create mode 100644 examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_13/main.w create mode 100644 examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_14/main.w create mode 100644 examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_2/main.w create mode 100644 examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_3/main.w create mode 100644 examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_4/main.w create mode 100644 examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_5/main.w create mode 100644 examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_6/main.w create mode 100644 examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_9/main.w create mode 100644 examples/tests/doc_examples/valid/01-variable-declaration.md_example_2/main.w create mode 100644 examples/tests/doc_examples/valid/01-variable-declaration.md_example_3/main.w create mode 100644 examples/tests/doc_examples/valid/01-variable-declaration.md_example_5/main.w create mode 100644 examples/tests/doc_examples/valid/02-application-tree.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/02-application-tree.md_example_2/main.w create mode 100644 examples/tests/doc_examples/valid/02-application-tree.md_example_3/main.w create mode 100644 examples/tests/doc_examples/valid/02-application-tree.md_example_4/main.w create mode 100644 examples/tests/doc_examples/valid/02-application-tree.md_example_5/main.w create mode 100644 examples/tests/doc_examples/valid/02-application-tree.md_example_6/main.w create mode 100644 examples/tests/doc_examples/valid/02-application-tree.md_example_7/main.w create mode 100644 examples/tests/doc_examples/valid/02-getting-started.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/02-primitives.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/02-primitives.md_example_2/main.w create mode 100644 examples/tests/doc_examples/valid/02-primitives.md_example_3/main.w create mode 100644 examples/tests/doc_examples/valid/02-primitives.md_example_4/main.w create mode 100644 examples/tests/doc_examples/valid/03-functions.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/03-functions.md_example_2/main.w create mode 100644 examples/tests/doc_examples/valid/03-functions.md_example_3/main.w create mode 100644 examples/tests/doc_examples/valid/03-platforms.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/04-flow-controls.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/04-flow-controls.md_example_2/main.w create mode 100644 examples/tests/doc_examples/valid/04-flow-controls.md_example_3/main.w create mode 100644 examples/tests/doc_examples/valid/04-flow-controls.md_example_4/main.w create mode 100644 examples/tests/doc_examples/valid/04-tests.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/04-tests.md_example_2/main.w create mode 100644 examples/tests/doc_examples/valid/04-tests.md_example_3/main.w create mode 100644 examples/tests/doc_examples/valid/04-tests.md_example_4/main.w create mode 100644 examples/tests/doc_examples/valid/05-optionality.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/05-optionality.md_example_2/main.w create mode 100644 examples/tests/doc_examples/valid/05-optionality.md_example_3/main.w create mode 100644 examples/tests/doc_examples/valid/05-optionality.md_example_4/main.w create mode 100644 examples/tests/doc_examples/valid/05-optionality.md_example_5/main.w create mode 100644 examples/tests/doc_examples/valid/05-optionality.md_example_6/main.w create mode 100644 examples/tests/doc_examples/valid/06-json.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/06-json.md_example_2/main.w create mode 100644 examples/tests/doc_examples/valid/06-json.md_example_3/main.w create mode 100644 examples/tests/doc_examples/valid/06-json.md_example_4/main.w create mode 100644 examples/tests/doc_examples/valid/06-json.md_example_5/main.w create mode 100644 examples/tests/doc_examples/valid/06-json.md_example_6/main.w create mode 100644 examples/tests/doc_examples/valid/06-json.md_example_7/main.w create mode 100644 examples/tests/doc_examples/valid/06-json.md_example_8/main.w create mode 100644 examples/tests/doc_examples/valid/06-json.md_example_9/main.w create mode 100644 examples/tests/doc_examples/valid/07-structs.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/07-structs.md_example_2/main.w create mode 100644 examples/tests/doc_examples/valid/07-structs.md_example_3/main.w create mode 100644 examples/tests/doc_examples/valid/07-structs.md_example_4/main.w create mode 100644 examples/tests/doc_examples/valid/08-classes.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/08-classes.md_example_2/main.w create mode 100644 examples/tests/doc_examples/valid/08-classes.md_example_3/main.w create mode 100644 examples/tests/doc_examples/valid/08-classes.md_example_4/main.w create mode 100644 examples/tests/doc_examples/valid/10-using-javascript.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/13-api-gateway.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/13-api-gateway.md_example_2/main.w create mode 100644 examples/tests/doc_examples/valid/13-api-gateway.md_example_3/main.w create mode 100644 examples/tests/doc_examples/valid/80-singletons.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/api.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/bucket.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/bucket.md_example_2/main.w create mode 100644 examples/tests/doc_examples/valid/bucket.md_example_3/main.w create mode 100644 examples/tests/doc_examples/valid/bucket.md_example_4/main.w create mode 100644 examples/tests/doc_examples/valid/counter.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/counter.md_example_2/main.w create mode 100644 examples/tests/doc_examples/valid/counter.md_example_3/main.w create mode 100644 examples/tests/doc_examples/valid/endpoint.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/endpoint.md_example_2/main.w create mode 100644 examples/tests/doc_examples/valid/function.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/function.md_example_2/main.w create mode 100644 examples/tests/doc_examples/valid/function.md_example_3/main.w create mode 100644 examples/tests/doc_examples/valid/function.md_example_4/main.w create mode 100644 examples/tests/doc_examples/valid/on-deploy.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/on-deploy.md_example_2/main.w create mode 100644 examples/tests/doc_examples/valid/queue.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/queue.md_example_2/main.w create mode 100644 examples/tests/doc_examples/valid/queue.md_example_3/main.w create mode 100644 examples/tests/doc_examples/valid/queue.md_example_4/main.w create mode 100644 examples/tests/doc_examples/valid/schedule.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/schedule.md_example_2/main.w create mode 100644 examples/tests/doc_examples/valid/secret.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/secret.md_example_2/main.w create mode 100644 examples/tests/doc_examples/valid/topic.md_example_1/main.w create mode 100644 examples/tests/doc_examples/valid/topic.md_example_2/main.w create mode 100644 examples/tests/doc_examples/valid/topic.md_example_3/main.w create mode 100644 examples/tests/doc_examples/valid/topic.md_example_4/main.w create mode 100644 examples/tests/doc_examples/valid/topic.md_example_5/main.w diff --git a/docs/docs/01-start-here/02-getting-started.md b/docs/docs/01-start-here/02-getting-started.md index 3e7c68bbc76..e9bc0eca29c 100644 --- a/docs/docs/01-start-here/02-getting-started.md +++ b/docs/docs/01-start-here/02-getting-started.md @@ -68,7 +68,7 @@ You can use the CLI to bootstrap a new project: Use the `new` command and then m wing new empty ``` -```js +```js example bring cloud; // define a queue, a bucket and a counter diff --git a/docs/docs/02-concepts/00-cloud-oriented-programming.md b/docs/docs/02-concepts/00-cloud-oriented-programming.md index 1a6949d8402..12ce581b98d 100644 --- a/docs/docs/02-concepts/00-cloud-oriented-programming.md +++ b/docs/docs/02-concepts/00-cloud-oriented-programming.md @@ -15,7 +15,7 @@ cloud without having to worry about the underlying infrastructure. It's best explained through an example: -```js +```js example bring cloud; let queue = new cloud.Queue(timeout: 2m); diff --git a/docs/docs/02-concepts/01-preflight-and-inflight.md b/docs/docs/02-concepts/01-preflight-and-inflight.md index ea7c3ceca36..73f019797ea 100644 --- a/docs/docs/02-concepts/01-preflight-and-inflight.md +++ b/docs/docs/02-concepts/01-preflight-and-inflight.md @@ -28,7 +28,7 @@ Your preflight code runs once, at compile time, and defines your application's i For example, this code snippet defines a storage bucket using a class from the standard library: -```js playground +```js playground example bring cloud; let bucket = new cloud.Bucket(); @@ -42,7 +42,7 @@ Preflight code can be also used to configure services or set up more complex eve In this code snippet, we've specified the bucket's contents will be publicly accessible, and it will be pre-populated with a file during the app's deployment (not while the app is running). -```js playground +```js playground example bring cloud; let bucket = new cloud.Bucket(public: true); @@ -52,7 +52,7 @@ bucket.addObject("file1.txt", "Hello world!"); There are a few global functions with specific behaviors in preflight. For example, adding a `log()` statement to your preflight code will result in Wing printing a message to the console after compilation. -```js +```js example // hello.w log("7 * 6 = {7 * 6}"); ``` @@ -84,7 +84,7 @@ Let's walk through some examples. Inflight code is always contained inside a block that starts with the word `inflight`. -```js +```js example let greeting = inflight () => { log("Hello from the cloud!"); }; @@ -93,7 +93,7 @@ let greeting = inflight () => { Inflight code can call other inflight functions and methods. For example, `cloud.Bucket` has an inflight method named `list()` that can be called inside inflight contexts: -```js playground +```js playground example bring cloud; let bucket = new cloud.Bucket(); @@ -110,7 +110,7 @@ Even though `bucket` is defined in preflight, it's okay to use its inflight meth For an inflight function to actually get executed, it must be provided to an API that expects inflight code. For example, we can provide it to a `cloud.Function`: -```js playground +```js playground example bring cloud; let func = new cloud.Function(inflight () => { @@ -133,7 +133,7 @@ firstObject(); // error: Cannot call into inflight phase while preflight Likewise, inflight code cannot call preflight code, because preflight code has the capability to modify your application's infrastructure configuration, which is disallowed after deployment. For example, since `addObject` is a preflight method, it cannot be called in inflight: -```js playground +```js playground example{valid: false} bring cloud; let bucket = new cloud.Bucket(); @@ -147,7 +147,7 @@ Instead, to insert an object into the bucket at runtime you would have to use an Since a class's initializer is just a special kind of preflight function, it also isn't possible to initialize regular classes during preflight: -```js playground +```js playground example{valid: false} bring cloud; inflight () => { @@ -163,7 +163,7 @@ A preflight class (the default kind of class) can contain both preflight and inf Here's a class that models a queue that can replay its messages. A `cloud.Bucket` stores the history of messages, and a `cloud.Counter` helps with sequencing each new message as it's added to the queue. -```js playground +```js playground example bring cloud; class ReplayableQueue { @@ -202,7 +202,7 @@ Inflight classes are safe to create in inflight contexts. For example, this inflight class can be created in an inflight contexts, and its methods can be called in inflight contexts: -```js playground +```js playground example inflight () => { class Person { name: str; @@ -213,7 +213,7 @@ inflight () => { this.age = age; } - inflight greet() { + pub inflight greet() { log("Hello, {this.name}!"); } } @@ -230,7 +230,7 @@ While inflight code can't call preflight code, it's perfectly ok to reference da For example, the `cloud.Api` class has a preflight field named `url`. Since the URL is a string, it can be directly referenced inflight: -```js +```js example bring cloud; bring http; @@ -254,7 +254,7 @@ new cloud.Function(checkEndpoint); However, mutation to preflight data is not allowed. This mean means that variables from preflight cannot be reassigned to, and mutable collections like `MutArray` and `MutMap` cannot be modified (they're turned into their immutable counterparts, `Array` and `Map`, respectively when accessed inflight). -```js playground +```js playground example{valid: false} let var count = 3; let names = MutArray["John", "Jane", "Joe"]; @@ -271,7 +271,7 @@ inflight () => { Preflight objects referenced inflight are called "lifted" objects: -```js playground +```js playground example let preflight_str = "hello from preflight"; inflight () => { log(preflight_str); // `preflight_str` is "lifted" into inflight. @@ -281,7 +281,7 @@ inflight () => { During the lifting process the compiler tries to figure out in what way the lifted objects are being used. This is how Winglang generats least privilage permissions. Consider the case of lifting a [`cloud.Bucket`](../04-standard-library/cloud/bucket.md) object: -```js playground +```js playground example bring cloud; let bucket = new cloud.Bucket(); new cloud.Function(inflight () => { @@ -294,7 +294,7 @@ In this example the compiler generates the correct _write_ access permissions fo #### Explicit lift qualification In some cases the compiler can't figure out (yet) the lift qualifications, and therefore will report an error: -```js playground +```js playground example{valid: false} bring cloud; let main_bucket = new cloud.Bucket() as "main"; let secondary_bucket = new cloud.Bucket() as "backup"; diff --git a/docs/docs/02-concepts/02-application-tree.md b/docs/docs/02-concepts/02-application-tree.md index dfa9c2079a1..02318fda115 100644 --- a/docs/docs/02-concepts/02-application-tree.md +++ b/docs/docs/02-concepts/02-application-tree.md @@ -10,7 +10,9 @@ The name is used to identify the resource in the Wing Console, and is used to de The default name of a resource is the name of the class. The name can be overridden using the `as` syntax: -```js +```js example +bring cloud; + let bucket1 = new cloud.Bucket(); // default name is "cloud.Bucket" let bucket2 = new cloud.Bucket() as "my-bucket"; ``` @@ -18,7 +20,9 @@ let bucket2 = new cloud.Bucket() as "my-bucket"; The name of a resource needs to be unique within the scope it is defined. New classes introduce new scopes, so the same name can be used for different resources in different classes. -```js +```js example +bring cloud; + class Group1 { new() { new cloud.Bucket() as "Store"; @@ -43,7 +47,7 @@ Instances of preflight classes define the application's construct tree. This way In Wing this tree structure is automatically generated. Any class instantiated at the top level (global scope) is a child of the "root" node of of the tree. Any class instantiated inside another class (in its constructor or one of its other preflight methods) will be placed as a child of that other class. -```js +```js example class ThumbnailBucket { //... } @@ -70,7 +74,9 @@ As mentioned in the [previous section](#instance-names) each instance must have And the name will be automatically generated based on the class name. So the tree shown above also shows the correct names for each infrastructure piece of our application. You may query information about the construct tree using the `nodeof(someInstance)` intrinsic function: -```js +```js example +bring cloud; + let b = new cloud.Bucket(); log(nodeof(b).path); // Will log something like "/root/Bucket" ``` @@ -79,7 +85,7 @@ log(nodeof(b).path); // Will log something like "/root/Bucket" You may define an explicit scope for an instance instead of using Wing's default of placing it inside the instance where it was created using the `in` keyword: -```js +```js example class ThumbnailBucket { //... } @@ -107,14 +113,16 @@ let defaultThumbnails = new ThumbnailBucket() as "defaultThumbs" in imageStorage Preflight classes instantiated inside static methods, or instantiated inside constructors before `this` is available will use the scope of the caller by default: -```js +```js example +bring cloud; + class Factory { pub static make() { new cloud.Bucket(); // We're in a static, so we don't know where to place this bucket } } -class MyBucket() { +class MyBucket { new() { Factory.make(); // Bucket will be placed inside `this` instance of `MyBucket` } @@ -132,7 +140,9 @@ new MyBucket(); Similarly, consider this case where we instantiate a class inside a parameter in a `super()` constructor call before the the class is creates and its scope becomes valid: -```js +```js example +bring cloud; + class Base { new(b: cloud.Bucket) {} } diff --git a/docs/docs/02-concepts/03-platforms.md b/docs/docs/02-concepts/03-platforms.md index aa5ab0f2144..f916a0dff63 100644 --- a/docs/docs/02-concepts/03-platforms.md +++ b/docs/docs/02-concepts/03-platforms.md @@ -123,7 +123,7 @@ There might be times when you need to write code that is specific to a particula With the Wing `util` library, you can access environment variables. The `WING_TARGET` environment variable contains the current platform target as it's value, which you can use to conditionally run target-specific code. See the example below: -```js playground +```js playground example bring cloud; bring util; diff --git a/docs/docs/02-concepts/04-tests.md b/docs/docs/02-concepts/04-tests.md index 8f82720da56..7fb091a6be0 100644 --- a/docs/docs/02-concepts/04-tests.md +++ b/docs/docs/02-concepts/04-tests.md @@ -11,7 +11,7 @@ Winglang incorporates a lightweight testing framework, which is built around the You can create a test by adding the following code structure to any Winglang file (.w): -```ts wing +```ts wing example test "" { // test code } @@ -21,7 +21,7 @@ If a test throws an exception (typically using the `assert` function), it's cons Here's an example: -```ts playground +```ts playground example // example.w bring math; @@ -50,7 +50,7 @@ Duration 0m0.54s Every Winglang test is executed in complete isolation. Take a look at the following code: -```ts playground +```ts playground example bring cloud; let b = new cloud.Bucket(); @@ -73,7 +73,7 @@ In the first test (`bucket list should include created file`), a file is created Consider the following example: -```ts playground +```ts playground example bring cloud; bring util; @@ -140,7 +140,7 @@ Wing Console provides a straightforward method to run either a single test or al Consider the following code: -```ts playground +```ts playground example{valid: false} // example.w bring cloud; diff --git a/docs/docs/04-standard-library/cloud/api.md b/docs/docs/04-standard-library/cloud/api.md index 2b839417888..5127273d45e 100644 --- a/docs/docs/04-standard-library/cloud/api.md +++ b/docs/docs/04-standard-library/cloud/api.md @@ -29,7 +29,7 @@ When a client invokes a route, the corresponding event handler function executes The following example shows a complete REST API implementation using `cloud.Api`, `ex.Table` & `cloud.Counter` -```ts playground +```ts playground example bring cloud; bring ex; diff --git a/docs/docs/04-standard-library/cloud/bucket.md b/docs/docs/04-standard-library/cloud/bucket.md index 1bd87a94960..8844346e31e 100644 --- a/docs/docs/04-standard-library/cloud/bucket.md +++ b/docs/docs/04-standard-library/cloud/bucket.md @@ -26,7 +26,7 @@ Unlike other kinds of storage like file storage, data is not stored in a hierarc ### Defining a bucket -```js +```js example bring cloud; let bucket = new cloud.Bucket( @@ -38,7 +38,7 @@ let bucket = new cloud.Bucket( If you have static data that you want to upload to the bucket each time your app is deployed, you can call the preflight method `addObject`: -```js +```js example bring cloud; let bucket = new cloud.Bucket(); @@ -48,7 +48,7 @@ bucket.addObject("my-file.txt", "Hello, world!"); ### Using a bucket inflight -```js playground +```js playground example bring cloud; let bucket = new cloud.Bucket(); @@ -80,7 +80,7 @@ Use the `onEvent` method for responding to any event. Each method creates a new `cloud.Function` resource which will be triggered by the given event type. -```js playground +```js playground example bring cloud; let store = new cloud.Bucket(); diff --git a/docs/docs/04-standard-library/cloud/counter.md b/docs/docs/04-standard-library/cloud/counter.md index e587a2d78e4..2d5aecf564f 100644 --- a/docs/docs/04-standard-library/cloud/counter.md +++ b/docs/docs/04-standard-library/cloud/counter.md @@ -20,7 +20,7 @@ The `cloud.Counter` resource represents a stateful container for one or more num ### Defining a counter -```js +```js example bring cloud; let counter = new cloud.Counter( @@ -30,7 +30,7 @@ let counter = new cloud.Counter( ### Using a counter inflight -```js playground +```js playground example bring cloud; let counter = new cloud.Counter(); @@ -51,7 +51,7 @@ new cloud.Function(counterFunc); ### Using keys to manage multiple counter values -```js playground +```js playground example bring cloud; let counter = new cloud.Counter(initial: 100); diff --git a/docs/docs/04-standard-library/cloud/endpoint.md b/docs/docs/04-standard-library/cloud/endpoint.md index 7e11f592e76..c9a3abcc1fb 100644 --- a/docs/docs/04-standard-library/cloud/endpoint.md +++ b/docs/docs/04-standard-library/cloud/endpoint.md @@ -19,7 +19,7 @@ The `cloud.Endpoint` represents a publicly accessible endpoint and outputs it as ## Usage -```ts playground +```ts playground example bring cloud; let endpoint = new cloud.Endpoint("https://example.com"); @@ -54,7 +54,7 @@ represents a publicly accessible endpoint and outputs it as part of the compilat #### Initializers -```wing +```wing example bring cloud; new cloud.Endpoint("https://example.com"); diff --git a/docs/docs/04-standard-library/cloud/function.md b/docs/docs/04-standard-library/cloud/function.md index 5165c72ae8e..16af5f6bd26 100644 --- a/docs/docs/04-standard-library/cloud/function.md +++ b/docs/docs/04-standard-library/cloud/function.md @@ -29,7 +29,7 @@ A function can be invoked in two ways: * **invoke()** - Executes the function with a payload and waits for the result. * **invokeAsync()** - Kicks off the execution of the function with a payload and returns immediately while the function is running. -```ts playground +```ts playground example bring cloud; bring util; @@ -61,7 +61,7 @@ It is possible to leverage this behavior to cache objects across function execut The following example reads the `bigdata.json` file once and reuses it every time `query()` is called. -```ts playground +```ts playground example bring cloud; let big = new cloud.Bucket(); @@ -98,6 +98,8 @@ The sim implementation of `cloud.Function` runs the inflight code as a JavaScrip By default, a maximum of 10 workers can be processing requests sent to a `cloud.Function` concurrently, but this number can be adjusted with the `concurrency` property: ```ts playground +bring cloud; + new cloud.Function(inflight () => { // ... code that shouldn't run concurrently ... }, concurrency: 1); @@ -109,7 +111,7 @@ The AWS implementation of `cloud.Function` uses [AWS Lambda](https://aws.amazon. To add extra IAM permissions to the function, you can use the `aws.Function` class as shown below. -```ts playground +```ts playground example bring aws; bring cloud; @@ -129,7 +131,7 @@ if let lambdaFn = aws.Function.from(f) { To access the AWS Lambda context object, you can use the `aws.Function` class as shown below. -```ts playground +```ts playground example bring aws; bring cloud; diff --git a/docs/docs/04-standard-library/cloud/on-deploy.md b/docs/docs/04-standard-library/cloud/on-deploy.md index 10729023e07..5d41d3694bf 100644 --- a/docs/docs/04-standard-library/cloud/on-deploy.md +++ b/docs/docs/04-standard-library/cloud/on-deploy.md @@ -20,7 +20,7 @@ The `cloud.OnDeploy` resource runs a block of inflight code each time the applic ## Usage -```ts playground +```ts playground example bring cloud; let bucket = new cloud.Bucket(); @@ -35,7 +35,7 @@ let setup = new cloud.OnDeploy(inflight () => { To specify that the `cloud.OnDeploy` resource should be run before or after another resource is created or updated, use the `executeBefore` or `executeAfter` properties: -```ts playground +```ts playground example bring cloud; let counter = new cloud.Counter(); diff --git a/docs/docs/04-standard-library/cloud/queue.md b/docs/docs/04-standard-library/cloud/queue.md index 978bc328718..1b5bcbc21b7 100644 --- a/docs/docs/04-standard-library/cloud/queue.md +++ b/docs/docs/04-standard-library/cloud/queue.md @@ -26,7 +26,7 @@ Queues by default are not FIFO (first in, first out) - so the order of messages ### Setting a Queue Consumer -```ts playground +```ts playground example bring cloud; let q = new cloud.Queue(); @@ -45,7 +45,7 @@ new cloud.Function(inflight () => { Pushing messages, popping them, and purging. -```ts playground +```ts playground example bring cloud; let q = new cloud.Queue(); @@ -54,8 +54,8 @@ new cloud.Function(inflight () => { q.push("message a"); q.push("message b", "message c", "message d"); log("approxSize is ${q.approxSize()}"); - log("popping message ${q.pop()}"); - log("popping message ${q.pop()}"); + log("popping message ${q.pop()!}"); + log("popping message ${q.pop()!}"); log("approxSize is ${q.approxSize()}"); q.purge(); log("approxSize is ${q.approxSize()}"); @@ -66,7 +66,7 @@ new cloud.Function(inflight () => { Creating a queue and adding a dead-letter queue with the maximum number of attempts configured -```ts playground +```ts playground example bring cloud; let dlq = new cloud.Queue() as "dead-letter queue"; @@ -88,7 +88,8 @@ If you would like to reference an existing queue from within your application yo The following example defines a reference to an Amazon SQS queue with a specific ARN and sends a message to the queue from the function: -```js +```js example +bring cloud; bring aws; let outbox = new aws.QueueRef("arn:aws:sqs:us-east-1:111111111111:Outbox"); diff --git a/docs/docs/04-standard-library/cloud/schedule.md b/docs/docs/04-standard-library/cloud/schedule.md index 9f0a3864870..7da90e055c4 100644 --- a/docs/docs/04-standard-library/cloud/schedule.md +++ b/docs/docs/04-standard-library/cloud/schedule.md @@ -23,10 +23,10 @@ The timezone used in cron expressions is always UTC. ### From cron -```ts playground +```ts playground example bring cloud; -let schedule = new cloud.Schedule(cron: "* * * * ?"); +let schedule = new cloud.Schedule(cron: "* * * * *"); schedule.onTick(inflight () => { log("schedule: triggered"); @@ -35,7 +35,7 @@ schedule.onTick(inflight () => { ### From rate -```ts playground +```ts playground example bring cloud; let schedule = new cloud.Schedule(rate: 1m); diff --git a/docs/docs/04-standard-library/cloud/secret.md b/docs/docs/04-standard-library/cloud/secret.md index 73f2e7c12d1..73dafd421eb 100644 --- a/docs/docs/04-standard-library/cloud/secret.md +++ b/docs/docs/04-standard-library/cloud/secret.md @@ -25,7 +25,7 @@ You can use the [`wing secrets`](https://www.winglang.io/docs/tools/cli#store-se ### Defining a secret -```js +```js example bring cloud; let secret = new cloud.Secret( @@ -37,7 +37,7 @@ Before deploying your application, you will be expected to store the secret valu ### Retrieving secret values -```js +```js example bring cloud; let secret = new cloud.Secret( diff --git a/docs/docs/04-standard-library/cloud/topic.md b/docs/docs/04-standard-library/cloud/topic.md index 56de75be3ee..11253eba690 100644 --- a/docs/docs/04-standard-library/cloud/topic.md +++ b/docs/docs/04-standard-library/cloud/topic.md @@ -22,7 +22,7 @@ Topics are a staple of event-driven architectures, especially those that rely on ### Creating a topic -```js +```js example bring cloud; let topic = new cloud.Topic(); @@ -30,7 +30,7 @@ let topic = new cloud.Topic(); ### Subscribing to a topic -```js +```js example bring cloud; let topic = new cloud.Topic(); @@ -42,11 +42,11 @@ topic.onMessage(inflight (message: str) => { ### Subscribing a Queue to a Topic -```js +```js example bring cloud; let queue = new cloud.Queue(); -queue.setConsumer(inflight (message str) => { +queue.setConsumer(inflight (message: str) => { log("Topic published message: {message}"); }); @@ -58,7 +58,7 @@ topic.subscribeQueue(queue); The inflight method `publish` sends messages to all of the topic's subscribers. -```js +```js example bring cloud; let topic = new cloud.Topic(); @@ -76,7 +76,7 @@ inflight () => { Here is an example of combining the preflight and inflight apis for a topic and creating an adorable simple pub-sub application. -```js +```js example bring cloud; // First we create a topic diff --git a/docs/docs/06-tools/01-cli.md b/docs/docs/06-tools/01-cli.md index b0b0b66819e..c7ff114d0e9 100644 --- a/docs/docs/06-tools/01-cli.md +++ b/docs/docs/06-tools/01-cli.md @@ -98,7 +98,7 @@ In the following example ([test_bucket.test.w](https://github.com/winglang/wing/tree/main/examples/tests/valid/test_bucket.test.w)), the application consists of a single `cloud.Bucket` and two tests `"put"` and `"get"`. -```js +```js example bring cloud; let b = new cloud.Bucket(); @@ -247,7 +247,7 @@ The `wing secrets` command can be used to store secrets needed by your applicati Take the following Wing application: -```js +```js example // main.w bring cloud; diff --git a/docs/docs/07-examples/01-variable-declaration.md b/docs/docs/07-examples/01-variable-declaration.md index d18b709d6d4..3a8cfd48233 100644 --- a/docs/docs/07-examples/01-variable-declaration.md +++ b/docs/docs/07-examples/01-variable-declaration.md @@ -6,22 +6,24 @@ keywords: [Wing example] ### Assignment -```ts +```ts example{valid: false} let x = 12; x = 77; // error: Variable is not reassignable +``` +```ts example let var y = "hello"; y = "world"; // OK (y is reassignable) ``` ### Inferred typing -```ts playground +```ts playground example let x1 = 12; let x2: num = 12; // equivalent ``` ### Optionals -```ts playground +```ts playground example{valid: false} let var x1 = "Hello"; // type str, value "Hello" let var x2: str = "Hello"; // same as above let var x3: str? = "Hello"; // type str? (optional), value "Hello" @@ -31,7 +33,7 @@ x1 = nil; // ERROR: Expected type to be "str", but got "nil" instead x3 = nil; // OK (x3 is optional) ``` ### Scopes -```ts +```ts example let s = "parent"; log(s); // prints parent if true { diff --git a/docs/docs/07-examples/02-primitives.md b/docs/docs/07-examples/02-primitives.md index 65c19798f27..b6208d69c91 100644 --- a/docs/docs/07-examples/02-primitives.md +++ b/docs/docs/07-examples/02-primitives.md @@ -7,7 +7,7 @@ keywords: [Wing example] ## Str ### Concat and Interpolate -```ts +```ts example let s1 = "Hello Wing String"; log(s1); // prints Hello Wing String let s2 = "Interpolate: {s1}"; // string interpolation @@ -17,7 +17,7 @@ log(s3); // prints Concat: Hello Wing String ``` ### Str methods -```ts +```ts example let s = "Hello to a new Wing world"; // lets start with split @@ -45,7 +45,7 @@ for w in s.split(" ") { ## Num -```ts +```ts example let n1 = 10; log("{n1}"); // 10 @@ -68,7 +68,7 @@ log("{n6}"); // The meaning of the universe ## Bool -```ts +```ts example let b1 = true; let b2 = false; diff --git a/docs/docs/07-examples/03-functions.md b/docs/docs/07-examples/03-functions.md index 554763dacba..77830f153df 100644 --- a/docs/docs/07-examples/03-functions.md +++ b/docs/docs/07-examples/03-functions.md @@ -7,9 +7,9 @@ keywords: [Wing example] ### Preflight function -```ts playground +```ts playground example // preflight function - when declared in preflight context -let dup = (s: str, count: num): str => { +let dup = (s: str, count: num) => { // code }; ``` @@ -18,21 +18,21 @@ let dup = (s: str, count: num): str => { Inflight functions are Wing's distributed computing primitive. They are isolated code blocks which can be packaged and executed on compute platforms in the cloud (such as containers, Lambda/Cloud Function, etc..). -```ts playground +```ts playground example let handler = inflight (message: str): void => { // using the inflight modifier - let dup = inflight (s: str, count: num): str => { + let dup = inflight (s: str, count: num) => { // code }; // inflight modifier is not required when function is declared in inflight context - let sup = (s: str, count: num): str => { + let sup = (s: str, count: num) => { // code }; }; ``` ### Struct Expansion -```ts playground +```ts playground example struct Options { prefix: str?; delim: str; diff --git a/docs/docs/07-examples/04-flow-controls.md b/docs/docs/07-examples/04-flow-controls.md index c67e1a3d7a9..0149726bbcb 100644 --- a/docs/docs/07-examples/04-flow-controls.md +++ b/docs/docs/07-examples/04-flow-controls.md @@ -6,7 +6,7 @@ keywords: [Wing example] ### For in -```ts playground +```ts playground example let iterable = ["a", "b", "c", "d", "e", "f", "g", "h"]; for value in iterable { if value == "g" { @@ -31,7 +31,7 @@ for value in iterable { ### For through a range -```ts playground +```ts playground example // print numbers from 0 to 9 for value in 0..10 { log("{value}"); @@ -50,7 +50,7 @@ for value in 1..=5 { ### If elif else -```ts playground +```ts playground example let grade = (score: num): str => { // Parentheses are optional in conditions. // However, curly braces are required in `if/else` statements. @@ -76,7 +76,7 @@ log("101 is {grade(101)}"); // 101 is Invalid grade ### While -```ts playground +```ts playground example let var i = 0; while i < 100 { i = i + 1; diff --git a/docs/docs/07-examples/05-optionality.md b/docs/docs/07-examples/05-optionality.md index e0cb665dfe1..3901a4564c2 100644 --- a/docs/docs/07-examples/05-optionality.md +++ b/docs/docs/07-examples/05-optionality.md @@ -6,13 +6,13 @@ keywords: [Wing example] ## Definition -```ts playground +```ts playground example let s1: str? = "Hello"; // type str? (optional), value "Hello" let s2: str? = nil; // type str? (optional), value nil ``` ## Testing existence -```ts playground +```ts playground example let s1: str? = "Hello"; // type str? (optional), value "Hello" let s2: str? = nil; // type str? (optional), value nil @@ -25,7 +25,7 @@ if !s2? { ``` ## Using if let -```ts playground +```ts playground example let s1: str? = "Hello"; // type str? (optional), value "Hello" // unwrap optional s1 and create s from type str @@ -46,7 +46,7 @@ log("s1 type is optional str"); ## Using ?? -```ts playground +```ts playground example let s1: str? = nil; // type str? (optional), value nil let s2 = s1 ?? "default value"; // s2 is of type str log(s2); // prints default value @@ -54,7 +54,7 @@ log(s2); // prints default value ## Optional Chaining -```ts playground +```ts playground example let j = Json { working: { a: { @@ -77,7 +77,7 @@ if let value = j.tryGet("broken")?.tryGet("a")?.tryGet("b")?.tryAsStr() { ## Optional bool -```ts playground +```ts playground example let b3: bool? = false; if b3? { diff --git a/docs/docs/07-examples/06-json.md b/docs/docs/07-examples/06-json.md index a4051227c47..6a591d97913 100644 --- a/docs/docs/07-examples/06-json.md +++ b/docs/docs/07-examples/06-json.md @@ -6,7 +6,7 @@ keywords: [Wing example] ## Create Json values ### Using Json literal -```js playground +```js playground example let j = Json { k1: 1, k2: "hello", @@ -32,7 +32,7 @@ log("{jsonHomogeneousArrayValue}"); ### From existing variables -```js playground +```js playground example let x: num = 42; let jsonNum = Json x; log("{jsonNum}"); // 42 @@ -59,7 +59,7 @@ if let jsonFromTryParse = Json.tryParse("{\"k1\":\"v\"}") { ## Enumerating ### Over keys -```js playground +```js playground example let j = Json { k1: "v1", k2: "v2" @@ -70,7 +70,7 @@ for k in Json.keys(j) { } ``` ### Over values -```js playground +```js playground example let j = Json { k1: "v1", k2: "v2" @@ -81,7 +81,7 @@ for value in Json.values(j) { ``` ### Over a json array -```js playground +```js playground example let arrayValue = Json ["a", "b", "c"]; for v in Json.values(arrayValue) { log(str.fromJson(v)); @@ -90,7 +90,7 @@ for v in Json.values(arrayValue) { ## Safely convert to primitives ### To `str` -```js playground +```js playground example let j = Json { k: "hello" }; @@ -99,24 +99,24 @@ log(j.get("k").asStr()); ``` ### To `num` -```js playground +```js playground example let j = Json { - k: 12 + k: 12 }; -log(j.get("k").asNum()); +log("{j.get("k").asNum()}"); ``` ### To `bool` -```js playground +```js playground example let j = Json { - k:true + k:true }; -log(j.get("k").asBool()); +log("{j.get("k").asBool()}"); ``` ## Safely convert to structs -```js playground +```js playground example struct Foo { val1: str; val2: num; diff --git a/docs/docs/07-examples/07-structs.md b/docs/docs/07-examples/07-structs.md index 74d2578b068..73083048521 100644 --- a/docs/docs/07-examples/07-structs.md +++ b/docs/docs/07-examples/07-structs.md @@ -7,7 +7,7 @@ keywords: [Wing example] ## Deceleration and Initialization ### Required fields -```ts playground +```ts playground example struct Example { a: str; b: num; @@ -19,7 +19,7 @@ log(example.a); // prints "a" ``` ### Optional fields -```ts playground +```ts playground example struct Example { a: str?; b: num?; @@ -33,7 +33,7 @@ if ! example.a? { ``` ### Composition -```ts playground +```ts playground example struct Another { hello: str; } @@ -57,7 +57,7 @@ log(data.c.hello); // prints two ## Struct expansion in function calls -```ts playground +```ts playground example struct Options { prefix: str?; delim: str; diff --git a/docs/docs/07-examples/08-classes.md b/docs/docs/07-examples/08-classes.md index 2f9715fa603..96155a2e10a 100644 --- a/docs/docs/07-examples/08-classes.md +++ b/docs/docs/07-examples/08-classes.md @@ -5,13 +5,13 @@ keywords: [Wing example] --- ### Preflight class -```ts playground +```ts playground example bring cloud; bring util; class Foo { - field1: str; // <-- readonly - var field2: num; // <-- reassignable + pub field1: str; // <-- readonly + pub var field2: num; // <-- reassignable inflight field3: Array; new() { @@ -47,10 +47,10 @@ new cloud.Function(inflight () => { ``` ### Inflight interface -```js playground +```js playground example bring cloud; -interface IProfile { +inflight interface IProfile { inflight name(): str; } @@ -70,7 +70,8 @@ new cloud.Function(inflight () => { ``` ### Preflight interface -```ts playground +```ts playground example +bring cloud; /** * Preflight Interface **/ @@ -95,8 +96,9 @@ class BucketBasedKeyValueStore impl IKVStore { ``` ### Complete IKVStore -```js playground +```js playground example bring cloud; +bring ex; interface IKVStore extends std.IResource { inflight get(key: str): Json; @@ -117,9 +119,9 @@ class BucketBasedKeyValueStore impl IKVStore { } class TableBasedKeyValueStore impl IKVStore { - table: cloud.Table; + table: ex.Table; new() { - this.table = new cloud.Table( + this.table = new ex.Table( name: "table", primaryKey: "key", columns: { @@ -130,7 +132,7 @@ class TableBasedKeyValueStore impl IKVStore { pub inflight get(key: str): Json { return this.table.get(key); } - pub inflight set(key: str, value: Json): str { + pub inflight set(key: str, value: Json) { this.table.insert(key, value); } } @@ -138,19 +140,21 @@ class TableBasedKeyValueStore impl IKVStore { let bucketBased: IKVStore = new BucketBasedKeyValueStore(); let tableBased: IKVStore = new TableBasedKeyValueStore(); -let testKv = inflight (kv: IKVStore):void => { - kv.set("k", Json { - value: "v" +test "bucketBased KVStore" { + bucketBased.set("k", Json { + value: "v" }); - let result = kv.get("k"); + let result = bucketBased.get("k"); log("{result.get("value")}"); assert("v" == str.fromJson(result.get("value"))); -}; +} -new cloud.Function(inflight () => { - log("testing bucketBased KVStore"); - testKv(bucketBased); - log("testing tableBased KVStore"); - testKv(tableBased); -}); +test "tableBased KVStore" { + tableBased.set("k", Json { + value: "v" + }); + let result = tableBased.get("k"); + log("{result.get("value")}"); + assert("v" == str.fromJson(result.get("value"))); +} ``` \ No newline at end of file diff --git a/docs/docs/07-examples/10-using-javascript.md b/docs/docs/07-examples/10-using-javascript.md index 0f1c25c79aa..b8e9022c1fa 100644 --- a/docs/docs/07-examples/10-using-javascript.md +++ b/docs/docs/07-examples/10-using-javascript.md @@ -8,7 +8,7 @@ keywords: [example, javascript, extern, typescript, js, ts] Inflight closures are an extremely important Wing functionality. Consider the following simple wing program: -```wing +```wing example // main.w bring cloud; let bucket = new cloud.Bucket(); diff --git a/docs/docs/07-examples/13-api-gateway.md b/docs/docs/07-examples/13-api-gateway.md index 7e6f34a6c26..f1083192e2a 100644 --- a/docs/docs/07-examples/13-api-gateway.md +++ b/docs/docs/07-examples/13-api-gateway.md @@ -5,7 +5,7 @@ keywords: [Wing example] --- ### Creating routes -```js playground +```js playground example bring cloud; let api = new cloud.Api(); @@ -37,7 +37,7 @@ api.delete("/", inflight (request: cloud.ApiRequest): cloud.ApiResponse => { ``` ### Path parameters -```js playground +```js playground example bring cloud; let api = new cloud.Api(); @@ -55,7 +55,7 @@ api.get("/items/:id/:value", inflight (req: cloud.ApiRequest): cloud.ApiResponse ``` ### Json body -```js playground +```js playground example bring cloud; let api = new cloud.Api(); diff --git a/docs/docs/07-examples/80-singletons.md b/docs/docs/07-examples/80-singletons.md index afb230953b4..b4f5f8a6317 100644 --- a/docs/docs/07-examples/80-singletons.md +++ b/docs/docs/07-examples/80-singletons.md @@ -10,7 +10,7 @@ a pattern for how to implement singletons in Wing. As an example, say we want to maintain a central bucket that can be accessed from any part of the application: -```js playground +```js playground example bring cloud; class SingletonBucket { diff --git a/docs/package-lock.json b/docs/package-lock.json new file mode 100644 index 00000000000..2c53c36929a --- /dev/null +++ b/docs/package-lock.json @@ -0,0 +1,113 @@ +{ + "name": "@winglang/docs", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@winglang/docs", + "version": "0.0.0", + "devDependencies": { + "@types/node": "^20.14.0", + "tsx": "^4.11.2", + "typescript": "^5.4.5" + } + }, + "../node_modules/.pnpm/tsx@4.11.2/node_modules/tsx": { + "version": "4.11.2", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.20.2", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "../node_modules/.pnpm/typescript@5.4.5/node_modules/typescript": { + "version": "5.4.5", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "devDependencies": { + "@esfx/canceltoken": "^1.0.0", + "@octokit/rest": "^20.0.2", + "@types/chai": "^4.3.11", + "@types/glob": "^8.1.0", + "@types/microsoft__typescript-etw": "^0.1.3", + "@types/minimist": "^1.2.5", + "@types/mocha": "^10.0.6", + "@types/ms": "^0.7.34", + "@types/node": "latest", + "@types/source-map-support": "^0.5.10", + "@types/which": "^3.0.3", + "@typescript-eslint/eslint-plugin": "^6.19.0", + "@typescript-eslint/parser": "^6.19.0", + "@typescript-eslint/utils": "^6.19.0", + "azure-devops-node-api": "^12.3.0", + "c8": "^9.1.0", + "chai": "^4.4.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "diff": "^5.1.0", + "dprint": "^0.45.0", + "esbuild": "^0.20.0", + "eslint": "^8.56.0", + "eslint-formatter-autolinkable-stylish": "^1.3.0", + "eslint-plugin-local": "^3.1.0", + "eslint-plugin-no-null": "^1.0.2", + "eslint-plugin-simple-import-sort": "^10.0.0", + "fast-xml-parser": "^4.3.3", + "glob": "^10.3.10", + "hereby": "^1.8.9", + "jsonc-parser": "^3.2.0", + "minimist": "^1.2.8", + "mocha": "^10.2.0", + "mocha-fivemat-progress-reporter": "^0.1.0", + "ms": "^2.1.3", + "node-fetch": "^3.3.2", + "playwright": "^1.41.0", + "source-map-support": "^0.5.21", + "tslib": "^2.6.2", + "typescript": "5.4.0-dev.20240119", + "which": "^3.0.1" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@types/node": { + "version": "20.14.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.0.tgz", + "integrity": "sha512-5cHBxFGJx6L4s56Bubp4fglrEpmyJypsqI6RgzMfBHWUJQGWAAi8cWcgetEbZXHYXo9C2Fa4EEds/uSyS4cxmA==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/tsx": { + "resolved": "../node_modules/.pnpm/tsx@4.11.2/node_modules/tsx", + "link": true + }, + "node_modules/typescript": { + "resolved": "../node_modules/.pnpm/typescript@5.4.5/node_modules/typescript", + "link": true + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + } + } +} diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 00000000000..6a0f5406386 --- /dev/null +++ b/docs/package.json @@ -0,0 +1,17 @@ +{ + "name": "@winglang/docs", + "version": "0.0.0", + "author": { + "name": "Wing Cloud", + "email": "ping@wing.cloud", + "organization": true + }, + "scripts": { + "compile": "tsx src/generate_examples_files.ts" + }, + "devDependencies": { + "@types/node": "^20.14.0", + "tsx": "^4.11.2", + "typescript": "^5.4.5" + } +} diff --git a/docs/src/generate_examples_files.ts b/docs/src/generate_examples_files.ts new file mode 100644 index 00000000000..d1af13890e7 --- /dev/null +++ b/docs/src/generate_examples_files.ts @@ -0,0 +1,93 @@ +import * as fs from 'fs'; +import { join } from 'path'; +import { docsRoot, testDir } from "../../tools/hangar/src/paths"; + +/** + * TODO: Support the following types of examples: + * - Examples that require importing other examples + * - Examples that require `wing.toml` + * - TypeScript examples + * - Website examples (need to generate some dummy static site config) + * - Examples that should only be tested on specific target platforms + */ +export interface ExampleMetadata { + /** @default true */ + valid: boolean; + name?: string; // We might be able to use this for matching dependant examples on each other +} + +export interface Example { + code: string; + filePath: string; + exampleNumber: number; + metadata: ExampleMetadata; +} + +const docExamplesDir = join(testDir, 'doc_examples'); + +export function findExamples(directory: string): Example[] { + const items = fs.readdirSync(directory, { withFileTypes: true }); + let examples: Example[] = []; + for (const item of items) { + const fullPath = join(directory, item.name); + if (item.isDirectory()) { + examples.push(...findExamples(fullPath)); // Recurse into subdirectories + } else if (item.isFile() && fullPath.endsWith('.md')) { + examples.push(...extractExamples(fullPath)); + } + } + return examples; +} + +export function extractExamples(filePath: string): Example[] { + const content = fs.readFileSync(filePath, 'utf8'); + const exampleCodeBlocks = content.match(/```.*? example.*?\n([\s\S]*?)```/g); + let examples: Example[] = []; + if (exampleCodeBlocks) { + exampleCodeBlocks.forEach((block, index) => { + const metaDataMatch = block.match(/```.*? example(\{[^}]+\})/); + let metadata: ExampleMetadata | undefined = undefined; + try { + if (metaDataMatch) { + const metaDataString = metaDataMatch[1] + .replace(/([a-zA-Z0-9_]+)\s*:/g, '"$1":') // Enclose property names in double quotes + .replace(/'/g, '"'); // Replace single quotes with double quotes if any + metadata = JSON.parse(metaDataString); + } + } catch (e) { + console.error(`Unable to parse metadata for example #${index + 1} in ${filePath}`, e); + } + const code = block.match(/```.*?\n([\s\S]*?)```/)![1]; + examples.push({ + code, + filePath, + exampleNumber: index + 1, + metadata: { + valid: true, + ...metadata + } + }); + }); + } + return examples; +} + +function generateTestsFromDocExamples(): void { + + const examples = findExamples(docsRoot); + examples.forEach((example) => { + const testName = `${example.filePath.split('/').pop()}_example_${example.exampleNumber}`; + + // For debug sake we add metadata as a comment to the code + example.code = `// Example metadata: ${JSON.stringify(example.metadata)}\n${example.code}`; + + example.code = `// This file was auto generated from an example found in: ${testName}\n${example.code}` + const outDir = join(docExamplesDir, example.metadata?.valid ? 'valid' : 'invalid', testName); + fs.mkdirSync(outDir, { recursive: true }); + fs.writeFileSync(join(outDir, 'main.w'), example.code); + }); +} + +fs.rmSync(join(docExamplesDir, "invalid"), { recursive: true, force: true }); +fs.rmSync(join(docExamplesDir, "valid"), { recursive: true, force: true }); +generateTestsFromDocExamples(); \ No newline at end of file diff --git a/docs/turbo.json b/docs/turbo.json new file mode 100644 index 00000000000..37f8ad2ee68 --- /dev/null +++ b/docs/turbo.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://turborepo.org/schema.json", + "extends": ["//"], + "pipeline": { + "compile": { + "inputs": [ + "./docs/**/*.md" + ], + "outputs": [ + "../examples/tests/doc_examples/**/*.w" + ] + } + } +} \ No newline at end of file diff --git a/examples/tests/doc_examples/.gitattributes b/examples/tests/doc_examples/.gitattributes new file mode 100644 index 00000000000..47a8c155a40 --- /dev/null +++ b/examples/tests/doc_examples/.gitattributes @@ -0,0 +1 @@ +*.w linguist-generated \ No newline at end of file diff --git a/examples/tests/doc_examples/invalid/01-preflight-and-inflight.md_example_12/main.w b/examples/tests/doc_examples/invalid/01-preflight-and-inflight.md_example_12/main.w new file mode 100644 index 00000000000..a97d34980bd --- /dev/null +++ b/examples/tests/doc_examples/invalid/01-preflight-and-inflight.md_example_12/main.w @@ -0,0 +1,12 @@ +// This file was auto generated from an example found in: 01-preflight-and-inflight.md_example_12 +// Example metadata: {"valid":false} +let var count = 3; +let names = MutArray["John", "Jane", "Joe"]; + +count = count + 1; // OK +names.push("Jack"); // OK + +inflight () => { + count = count + 1; // error: Variable cannot be reassigned from inflight + names.push("Jill"); // error: push doesn't exist in Array +}; diff --git a/examples/tests/doc_examples/invalid/01-preflight-and-inflight.md_example_15/main.w b/examples/tests/doc_examples/invalid/01-preflight-and-inflight.md_example_15/main.w new file mode 100644 index 00000000000..7a555bd62fd --- /dev/null +++ b/examples/tests/doc_examples/invalid/01-preflight-and-inflight.md_example_15/main.w @@ -0,0 +1,13 @@ +// This file was auto generated from an example found in: 01-preflight-and-inflight.md_example_15 +// Example metadata: {"valid":false} +bring cloud; +let main_bucket = new cloud.Bucket() as "main"; +let secondary_bucket = new cloud.Bucket() as "backup"; +let use_main = true; +new cloud.Function(inflight () => { + let var b = main_bucket; + if !use_main { + b = secondary_bucket; + } + b.put("key", "value"); // Error: the compiler doesn't know the possible values for `b` and therefore can't qualify the lift. +}); diff --git a/examples/tests/doc_examples/invalid/01-preflight-and-inflight.md_example_7/main.w b/examples/tests/doc_examples/invalid/01-preflight-and-inflight.md_example_7/main.w new file mode 100644 index 00000000000..2ba226aaf82 --- /dev/null +++ b/examples/tests/doc_examples/invalid/01-preflight-and-inflight.md_example_7/main.w @@ -0,0 +1,9 @@ +// This file was auto generated from an example found in: 01-preflight-and-inflight.md_example_7 +// Example metadata: {"valid":false} +bring cloud; + +let bucket = new cloud.Bucket(); + +let saveCalculation = inflight () => { + bucket.addObject("file1", "{2 ** 10}"); // error: Cannot call into preflight phase while inflight +}; diff --git a/examples/tests/doc_examples/invalid/01-preflight-and-inflight.md_example_8/main.w b/examples/tests/doc_examples/invalid/01-preflight-and-inflight.md_example_8/main.w new file mode 100644 index 00000000000..7bf74636ade --- /dev/null +++ b/examples/tests/doc_examples/invalid/01-preflight-and-inflight.md_example_8/main.w @@ -0,0 +1,7 @@ +// This file was auto generated from an example found in: 01-preflight-and-inflight.md_example_8 +// Example metadata: {"valid":false} +bring cloud; + +inflight () => { + new cloud.Bucket(); // error: Cannot create preflight class "Bucket" in inflight phase +}; diff --git a/examples/tests/doc_examples/invalid/01-variable-declaration.md_example_1/main.w b/examples/tests/doc_examples/invalid/01-variable-declaration.md_example_1/main.w new file mode 100644 index 00000000000..fe1bf28f255 --- /dev/null +++ b/examples/tests/doc_examples/invalid/01-variable-declaration.md_example_1/main.w @@ -0,0 +1,4 @@ +// This file was auto generated from an example found in: 01-variable-declaration.md_example_1 +// Example metadata: {"valid":false} +let x = 12; +x = 77; // error: Variable is not reassignable diff --git a/examples/tests/doc_examples/invalid/01-variable-declaration.md_example_4/main.w b/examples/tests/doc_examples/invalid/01-variable-declaration.md_example_4/main.w new file mode 100644 index 00000000000..1894434fd78 --- /dev/null +++ b/examples/tests/doc_examples/invalid/01-variable-declaration.md_example_4/main.w @@ -0,0 +1,9 @@ +// This file was auto generated from an example found in: 01-variable-declaration.md_example_4 +// Example metadata: {"valid":false} +let var x1 = "Hello"; // type str, value "Hello" +let var x2: str = "Hello"; // same as above +let var x3: str? = "Hello"; // type str? (optional), value "Hello" +let var x4: str? = nil; // type str? (optional), value nil + +x1 = nil; // ERROR: Expected type to be "str", but got "nil" instead +x3 = nil; // OK (x3 is optional) diff --git a/examples/tests/doc_examples/invalid/04-tests.md_example_5/main.w b/examples/tests/doc_examples/invalid/04-tests.md_example_5/main.w new file mode 100644 index 00000000000..b0da4713678 --- /dev/null +++ b/examples/tests/doc_examples/invalid/04-tests.md_example_5/main.w @@ -0,0 +1,21 @@ +// This file was auto generated from an example found in: 04-tests.md_example_5 +// Example metadata: {"valid":false} +// example.w +bring cloud; + +let b = new cloud.Bucket(); + +test "bucket list should include created file" { + b.put("file", "lorem ipsum"); + let listOfFile = b.list(); + assert(listOfFile.length == 1); +} + +test "bucket starts empty" { + let listOfFile = b.list(); + assert(listOfFile.length == 0); +} + +test "this test should fail" { + throw("test throws an exception fails"); +} diff --git a/examples/tests/doc_examples/package.json b/examples/tests/doc_examples/package.json new file mode 100644 index 00000000000..de3b80ab5fd --- /dev/null +++ b/examples/tests/doc_examples/package.json @@ -0,0 +1,6 @@ +{ + "name": "examples-docs", + "volta": { + "extends": "../../../package.json" + } +} \ No newline at end of file diff --git a/examples/tests/doc_examples/turbo.json b/examples/tests/doc_examples/turbo.json new file mode 100644 index 00000000000..af4cba7052e --- /dev/null +++ b/examples/tests/doc_examples/turbo.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://turborepo.org/schema.json", + "extends": ["//"], + "pipeline": { + "topo": {} + } +} diff --git a/examples/tests/doc_examples/valid/00-cloud-oriented-programming.md_example_1/main.w b/examples/tests/doc_examples/valid/00-cloud-oriented-programming.md_example_1/main.w new file mode 100644 index 00000000000..85addff0931 --- /dev/null +++ b/examples/tests/doc_examples/valid/00-cloud-oriented-programming.md_example_1/main.w @@ -0,0 +1,13 @@ +// This file was auto generated from an example found in: 00-cloud-oriented-programming.md_example_1 +// Example metadata: {"valid":true} +bring cloud; + +let queue = new cloud.Queue(timeout: 2m); +let bucket = new cloud.Bucket(); +let counter = new cloud.Counter(initial: 100); + +queue.setConsumer(inflight (body: str) => { + let next = counter.inc(); + let key = "myfile-{next}.txt"; + bucket.put(key, body); +}); diff --git a/examples/tests/doc_examples/valid/01-cli.md_example_1/main.w b/examples/tests/doc_examples/valid/01-cli.md_example_1/main.w new file mode 100644 index 00000000000..73653995db7 --- /dev/null +++ b/examples/tests/doc_examples/valid/01-cli.md_example_1/main.w @@ -0,0 +1,16 @@ +// This file was auto generated from an example found in: 01-cli.md_example_1 +// Example metadata: {"valid":true} +bring cloud; + +let b = new cloud.Bucket(); + +test "put" { + assert(b.list().length == 0); + b.put("hello.txt", "world"); + assert(b.list().length == 1); +} + +test "get" { + b.put("hello.txt", "world"); + assert(b.get("hello.txt") == "world"); +} diff --git a/examples/tests/doc_examples/valid/01-cli.md_example_2/main.w b/examples/tests/doc_examples/valid/01-cli.md_example_2/main.w new file mode 100644 index 00000000000..fe6d5da8e1a --- /dev/null +++ b/examples/tests/doc_examples/valid/01-cli.md_example_2/main.w @@ -0,0 +1,6 @@ +// This file was auto generated from an example found in: 01-cli.md_example_2 +// Example metadata: {"valid":true} +// main.w +bring cloud; + +let secret = new cloud.Secret(name: "slack-token"); diff --git a/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_1/main.w b/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_1/main.w new file mode 100644 index 00000000000..ada40bf07a0 --- /dev/null +++ b/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_1/main.w @@ -0,0 +1,5 @@ +// This file was auto generated from an example found in: 01-preflight-and-inflight.md_example_1 +// Example metadata: {"valid":true} +bring cloud; + +let bucket = new cloud.Bucket(); diff --git a/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_10/main.w b/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_10/main.w new file mode 100644 index 00000000000..f6748316a40 --- /dev/null +++ b/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_10/main.w @@ -0,0 +1,20 @@ +// This file was auto generated from an example found in: 01-preflight-and-inflight.md_example_10 +// Example metadata: {"valid":true} +inflight () => { + class Person { + name: str; + age: num; + + new(name: str, age: num) { + this.name = name; + this.age = age; + } + + pub inflight greet() { + log("Hello, {this.name}!"); + } + } + + let p = new Person("John", 30); + p.greet(); +}; diff --git a/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_11/main.w b/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_11/main.w new file mode 100644 index 00000000000..c8b4f4a6231 --- /dev/null +++ b/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_11/main.w @@ -0,0 +1,20 @@ +// This file was auto generated from an example found in: 01-preflight-and-inflight.md_example_11 +// Example metadata: {"valid":true} +bring cloud; +bring http; + +let api = new cloud.Api(); +api.get("/test", inflight (req: cloud.ApiRequest): cloud.ApiResponse => { + return cloud.ApiResponse { + status: 200, + body: "success!" + }; +}); + +let checkEndpoint = inflight () => { + let url = api.url; // this is OK + let path = "{url}/test"; + let response = http.get(path); + assert(response.status == 200); +}; +new cloud.Function(checkEndpoint); diff --git a/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_13/main.w b/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_13/main.w new file mode 100644 index 00000000000..c54983d5f1c --- /dev/null +++ b/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_13/main.w @@ -0,0 +1,6 @@ +// This file was auto generated from an example found in: 01-preflight-and-inflight.md_example_13 +// Example metadata: {"valid":true} +let preflight_str = "hello from preflight"; +inflight () => { + log(preflight_str); // `preflight_str` is "lifted" into inflight. +}; diff --git a/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_14/main.w b/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_14/main.w new file mode 100644 index 00000000000..6472626c36a --- /dev/null +++ b/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_14/main.w @@ -0,0 +1,7 @@ +// This file was auto generated from an example found in: 01-preflight-and-inflight.md_example_14 +// Example metadata: {"valid":true} +bring cloud; +let bucket = new cloud.Bucket(); +new cloud.Function(inflight () => { + bucket.put("key", "value"); // `bucket` is lifted and `put` is being used on it +}); diff --git a/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_2/main.w b/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_2/main.w new file mode 100644 index 00000000000..410ff2fe396 --- /dev/null +++ b/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_2/main.w @@ -0,0 +1,6 @@ +// This file was auto generated from an example found in: 01-preflight-and-inflight.md_example_2 +// Example metadata: {"valid":true} +bring cloud; + +let bucket = new cloud.Bucket(public: true); +bucket.addObject("file1.txt", "Hello world!"); diff --git a/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_3/main.w b/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_3/main.w new file mode 100644 index 00000000000..22689d607f8 --- /dev/null +++ b/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_3/main.w @@ -0,0 +1,4 @@ +// This file was auto generated from an example found in: 01-preflight-and-inflight.md_example_3 +// Example metadata: {"valid":true} +// hello.w +log("7 * 6 = {7 * 6}"); diff --git a/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_4/main.w b/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_4/main.w new file mode 100644 index 00000000000..b3179c0324e --- /dev/null +++ b/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_4/main.w @@ -0,0 +1,5 @@ +// This file was auto generated from an example found in: 01-preflight-and-inflight.md_example_4 +// Example metadata: {"valid":true} +let greeting = inflight () => { + log("Hello from the cloud!"); +}; diff --git a/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_5/main.w b/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_5/main.w new file mode 100644 index 00000000000..671ae114db2 --- /dev/null +++ b/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_5/main.w @@ -0,0 +1,10 @@ +// This file was auto generated from an example found in: 01-preflight-and-inflight.md_example_5 +// Example metadata: {"valid":true} +bring cloud; + +let bucket = new cloud.Bucket(); + +let firstObject = inflight (): str => { + let items = bucket.list(); + return items.at(0); +}; diff --git a/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_6/main.w b/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_6/main.w new file mode 100644 index 00000000000..e9805dd41d2 --- /dev/null +++ b/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_6/main.w @@ -0,0 +1,7 @@ +// This file was auto generated from an example found in: 01-preflight-and-inflight.md_example_6 +// Example metadata: {"valid":true} +bring cloud; + +let func = new cloud.Function(inflight () => { + log("Hello from the cloud!"); +}); diff --git a/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_9/main.w b/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_9/main.w new file mode 100644 index 00000000000..e175ec58fae --- /dev/null +++ b/examples/tests/doc_examples/valid/01-preflight-and-inflight.md_example_9/main.w @@ -0,0 +1,32 @@ +// This file was auto generated from an example found in: 01-preflight-and-inflight.md_example_9 +// Example metadata: {"valid":true} +bring cloud; + +class ReplayableQueue { + queue: cloud.Queue; + bucket: cloud.Bucket; + counter: cloud.Counter; + + new() { + this.queue = new cloud.Queue(); + this.bucket = new cloud.Bucket(); + this.counter = new cloud.Counter(); + } + + setConsumer(fn: inflight (str): str){ + this.queue.setConsumer(fn); + } + + inflight push(m: str) { + this.queue.push(m); + this.bucket.put("messages/{this.counter.inc()}", m); + } + + inflight replay(){ + for i in this.bucket.list() { + this.queue.push(this.bucket.get(i)); + } + } +} + +let rq = new ReplayableQueue(); diff --git a/examples/tests/doc_examples/valid/01-variable-declaration.md_example_2/main.w b/examples/tests/doc_examples/valid/01-variable-declaration.md_example_2/main.w new file mode 100644 index 00000000000..3ea48d09629 --- /dev/null +++ b/examples/tests/doc_examples/valid/01-variable-declaration.md_example_2/main.w @@ -0,0 +1,4 @@ +// This file was auto generated from an example found in: 01-variable-declaration.md_example_2 +// Example metadata: {"valid":true} +let var y = "hello"; +y = "world"; // OK (y is reassignable) diff --git a/examples/tests/doc_examples/valid/01-variable-declaration.md_example_3/main.w b/examples/tests/doc_examples/valid/01-variable-declaration.md_example_3/main.w new file mode 100644 index 00000000000..d9ef2be947c --- /dev/null +++ b/examples/tests/doc_examples/valid/01-variable-declaration.md_example_3/main.w @@ -0,0 +1,4 @@ +// This file was auto generated from an example found in: 01-variable-declaration.md_example_3 +// Example metadata: {"valid":true} +let x1 = 12; +let x2: num = 12; // equivalent diff --git a/examples/tests/doc_examples/valid/01-variable-declaration.md_example_5/main.w b/examples/tests/doc_examples/valid/01-variable-declaration.md_example_5/main.w new file mode 100644 index 00000000000..7b3968d7f14 --- /dev/null +++ b/examples/tests/doc_examples/valid/01-variable-declaration.md_example_5/main.w @@ -0,0 +1,9 @@ +// This file was auto generated from an example found in: 01-variable-declaration.md_example_5 +// Example metadata: {"valid":true} +let s = "parent"; +log(s); // prints parent +if true { + let s = "inner"; + log(s); // prints inner +} +log(s); // prints parent diff --git a/examples/tests/doc_examples/valid/02-application-tree.md_example_1/main.w b/examples/tests/doc_examples/valid/02-application-tree.md_example_1/main.w new file mode 100644 index 00000000000..49e0dcd93c0 --- /dev/null +++ b/examples/tests/doc_examples/valid/02-application-tree.md_example_1/main.w @@ -0,0 +1,6 @@ +// This file was auto generated from an example found in: 02-application-tree.md_example_1 +// Example metadata: {"valid":true} +bring cloud; + +let bucket1 = new cloud.Bucket(); // default name is "cloud.Bucket" +let bucket2 = new cloud.Bucket() as "my-bucket"; diff --git a/examples/tests/doc_examples/valid/02-application-tree.md_example_2/main.w b/examples/tests/doc_examples/valid/02-application-tree.md_example_2/main.w new file mode 100644 index 00000000000..8b263f3c448 --- /dev/null +++ b/examples/tests/doc_examples/valid/02-application-tree.md_example_2/main.w @@ -0,0 +1,19 @@ +// This file was auto generated from an example found in: 02-application-tree.md_example_2 +// Example metadata: {"valid":true} +bring cloud; + +class Group1 { + new() { + new cloud.Bucket() as "Store"; + } +} + +class Group2 { + new() { + new cloud.Bucket() as "Store"; + } +} + +// The following is valid +new Group1(); +new Group2(); diff --git a/examples/tests/doc_examples/valid/02-application-tree.md_example_3/main.w b/examples/tests/doc_examples/valid/02-application-tree.md_example_3/main.w new file mode 100644 index 00000000000..717c1b89ae6 --- /dev/null +++ b/examples/tests/doc_examples/valid/02-application-tree.md_example_3/main.w @@ -0,0 +1,22 @@ +// This file was auto generated from an example found in: 02-application-tree.md_example_3 +// Example metadata: {"valid":true} +class ThumbnailBucket { + //... +} + +class ImageStorage { + new() { + new ThumbnailBucket(); // This ThumbnailBucket will be a child of a ImageStorage instance in the construct tree + } +} + +new ImageStorage(); // This ImageStorage will be a child of the root in the construct tree +new ThumbnailBucket(); // This Counter will be a child of of the root in the construct tree + +// Here's a tree view of the generated infrastructure: +// +// root +// /\ +// ImageStorage ThumbnailBucket +// / +// ThumbnailBucket diff --git a/examples/tests/doc_examples/valid/02-application-tree.md_example_4/main.w b/examples/tests/doc_examples/valid/02-application-tree.md_example_4/main.w new file mode 100644 index 00000000000..9be060e9cc3 --- /dev/null +++ b/examples/tests/doc_examples/valid/02-application-tree.md_example_4/main.w @@ -0,0 +1,6 @@ +// This file was auto generated from an example found in: 02-application-tree.md_example_4 +// Example metadata: {"valid":true} +bring cloud; + +let b = new cloud.Bucket(); +log(nodeof(b).path); // Will log something like "/root/Bucket" diff --git a/examples/tests/doc_examples/valid/02-application-tree.md_example_5/main.w b/examples/tests/doc_examples/valid/02-application-tree.md_example_5/main.w new file mode 100644 index 00000000000..6b98f40a0cf --- /dev/null +++ b/examples/tests/doc_examples/valid/02-application-tree.md_example_5/main.w @@ -0,0 +1,22 @@ +// This file was auto generated from an example found in: 02-application-tree.md_example_5 +// Example metadata: {"valid":true} +class ThumbnailBucket { + //... +} + +class ImageStorage { + new() { + new ThumbnailBucket(); // This ThumbnailBucket will be a child of a ImageStorage instance in the construct tree + } +} + +let imageStorage = new ImageStorage(); // This goes in root +let defaultThumbnails = new ThumbnailBucket() as "defaultThumbs" in imageStorage; // This is explicitly named "defaultThumbs" and explicitly placed inside imageStorage + +// Here's a tree view of the generated infrastructure: +// +// root +// / +// ImageStorage +// / \ +// ThumbnailBucket defaultsThumbs diff --git a/examples/tests/doc_examples/valid/02-application-tree.md_example_6/main.w b/examples/tests/doc_examples/valid/02-application-tree.md_example_6/main.w new file mode 100644 index 00000000000..56895e2c3ee --- /dev/null +++ b/examples/tests/doc_examples/valid/02-application-tree.md_example_6/main.w @@ -0,0 +1,23 @@ +// This file was auto generated from an example found in: 02-application-tree.md_example_6 +// Example metadata: {"valid":true} +bring cloud; + +class Factory { + pub static make() { + new cloud.Bucket(); // We're in a static, so we don't know where to place this bucket + } +} + +class MyBucket { + new() { + Factory.make(); // Bucket will be placed inside `this` instance of `MyBucket` + } +} +new MyBucket(); + +// tree: +// root +// / +// MyBucket +// / +// Bucket diff --git a/examples/tests/doc_examples/valid/02-application-tree.md_example_7/main.w b/examples/tests/doc_examples/valid/02-application-tree.md_example_7/main.w new file mode 100644 index 00000000000..c7e0b6047e7 --- /dev/null +++ b/examples/tests/doc_examples/valid/02-application-tree.md_example_7/main.w @@ -0,0 +1,18 @@ +// This file was auto generated from an example found in: 02-application-tree.md_example_7 +// Example metadata: {"valid":true} +bring cloud; + +class Base { + new(b: cloud.Bucket) {} +} +class Derived extends Base { + new() { + super(new cloud.Bucket()); // Bucket create before `Derived` so scope defaults to caller + } +} +new Derived(); + +// tree: +// root +// /\ +// Bucket Derived diff --git a/examples/tests/doc_examples/valid/02-getting-started.md_example_1/main.w b/examples/tests/doc_examples/valid/02-getting-started.md_example_1/main.w new file mode 100644 index 00000000000..091d8d21fc8 --- /dev/null +++ b/examples/tests/doc_examples/valid/02-getting-started.md_example_1/main.w @@ -0,0 +1,22 @@ +// This file was auto generated from an example found in: 02-getting-started.md_example_1 +// Example metadata: {"valid":true} +bring cloud; + +// define a queue, a bucket and a counter +let bucket = new cloud.Bucket(); +let counter = new cloud.Counter(initial: 1); +let queue = new cloud.Queue(); + +// When a message is received in the queue it should be consumed +// by the following closure +queue.setConsumer(inflight (message: str) => { + // Increment the distributed counter, the index variable will + // store the value prior to the increment + let index = counter.inc(); + // Once two messages are pushed to the queue, e.g. "Wing" and "Queue". + // Two files will be created: + // - wing-1.txt with "Hello Wing" + // - wing-2.txt with "Hello Queue" + bucket.put("wing-{index}.txt", "Hello, {message}"); + log("file wing-{index}.txt created"); +}); diff --git a/examples/tests/doc_examples/valid/02-primitives.md_example_1/main.w b/examples/tests/doc_examples/valid/02-primitives.md_example_1/main.w new file mode 100644 index 00000000000..0cdb9a21d0a --- /dev/null +++ b/examples/tests/doc_examples/valid/02-primitives.md_example_1/main.w @@ -0,0 +1,8 @@ +// This file was auto generated from an example found in: 02-primitives.md_example_1 +// Example metadata: {"valid":true} +let s1 = "Hello Wing String"; +log(s1); // prints Hello Wing String +let s2 = "Interpolate: {s1}"; // string interpolation +log(s2); // prints Interpolate Hello Wing String +let s3 = "Concat: " + s1; // string concatenation +log(s3); // prints Concat: Hello Wing String diff --git a/examples/tests/doc_examples/valid/02-primitives.md_example_2/main.w b/examples/tests/doc_examples/valid/02-primitives.md_example_2/main.w new file mode 100644 index 00000000000..5535f0a4670 --- /dev/null +++ b/examples/tests/doc_examples/valid/02-primitives.md_example_2/main.w @@ -0,0 +1,25 @@ +// This file was auto generated from an example found in: 02-primitives.md_example_2 +// Example metadata: {"valid":true} +let s = "Hello to a new Wing world"; + +// lets start with split +for w in s.split(" ") { + if w.startsWith("H") { + log(w); // 'Hello' starts with H + } + if w.length > 3 && w.lowercase() == w { + log(w); // 'world' is lowercased with more then 3 chars + } + if w.contains("in") && w.endsWith("g") { + log(w); // 'Wing' has in and end with g + } + if s.indexOf(w) == 6 { + log(w); // 'to' position is 6 + } + if s.at(9) == w { + log(w); // 'a' is a single char + } + if s.substring(11,14) == w { + log(w); // 'new' position is 11-14 + } +} diff --git a/examples/tests/doc_examples/valid/02-primitives.md_example_3/main.w b/examples/tests/doc_examples/valid/02-primitives.md_example_3/main.w new file mode 100644 index 00000000000..b8d9fe60c56 --- /dev/null +++ b/examples/tests/doc_examples/valid/02-primitives.md_example_3/main.w @@ -0,0 +1,19 @@ +// This file was auto generated from an example found in: 02-primitives.md_example_3 +// Example metadata: {"valid":true} +let n1 = 10; +log("{n1}"); // 10 + +let n2 = n1 - 10 / 10 + 1 * 10 ; // arithmetic +log("{n2}"); // 1 + +let n3 = 10 % 7; // modulo +log("{n3}"); // 3 + +let n4 = 10 \ 7; // FloorDiv +log("{n4}"); // 1 + +let n5 = 2 ** 10; // power of +log("{n5}"); // 1024 + +let n6 = (10 + 1) / (12 - 1) + (20 / 2) * 2 + 10 * 2**10 / 512 + 1; +log("{n6}"); // The meaning of the universe diff --git a/examples/tests/doc_examples/valid/02-primitives.md_example_4/main.w b/examples/tests/doc_examples/valid/02-primitives.md_example_4/main.w new file mode 100644 index 00000000000..c9dbf43d252 --- /dev/null +++ b/examples/tests/doc_examples/valid/02-primitives.md_example_4/main.w @@ -0,0 +1,8 @@ +// This file was auto generated from an example found in: 02-primitives.md_example_4 +// Example metadata: {"valid":true} +let b1 = true; +let b2 = false; + +if b1 && !b2 { + log("b1:{b1},b2:{b2}"); // prints b1:true, b2:false +} diff --git a/examples/tests/doc_examples/valid/03-functions.md_example_1/main.w b/examples/tests/doc_examples/valid/03-functions.md_example_1/main.w new file mode 100644 index 00000000000..57ccb08f10b --- /dev/null +++ b/examples/tests/doc_examples/valid/03-functions.md_example_1/main.w @@ -0,0 +1,6 @@ +// This file was auto generated from an example found in: 03-functions.md_example_1 +// Example metadata: {"valid":true} +// preflight function - when declared in preflight context +let dup = (s: str, count: num) => { + // code +}; diff --git a/examples/tests/doc_examples/valid/03-functions.md_example_2/main.w b/examples/tests/doc_examples/valid/03-functions.md_example_2/main.w new file mode 100644 index 00000000000..a7ca33ea8a9 --- /dev/null +++ b/examples/tests/doc_examples/valid/03-functions.md_example_2/main.w @@ -0,0 +1,13 @@ +// This file was auto generated from an example found in: 03-functions.md_example_2 +// Example metadata: {"valid":true} + +let handler = inflight (message: str): void => { + // using the inflight modifier + let dup = inflight (s: str, count: num) => { + // code + }; + // inflight modifier is not required when function is declared in inflight context + let sup = (s: str, count: num) => { + // code + }; +}; diff --git a/examples/tests/doc_examples/valid/03-functions.md_example_3/main.w b/examples/tests/doc_examples/valid/03-functions.md_example_3/main.w new file mode 100644 index 00000000000..4b7db9fa5c9 --- /dev/null +++ b/examples/tests/doc_examples/valid/03-functions.md_example_3/main.w @@ -0,0 +1,17 @@ +// This file was auto generated from an example found in: 03-functions.md_example_3 +// Example metadata: {"valid":true} +struct Options { + prefix: str?; + delim: str; +} + +let join_str = (a: Array, opts: Options):str => { + let prefix = opts.prefix ?? ""; + return prefix + a.join(opts.delim); +}; + +log(join_str(["hello", "world"], delim: ", ")); // "!hello.world" + +// also OK to pass an object +let opts = Options { delim: "/" , prefix: "!!" }; +log(join_str(["hello", "world"], opts)); // "!!hello/world"); diff --git a/examples/tests/doc_examples/valid/03-platforms.md_example_1/main.w b/examples/tests/doc_examples/valid/03-platforms.md_example_1/main.w new file mode 100644 index 00000000000..3cfeab86f0b --- /dev/null +++ b/examples/tests/doc_examples/valid/03-platforms.md_example_1/main.w @@ -0,0 +1,26 @@ +// This file was auto generated from an example found in: 03-platforms.md_example_1 +// Example metadata: {"valid":true} +bring cloud; +bring util; + +let invocationCounter = new cloud.Counter(); +let queue = new cloud.Queue(); + +queue.setConsumer(inflight (msg: str) => { + invocationCounter.inc(); +}); + +new cloud.Function(inflight ()=> { + // push a message to queue + queue.push("m"); + // sleep according to target + if util.env("WING_TARGET") == "sim" { + log("Running on Simulator, sleeping for 1s"); + util.sleep(1s); + } else { + log("Running on the cloud, sleeping for 30s"); + util.sleep(30s); + } + log("Function invoked {invocationCounter.peek()} times"); +}); + diff --git a/examples/tests/doc_examples/valid/04-flow-controls.md_example_1/main.w b/examples/tests/doc_examples/valid/04-flow-controls.md_example_1/main.w new file mode 100644 index 00000000000..94383efc82b --- /dev/null +++ b/examples/tests/doc_examples/valid/04-flow-controls.md_example_1/main.w @@ -0,0 +1,22 @@ +// This file was auto generated from an example found in: 04-flow-controls.md_example_1 +// Example metadata: {"valid":true} +let iterable = ["a", "b", "c", "d", "e", "f", "g", "h"]; +for value in iterable { + if value == "g" { + // stopping at g + break; + } + if value == "b" { + // skipping b + continue; + } + log(value); +} +/** + * prints + a + c + d + e + f +**/ diff --git a/examples/tests/doc_examples/valid/04-flow-controls.md_example_2/main.w b/examples/tests/doc_examples/valid/04-flow-controls.md_example_2/main.w new file mode 100644 index 00000000000..9b83cbcd9bc --- /dev/null +++ b/examples/tests/doc_examples/valid/04-flow-controls.md_example_2/main.w @@ -0,0 +1,16 @@ +// This file was auto generated from an example found in: 04-flow-controls.md_example_2 +// Example metadata: {"valid":true} +// print numbers from 0 to 9 +for value in 0..10 { + log("{value}"); +} + +// prints numbers in reverse order from 10 to 0 +for value in 10..-1 { + log("{value}"); +} + +// include end +for value in 1..=5 { + log("{value}"); +} diff --git a/examples/tests/doc_examples/valid/04-flow-controls.md_example_3/main.w b/examples/tests/doc_examples/valid/04-flow-controls.md_example_3/main.w new file mode 100644 index 00000000000..c7281a6d58f --- /dev/null +++ b/examples/tests/doc_examples/valid/04-flow-controls.md_example_3/main.w @@ -0,0 +1,23 @@ +// This file was auto generated from an example found in: 04-flow-controls.md_example_3 +// Example metadata: {"valid":true} +let grade = (score: num): str => { + // Parentheses are optional in conditions. + // However, curly braces are required in `if/else` statements. + if 0 < score && score < 55 { + return "F"; + } elif 55 <= score && score < 65 { + return "C"; + } elif 65 <= score && score < 75 { + return "B"; + } elif 75 <= score && score <= 100 { + return "A"; + } else { + return "Invalid grade"; + } +}; + +log("54 is {grade(54)}"); // 54 is F +log("62 is {grade(62)}"); // 62 is C +log("68 is {grade(68)}"); // 68 is B +log("99 is {grade(99)}"); // 99 is A +log("101 is {grade(101)}"); // 101 is Invalid grade diff --git a/examples/tests/doc_examples/valid/04-flow-controls.md_example_4/main.w b/examples/tests/doc_examples/valid/04-flow-controls.md_example_4/main.w new file mode 100644 index 00000000000..b6e84150263 --- /dev/null +++ b/examples/tests/doc_examples/valid/04-flow-controls.md_example_4/main.w @@ -0,0 +1,28 @@ +// This file was auto generated from an example found in: 04-flow-controls.md_example_4 +// Example metadata: {"valid":true} +let var i = 0; +while i < 100 { + i = i + 1; + if i == 20 { + // although the while loop goes to 100, we break it at 20 + break; + } + if i % 2 == 0 { + // continue for even numbers + continue; + } + log("{i}"); +} +/** + * prints + 1 + 3 + 5 + 7 + 9 + 11 + 13 + 15 + 17 + 19 +**/ diff --git a/examples/tests/doc_examples/valid/04-tests.md_example_1/main.w b/examples/tests/doc_examples/valid/04-tests.md_example_1/main.w new file mode 100644 index 00000000000..0d07ac070af --- /dev/null +++ b/examples/tests/doc_examples/valid/04-tests.md_example_1/main.w @@ -0,0 +1,5 @@ +// This file was auto generated from an example found in: 04-tests.md_example_1 +// Example metadata: {"valid":true} +test "" { + // test code +} diff --git a/examples/tests/doc_examples/valid/04-tests.md_example_2/main.w b/examples/tests/doc_examples/valid/04-tests.md_example_2/main.w new file mode 100644 index 00000000000..86cc8f4fae6 --- /dev/null +++ b/examples/tests/doc_examples/valid/04-tests.md_example_2/main.w @@ -0,0 +1,8 @@ +// This file was auto generated from an example found in: 04-tests.md_example_2 +// Example metadata: {"valid":true} +// example.w +bring math; + +test "abs" { + assert(1 == math.abs(-1)); +} diff --git a/examples/tests/doc_examples/valid/04-tests.md_example_3/main.w b/examples/tests/doc_examples/valid/04-tests.md_example_3/main.w new file mode 100644 index 00000000000..139027f66f3 --- /dev/null +++ b/examples/tests/doc_examples/valid/04-tests.md_example_3/main.w @@ -0,0 +1,16 @@ +// This file was auto generated from an example found in: 04-tests.md_example_3 +// Example metadata: {"valid":true} +bring cloud; + +let b = new cloud.Bucket(); + +test "bucket list should include created file" { + b.put("file", "lorem ipsum"); + let listOfFile = b.list(); + assert(listOfFile.length == 1); +} + +test "bucket starts empty" { + let listOfFile = b.list(); + assert(listOfFile.length == 0); +} diff --git a/examples/tests/doc_examples/valid/04-tests.md_example_4/main.w b/examples/tests/doc_examples/valid/04-tests.md_example_4/main.w new file mode 100644 index 00000000000..1bb41c2b12b --- /dev/null +++ b/examples/tests/doc_examples/valid/04-tests.md_example_4/main.w @@ -0,0 +1,23 @@ +// This file was auto generated from an example found in: 04-tests.md_example_4 +// Example metadata: {"valid":true} +bring cloud; +bring util; + +let b = new cloud.Bucket(); +b.onCreate(inflight (key: str) => { + if !key.startsWith("/dest") { + let content = b.get(key); + b.put("/dest/" + key, content.uppercase()); + } +}); + +test "bucket onCreate" { + b.put("file", "lorem ipsum"); + // Using waitUntil for waiting until the async event system of onCreate + // finished generating a the dest/file + let foundUppercaseFile = util.waitUntil((): bool => { + return b.exists("/dest/file"); + }); + assert(foundUppercaseFile && b.get("/dest/file") == "LOREM IPSUM"); +} + diff --git a/examples/tests/doc_examples/valid/05-optionality.md_example_1/main.w b/examples/tests/doc_examples/valid/05-optionality.md_example_1/main.w new file mode 100644 index 00000000000..99c37bc9059 --- /dev/null +++ b/examples/tests/doc_examples/valid/05-optionality.md_example_1/main.w @@ -0,0 +1,4 @@ +// This file was auto generated from an example found in: 05-optionality.md_example_1 +// Example metadata: {"valid":true} +let s1: str? = "Hello"; // type str? (optional), value "Hello" +let s2: str? = nil; // type str? (optional), value nil diff --git a/examples/tests/doc_examples/valid/05-optionality.md_example_2/main.w b/examples/tests/doc_examples/valid/05-optionality.md_example_2/main.w new file mode 100644 index 00000000000..8ecc04906d5 --- /dev/null +++ b/examples/tests/doc_examples/valid/05-optionality.md_example_2/main.w @@ -0,0 +1,11 @@ +// This file was auto generated from an example found in: 05-optionality.md_example_2 +// Example metadata: {"valid":true} +let s1: str? = "Hello"; // type str? (optional), value "Hello" +let s2: str? = nil; // type str? (optional), value nil + +if s1? { + log("x1 is not nil"); +} +if !s2? { + log("x2 is nil"); +} diff --git a/examples/tests/doc_examples/valid/05-optionality.md_example_3/main.w b/examples/tests/doc_examples/valid/05-optionality.md_example_3/main.w new file mode 100644 index 00000000000..e4355080865 --- /dev/null +++ b/examples/tests/doc_examples/valid/05-optionality.md_example_3/main.w @@ -0,0 +1,18 @@ +// This file was auto generated from an example found in: 05-optionality.md_example_3 +// Example metadata: {"valid":true} +let s1: str? = "Hello"; // type str? (optional), value "Hello" + +// unwrap optional s1 and create s from type str +if let s = s1 { + log("s is not optional, value {s}"); +} else { + log("s1 was nil, s doesn't exists in this scope"); +} + +// same as above but shadowing s1 variable +if let s1 = s1 { + log("s1 type is str, value {s1}"); +} else { + log("s1 was nil"); +} +log("s1 type is optional str"); diff --git a/examples/tests/doc_examples/valid/05-optionality.md_example_4/main.w b/examples/tests/doc_examples/valid/05-optionality.md_example_4/main.w new file mode 100644 index 00000000000..f9589cfb47b --- /dev/null +++ b/examples/tests/doc_examples/valid/05-optionality.md_example_4/main.w @@ -0,0 +1,5 @@ +// This file was auto generated from an example found in: 05-optionality.md_example_4 +// Example metadata: {"valid":true} +let s1: str? = nil; // type str? (optional), value nil +let s2 = s1 ?? "default value"; // s2 is of type str +log(s2); // prints default value diff --git a/examples/tests/doc_examples/valid/05-optionality.md_example_5/main.w b/examples/tests/doc_examples/valid/05-optionality.md_example_5/main.w new file mode 100644 index 00000000000..1f906eb049c --- /dev/null +++ b/examples/tests/doc_examples/valid/05-optionality.md_example_5/main.w @@ -0,0 +1,20 @@ +// This file was auto generated from an example found in: 05-optionality.md_example_5 +// Example metadata: {"valid":true} +let j = Json { + working: { + a: { + b: "value" + } + }, + broken: {} +}; + +if let value = j.tryGet("working")?.tryGet("a")?.tryGet("b")?.tryAsStr() { + log("value is {value}"); +} + +if let value = j.tryGet("broken")?.tryGet("a")?.tryGet("b")?.tryAsStr() { + // not reachable +} else { + log("value was not found"); +} diff --git a/examples/tests/doc_examples/valid/05-optionality.md_example_6/main.w b/examples/tests/doc_examples/valid/05-optionality.md_example_6/main.w new file mode 100644 index 00000000000..0c6a751a5f1 --- /dev/null +++ b/examples/tests/doc_examples/valid/05-optionality.md_example_6/main.w @@ -0,0 +1,23 @@ +// This file was auto generated from an example found in: 05-optionality.md_example_6 +// Example metadata: {"valid":true} +let b3: bool? = false; + +if b3? { + log("although b3 is false, the if statement here checks for existence of value"); +} + +if let b3 = b3 { // unboxing b3 and shadowing original b3 + if b3 { + log("b3 is true"); + } else { + log("b3 is false"); + } +} else { + log("b3 is nil"); +} + +/** + * prints: + although b3 is false, the if statement here checks for existence of value + b3 is false +**/ diff --git a/examples/tests/doc_examples/valid/06-json.md_example_1/main.w b/examples/tests/doc_examples/valid/06-json.md_example_1/main.w new file mode 100644 index 00000000000..033b7e26cd3 --- /dev/null +++ b/examples/tests/doc_examples/valid/06-json.md_example_1/main.w @@ -0,0 +1,23 @@ +// This file was auto generated from an example found in: 06-json.md_example_1 +// Example metadata: {"valid":true} +let j = Json { + k1: 1, + k2: "hello", + k3: true, + k4: { + k1: [1, "a", true, {} ] + } +}; +log("{j}"); + +let jsonStrValue = Json "Hello"; +log("{jsonStrValue}"); + +let jsonNumValue = Json 42; +log("{jsonNumValue}"); + +let jsonBoolValue = Json true; +log("{jsonBoolValue}"); + +let jsonHomogeneousArrayValue = Json ["a", "b"]; +log("{jsonHomogeneousArrayValue}"); diff --git a/examples/tests/doc_examples/valid/06-json.md_example_2/main.w b/examples/tests/doc_examples/valid/06-json.md_example_2/main.w new file mode 100644 index 00000000000..82418742392 --- /dev/null +++ b/examples/tests/doc_examples/valid/06-json.md_example_2/main.w @@ -0,0 +1,12 @@ +// This file was auto generated from an example found in: 06-json.md_example_2 +// Example metadata: {"valid":true} +let x: num = 42; +let jsonNum = Json x; +log("{jsonNum}"); // 42 + +let chars = Array["a", "b"]; +let jsonChars = Json chars; +log("{jsonChars}"); // ["a","b"] + +let jsonComplex = Json { "first": x, "second": chars }; +log("{jsonComplex}"); // {"first": 42, "second": ["a","b"]} diff --git a/examples/tests/doc_examples/valid/06-json.md_example_3/main.w b/examples/tests/doc_examples/valid/06-json.md_example_3/main.w new file mode 100644 index 00000000000..04a1ca743aa --- /dev/null +++ b/examples/tests/doc_examples/valid/06-json.md_example_3/main.w @@ -0,0 +1,10 @@ +// This file was auto generated from an example found in: 06-json.md_example_3 +// Example metadata: {"valid":true} +let j = Json { + k1: "v1", + k2: "v2" +}; +for k in Json.keys(j) { + let value = j.get(k); + log("found key {k} with value {value}"); +} diff --git a/examples/tests/doc_examples/valid/06-json.md_example_4/main.w b/examples/tests/doc_examples/valid/06-json.md_example_4/main.w new file mode 100644 index 00000000000..9d51fe48328 --- /dev/null +++ b/examples/tests/doc_examples/valid/06-json.md_example_4/main.w @@ -0,0 +1,9 @@ +// This file was auto generated from an example found in: 06-json.md_example_4 +// Example metadata: {"valid":true} +let j = Json { + k1: "v1", + k2: "v2" +}; +for value in Json.values(j) { + log("found value {value}"); +} diff --git a/examples/tests/doc_examples/valid/06-json.md_example_5/main.w b/examples/tests/doc_examples/valid/06-json.md_example_5/main.w new file mode 100644 index 00000000000..f677769b9fa --- /dev/null +++ b/examples/tests/doc_examples/valid/06-json.md_example_5/main.w @@ -0,0 +1,6 @@ +// This file was auto generated from an example found in: 06-json.md_example_5 +// Example metadata: {"valid":true} +let arrayValue = Json ["a", "b", "c"]; +for v in Json.values(arrayValue) { + log(str.fromJson(v)); +} diff --git a/examples/tests/doc_examples/valid/06-json.md_example_6/main.w b/examples/tests/doc_examples/valid/06-json.md_example_6/main.w new file mode 100644 index 00000000000..b83d75c0243 --- /dev/null +++ b/examples/tests/doc_examples/valid/06-json.md_example_6/main.w @@ -0,0 +1,7 @@ +// This file was auto generated from an example found in: 06-json.md_example_6 +// Example metadata: {"valid":true} +let j = Json { + k: "hello" +}; + +log(j.get("k").asStr()); diff --git a/examples/tests/doc_examples/valid/06-json.md_example_7/main.w b/examples/tests/doc_examples/valid/06-json.md_example_7/main.w new file mode 100644 index 00000000000..20547f84dbc --- /dev/null +++ b/examples/tests/doc_examples/valid/06-json.md_example_7/main.w @@ -0,0 +1,6 @@ +// This file was auto generated from an example found in: 06-json.md_example_7 +// Example metadata: {"valid":true} +let j = Json { + k: 12 +}; +log("{j.get("k").asNum()}"); diff --git a/examples/tests/doc_examples/valid/06-json.md_example_8/main.w b/examples/tests/doc_examples/valid/06-json.md_example_8/main.w new file mode 100644 index 00000000000..c1fe2966aef --- /dev/null +++ b/examples/tests/doc_examples/valid/06-json.md_example_8/main.w @@ -0,0 +1,6 @@ +// This file was auto generated from an example found in: 06-json.md_example_8 +// Example metadata: {"valid":true} +let j = Json { + k:true +}; +log("{j.get("k").asBool()}"); diff --git a/examples/tests/doc_examples/valid/06-json.md_example_9/main.w b/examples/tests/doc_examples/valid/06-json.md_example_9/main.w new file mode 100644 index 00000000000..1e35a7912f0 --- /dev/null +++ b/examples/tests/doc_examples/valid/06-json.md_example_9/main.w @@ -0,0 +1,13 @@ +// This file was auto generated from an example found in: 06-json.md_example_9 +// Example metadata: {"valid":true} +struct Foo { + val1: str; + val2: num; +} + +let jFoo = { + val1: "cool", + val2: 21 +}; + +let foo = Foo.fromJson(jFoo); diff --git a/examples/tests/doc_examples/valid/07-structs.md_example_1/main.w b/examples/tests/doc_examples/valid/07-structs.md_example_1/main.w new file mode 100644 index 00000000000..ac77a1892a0 --- /dev/null +++ b/examples/tests/doc_examples/valid/07-structs.md_example_1/main.w @@ -0,0 +1,10 @@ +// This file was auto generated from an example found in: 07-structs.md_example_1 +// Example metadata: {"valid":true} +struct Example { + a: str; + b: num; + c: bool; +} + +let example = Example { a: "a", b: 0, c: false }; +log(example.a); // prints "a" diff --git a/examples/tests/doc_examples/valid/07-structs.md_example_2/main.w b/examples/tests/doc_examples/valid/07-structs.md_example_2/main.w new file mode 100644 index 00000000000..7ad7553d1c7 --- /dev/null +++ b/examples/tests/doc_examples/valid/07-structs.md_example_2/main.w @@ -0,0 +1,12 @@ +// This file was auto generated from an example found in: 07-structs.md_example_2 +// Example metadata: {"valid":true} +struct Example { + a: str?; + b: num?; + c: bool?; +} + +let example = Example { }; +if ! example.a? { + log("a is nil"); +} diff --git a/examples/tests/doc_examples/valid/07-structs.md_example_3/main.w b/examples/tests/doc_examples/valid/07-structs.md_example_3/main.w new file mode 100644 index 00000000000..97b1088b98b --- /dev/null +++ b/examples/tests/doc_examples/valid/07-structs.md_example_3/main.w @@ -0,0 +1,21 @@ +// This file was auto generated from an example found in: 07-structs.md_example_3 +// Example metadata: {"valid":true} +struct Another { + hello: str; +} + +struct MyData { + a: str; + b: num?; + c: Another; +} + +let data = MyData { + a: "hello", + c: Another { + hello: "two" + } +}; + +log(data.a); // prints hello +log(data.c.hello); // prints two diff --git a/examples/tests/doc_examples/valid/07-structs.md_example_4/main.w b/examples/tests/doc_examples/valid/07-structs.md_example_4/main.w new file mode 100644 index 00000000000..54867719c4c --- /dev/null +++ b/examples/tests/doc_examples/valid/07-structs.md_example_4/main.w @@ -0,0 +1,17 @@ +// This file was auto generated from an example found in: 07-structs.md_example_4 +// Example metadata: {"valid":true} +struct Options { + prefix: str?; + delim: str; +} + +let join_str = (a: Array, opts: Options):str => { + let prefix = opts.prefix ?? ""; + return prefix + a.join(opts.delim); +}; + +log(join_str(["hello", "world"], delim: ", ")); // "!hello.world" + +// also OK to pass an object +let opts = Options { delim: "," }; +log(join_str(["hello", "world"], opts)); // "!!hello/world"); diff --git a/examples/tests/doc_examples/valid/08-classes.md_example_1/main.w b/examples/tests/doc_examples/valid/08-classes.md_example_1/main.w new file mode 100644 index 00000000000..4dcab81f940 --- /dev/null +++ b/examples/tests/doc_examples/valid/08-classes.md_example_1/main.w @@ -0,0 +1,40 @@ +// This file was auto generated from an example found in: 08-classes.md_example_1 +// Example metadata: {"valid":true} +bring cloud; +bring util; + +class Foo { + pub field1: str; // <-- readonly + pub var field2: num; // <-- reassignable + inflight field3: Array; + + new() { + this.field1 = "hello"; + this.field2 = 123; + } + + setField2(value: num): void { + this.field2 = value; + } + + inflight new() { + this.field3 = ["value created on inflight init"]; + log("at inflight init"); + } + + pub inflight doStuff() { + // all code is async and runs on the cloud + log("field3[0]='{this.field3.at(0)}'"); + util.sleep(1s); + log("done"); + } +} + +let f = new Foo(); +log("field1={f.field1}"); +log("field2={f.field2}"); + +new cloud.Function(inflight () => { + f.doStuff(); +}); + diff --git a/examples/tests/doc_examples/valid/08-classes.md_example_2/main.w b/examples/tests/doc_examples/valid/08-classes.md_example_2/main.w new file mode 100644 index 00000000000..2d3401ba798 --- /dev/null +++ b/examples/tests/doc_examples/valid/08-classes.md_example_2/main.w @@ -0,0 +1,21 @@ +// This file was auto generated from an example found in: 08-classes.md_example_2 +// Example metadata: {"valid":true} +bring cloud; + +inflight interface IProfile { + inflight name(): str; +} + +inflight class WingPerson impl IProfile { + pub inflight name(): str { + return "Fairy Wing"; + } +} + +let logName = inflight(profile: IProfile): void => { + log(profile.name()); +}; + +new cloud.Function(inflight () => { + logName(new WingPerson()); +}); diff --git a/examples/tests/doc_examples/valid/08-classes.md_example_3/main.w b/examples/tests/doc_examples/valid/08-classes.md_example_3/main.w new file mode 100644 index 00000000000..f84b999927f --- /dev/null +++ b/examples/tests/doc_examples/valid/08-classes.md_example_3/main.w @@ -0,0 +1,24 @@ +// This file was auto generated from an example found in: 08-classes.md_example_3 +// Example metadata: {"valid":true} +bring cloud; +/** + * Preflight Interface + **/ +interface IKVStore extends std.IResource { // https://github.com/winglang/wing/issues/1961 + inflight get(key: str): Json; + inflight set(key: str, value: Json): void; +} + +class BucketBasedKeyValueStore impl IKVStore { + bucket: cloud.Bucket; + new() { + this.bucket = new cloud.Bucket(); + } + pub inflight get(key: str): Json { + return this.bucket.getJson(key); + } + pub inflight set(key: str, value: Json): void { + this.bucket.putJson(key, value); + } +} + diff --git a/examples/tests/doc_examples/valid/08-classes.md_example_4/main.w b/examples/tests/doc_examples/valid/08-classes.md_example_4/main.w new file mode 100644 index 00000000000..248a3276315 --- /dev/null +++ b/examples/tests/doc_examples/valid/08-classes.md_example_4/main.w @@ -0,0 +1,62 @@ +// This file was auto generated from an example found in: 08-classes.md_example_4 +// Example metadata: {"valid":true} +bring cloud; +bring ex; + +interface IKVStore extends std.IResource { + inflight get(key: str): Json; + inflight set(key: str, value: Json): void; +} + +class BucketBasedKeyValueStore impl IKVStore { + bucket: cloud.Bucket; + new() { + this.bucket = new cloud.Bucket(); + } + pub inflight get(key: str): Json { + return this.bucket.getJson(key); + } + pub inflight set(key: str, value: Json): void { + this.bucket.putJson(key, value); + } +} + +class TableBasedKeyValueStore impl IKVStore { + table: ex.Table; + new() { + this.table = new ex.Table( + name: "table", + primaryKey: "key", + columns: { + value: ex.ColumnType.STRING + } + ); + } + pub inflight get(key: str): Json { + return this.table.get(key); + } + pub inflight set(key: str, value: Json) { + this.table.insert(key, value); + } +} + +let bucketBased: IKVStore = new BucketBasedKeyValueStore(); +let tableBased: IKVStore = new TableBasedKeyValueStore(); + +test "bucketBased KVStore" { + bucketBased.set("k", Json { + value: "v" + }); + let result = bucketBased.get("k"); + log("{result.get("value")}"); + assert("v" == str.fromJson(result.get("value"))); +} + +test "tableBased KVStore" { + tableBased.set("k", Json { + value: "v" + }); + let result = tableBased.get("k"); + log("{result.get("value")}"); + assert("v" == str.fromJson(result.get("value"))); +} diff --git a/examples/tests/doc_examples/valid/10-using-javascript.md_example_1/main.w b/examples/tests/doc_examples/valid/10-using-javascript.md_example_1/main.w new file mode 100644 index 00000000000..900539f6a08 --- /dev/null +++ b/examples/tests/doc_examples/valid/10-using-javascript.md_example_1/main.w @@ -0,0 +1,9 @@ +// This file was auto generated from an example found in: 10-using-javascript.md_example_1 +// Example metadata: {"valid":true} +// main.w +bring cloud; +let bucket = new cloud.Bucket(); + +bucket.onCreate(inflight (file) => { + log(file); +}); diff --git a/examples/tests/doc_examples/valid/13-api-gateway.md_example_1/main.w b/examples/tests/doc_examples/valid/13-api-gateway.md_example_1/main.w new file mode 100644 index 00000000000..7fb3c783d3a --- /dev/null +++ b/examples/tests/doc_examples/valid/13-api-gateway.md_example_1/main.w @@ -0,0 +1,30 @@ +// This file was auto generated from an example found in: 13-api-gateway.md_example_1 +// Example metadata: {"valid":true} +bring cloud; + +let api = new cloud.Api(); + +api.get("/", inflight (request: cloud.ApiRequest): cloud.ApiResponse => { + return cloud.ApiResponse { + status: 200, + body: "Hello GET" + }; +}); +api.post("/", inflight (request: cloud.ApiRequest): cloud.ApiResponse => { + return cloud.ApiResponse { + status: 200, + body: "Hello POST" + }; +}); +api.put("/", inflight (request: cloud.ApiRequest): cloud.ApiResponse => { + return cloud.ApiResponse { + status: 200, body: + "Hello PUT" + }; +}); +api.delete("/", inflight (request: cloud.ApiRequest): cloud.ApiResponse => { + return cloud.ApiResponse { + status: 200, + body: "Hello DELETE" + }; +}); diff --git a/examples/tests/doc_examples/valid/13-api-gateway.md_example_2/main.w b/examples/tests/doc_examples/valid/13-api-gateway.md_example_2/main.w new file mode 100644 index 00000000000..c4fbe45e598 --- /dev/null +++ b/examples/tests/doc_examples/valid/13-api-gateway.md_example_2/main.w @@ -0,0 +1,16 @@ +// This file was auto generated from an example found in: 13-api-gateway.md_example_2 +// Example metadata: {"valid":true} +bring cloud; + +let api = new cloud.Api(); + +api.get("/items/:id/:value", inflight (req: cloud.ApiRequest): cloud.ApiResponse => { + let itemId = req.vars.get("id"); + let itemValue = req.vars.get("value"); + log("Received itemId:{itemId}, itemValue:{itemValue}"); + return cloud.ApiResponse { + status: 200, + body: "Received itemId:{itemId}, itemValue:{itemValue}" + }; +}); + diff --git a/examples/tests/doc_examples/valid/13-api-gateway.md_example_3/main.w b/examples/tests/doc_examples/valid/13-api-gateway.md_example_3/main.w new file mode 100644 index 00000000000..1615f1620e9 --- /dev/null +++ b/examples/tests/doc_examples/valid/13-api-gateway.md_example_3/main.w @@ -0,0 +1,19 @@ +// This file was auto generated from an example found in: 13-api-gateway.md_example_3 +// Example metadata: {"valid":true} +bring cloud; + +let api = new cloud.Api(); + +api.put("/items/:id", inflight (req: cloud.ApiRequest): cloud.ApiResponse => { + let itemId = req.vars.get("id"); + if let itemBody = Json.tryParse(req.body ?? "") { + return cloud.ApiResponse { + status: 200, + body: "Received id {itemId} with body {itemBody}" + }; + } + return cloud.ApiResponse { + status: 400, + body: "Missing body" + }; +}); diff --git a/examples/tests/doc_examples/valid/80-singletons.md_example_1/main.w b/examples/tests/doc_examples/valid/80-singletons.md_example_1/main.w new file mode 100644 index 00000000000..6a5433f182b --- /dev/null +++ b/examples/tests/doc_examples/valid/80-singletons.md_example_1/main.w @@ -0,0 +1,12 @@ +// This file was auto generated from an example found in: 80-singletons.md_example_1 +// Example metadata: {"valid":true} +bring cloud; + +class SingletonBucket { + pub static of(scope: std.IResource): cloud.Bucket { + let uid = "SingletonBucket"; + let root = nodeof(scope).root; + let rootNode = nodeof(root); + return unsafeCast(rootNode.tryFindChild(uid)) ?? new cloud.Bucket() as uid in root; + } +} diff --git a/examples/tests/doc_examples/valid/api.md_example_1/main.w b/examples/tests/doc_examples/valid/api.md_example_1/main.w new file mode 100644 index 00000000000..eb37179001b --- /dev/null +++ b/examples/tests/doc_examples/valid/api.md_example_1/main.w @@ -0,0 +1,70 @@ +// This file was auto generated from an example found in: api.md_example_1 +// Example metadata: {"valid":true} +bring cloud; +bring ex; + +let api = new cloud.Api(); +// Used for generating unique id +let counter = new cloud.Counter(); +// our employee database +let db = new ex.Table( + name: "employees", + primaryKey: "id", + columns: { + "name" => ex.ColumnType.STRING + } +); + +api.get("/employees", inflight (request: cloud.ApiRequest): cloud.ApiResponse => { + let result = MutJson []; + let var i = 0; + for employee in db.list() { + result.setAt(i, employee); + i = i + 1; + } + return cloud.ApiResponse { + status: 200, + body: Json.stringify(result) + }; +}); + + +api.get("/employees/:id", inflight (request: cloud.ApiRequest): cloud.ApiResponse => { + let employee = db.get(request.vars.get("id")); + return cloud.ApiResponse { + status: 200, + body: Json.stringify(employee) + }; +}); + +api.post("/employees", inflight (request: cloud.ApiRequest): cloud.ApiResponse => { + if let body = request.body { + let employeeData = Json.parse(body); + let id = "{counter.inc()}"; + db.insert(id, employeeData); + return cloud.ApiResponse { + status: 201, + body: id + }; + } +}); + +api.put("/employees/:id", inflight (request: cloud.ApiRequest): cloud.ApiResponse => { + if let body = request.body { + let employeeData = Json.parse(body); + let id = request.vars.get("id"); + db.update(id, employeeData); + return cloud.ApiResponse { + status: 200, + body: Json.stringify(employeeData) + }; + } +}); + +api.delete("/employees/:id", inflight (request: cloud.ApiRequest): cloud.ApiResponse => { + let id = request.vars.get("id"); + db.delete(id); + return cloud.ApiResponse { + status: 204 + }; +}); diff --git a/examples/tests/doc_examples/valid/bucket.md_example_1/main.w b/examples/tests/doc_examples/valid/bucket.md_example_1/main.w new file mode 100644 index 00000000000..6fa931672a8 --- /dev/null +++ b/examples/tests/doc_examples/valid/bucket.md_example_1/main.w @@ -0,0 +1,7 @@ +// This file was auto generated from an example found in: bucket.md_example_1 +// Example metadata: {"valid":true} +bring cloud; + +let bucket = new cloud.Bucket( + public: true, // optional, defaults to `false` +); diff --git a/examples/tests/doc_examples/valid/bucket.md_example_2/main.w b/examples/tests/doc_examples/valid/bucket.md_example_2/main.w new file mode 100644 index 00000000000..6294a794b4f --- /dev/null +++ b/examples/tests/doc_examples/valid/bucket.md_example_2/main.w @@ -0,0 +1,7 @@ +// This file was auto generated from an example found in: bucket.md_example_2 +// Example metadata: {"valid":true} +bring cloud; + +let bucket = new cloud.Bucket(); + +bucket.addObject("my-file.txt", "Hello, world!"); diff --git a/examples/tests/doc_examples/valid/bucket.md_example_3/main.w b/examples/tests/doc_examples/valid/bucket.md_example_3/main.w new file mode 100644 index 00000000000..1b11216fd0d --- /dev/null +++ b/examples/tests/doc_examples/valid/bucket.md_example_3/main.w @@ -0,0 +1,24 @@ +// This file was auto generated from an example found in: bucket.md_example_3 +// Example metadata: {"valid":true} +bring cloud; + +let bucket = new cloud.Bucket(); + +let bucketFunc = inflight () => { + bucket.put("file.txt", "Hello, world!"); + bucket.putJson("person.json", Json { name: "Alice" }); + + let fileData = bucket.get("file.txt"); + assert(fileData == "Hello, world!"); + + let jsonData = bucket.getJson("person.json"); + assert(jsonData.get("name") == "Alice"); + + let keys = bucket.list(); + assert(keys.at(0) == "file.txt"); + assert(keys.at(1) == "person.json"); + + bucket.delete("file.txt"); +}; + +new cloud.Function(bucketFunc); diff --git a/examples/tests/doc_examples/valid/bucket.md_example_4/main.w b/examples/tests/doc_examples/valid/bucket.md_example_4/main.w new file mode 100644 index 00000000000..c9dd7159da9 --- /dev/null +++ b/examples/tests/doc_examples/valid/bucket.md_example_4/main.w @@ -0,0 +1,18 @@ +// This file was auto generated from an example found in: bucket.md_example_4 +// Example metadata: {"valid":true} +bring cloud; + +let store = new cloud.Bucket(); +let copies = new cloud.Bucket() as "Backup"; + +store.onCreate(inflight (key: str) => { + let data = store.get(key); + if !key.endsWith(".log") { + copies.put(key, data); + } +}); + +store.onDelete(inflight (key: str) => { + copies.delete(key); + log("Deleted {key}"); +}); diff --git a/examples/tests/doc_examples/valid/counter.md_example_1/main.w b/examples/tests/doc_examples/valid/counter.md_example_1/main.w new file mode 100644 index 00000000000..ff57bdc2f65 --- /dev/null +++ b/examples/tests/doc_examples/valid/counter.md_example_1/main.w @@ -0,0 +1,7 @@ +// This file was auto generated from an example found in: counter.md_example_1 +// Example metadata: {"valid":true} +bring cloud; + +let counter = new cloud.Counter( + initial: 123, // optional, defaults to 0 +); diff --git a/examples/tests/doc_examples/valid/counter.md_example_2/main.w b/examples/tests/doc_examples/valid/counter.md_example_2/main.w new file mode 100644 index 00000000000..158fbef4981 --- /dev/null +++ b/examples/tests/doc_examples/valid/counter.md_example_2/main.w @@ -0,0 +1,18 @@ +// This file was auto generated from an example found in: counter.md_example_2 +// Example metadata: {"valid":true} +bring cloud; + +let counter = new cloud.Counter(); + +let counterFunc = inflight () => { + let prev = counter.inc(); // increment by 1 and return previous value + counter.inc(5); // increment by 5 + counter.dec(); // decrement by 1 + counter.dec(2); // decrement by 2 + + assert(counter.peek() == 3); // check the current value + + counter.set(100); // set to a specific value +}; + +new cloud.Function(counterFunc); diff --git a/examples/tests/doc_examples/valid/counter.md_example_3/main.w b/examples/tests/doc_examples/valid/counter.md_example_3/main.w new file mode 100644 index 00000000000..20ab812f1ee --- /dev/null +++ b/examples/tests/doc_examples/valid/counter.md_example_3/main.w @@ -0,0 +1,18 @@ +// This file was auto generated from an example found in: counter.md_example_3 +// Example metadata: {"valid":true} +bring cloud; + +let counter = new cloud.Counter(initial: 100); + +let counterFunc = inflight () => { + let k1 = "key-1"; + let k2 = "key-2"; + + counter.dec(1, k1); // decrement k1 by 1 + counter.inc(11, k2); // increment k2 by 11 + + assert(counter.peek(k1) == 99); // check the current value of k1 + assert(counter.peek(k2) == 111); // check the current value of k2 +}; + +new cloud.Function(counterFunc); diff --git a/examples/tests/doc_examples/valid/endpoint.md_example_1/main.w b/examples/tests/doc_examples/valid/endpoint.md_example_1/main.w new file mode 100644 index 00000000000..93a0403459a --- /dev/null +++ b/examples/tests/doc_examples/valid/endpoint.md_example_1/main.w @@ -0,0 +1,5 @@ +// This file was auto generated from an example found in: endpoint.md_example_1 +// Example metadata: {"valid":true} +bring cloud; + +let endpoint = new cloud.Endpoint("https://example.com"); diff --git a/examples/tests/doc_examples/valid/endpoint.md_example_2/main.w b/examples/tests/doc_examples/valid/endpoint.md_example_2/main.w new file mode 100644 index 00000000000..9d7cb97a719 --- /dev/null +++ b/examples/tests/doc_examples/valid/endpoint.md_example_2/main.w @@ -0,0 +1,5 @@ +// This file was auto generated from an example found in: endpoint.md_example_2 +// Example metadata: {"valid":true} +bring cloud; + +new cloud.Endpoint("https://example.com"); diff --git a/examples/tests/doc_examples/valid/function.md_example_1/main.w b/examples/tests/doc_examples/valid/function.md_example_1/main.w new file mode 100644 index 00000000000..b727f4e0b03 --- /dev/null +++ b/examples/tests/doc_examples/valid/function.md_example_1/main.w @@ -0,0 +1,24 @@ +// This file was auto generated from an example found in: function.md_example_1 +// Example metadata: {"valid":true} +bring cloud; +bring util; + +// defining a cloud.Function resource +let countWords = new cloud.Function(inflight (s: str?): str => { + return "{s?.split(" ")?.length ?? 0}"; +}) as "countWords"; + +let longTask = new cloud.Function(inflight () => { + util.sleep(30s); + log("done!"); +}); + +new cloud.Function(inflight () => { + let sentence = "I am a sentence with 7 words"; + // invoking cloud.Function from inflight context + let wordsCount = countWords.invoke(sentence); + log("'{sentence}' has {wordsCount ?? "0"} words"); + + longTask.invokeAsync(""); + log("task started"); +}) as "Invoke Me"; diff --git a/examples/tests/doc_examples/valid/function.md_example_2/main.w b/examples/tests/doc_examples/valid/function.md_example_2/main.w new file mode 100644 index 00000000000..745b9c2ef4d --- /dev/null +++ b/examples/tests/doc_examples/valid/function.md_example_2/main.w @@ -0,0 +1,27 @@ +// This file was auto generated from an example found in: function.md_example_2 +// Example metadata: {"valid":true} +bring cloud; + +let big = new cloud.Bucket(); + +big.addObject("bigdata.json", Json.stringify({ + "my-key": "my-value" +})); + +class MyDatabase { + inflight bigdata: Json; + inflight new() { + // download big data once + this.bigdata = big.getJson("bigdata.json"); + } + + pub inflight query(key: str): Json { + return this.bigdata.get(key); + } +} + +let db = new MyDatabase(); + +new cloud.Function(inflight () => { + log(Json.stringify(db.query("my-key"))); +}); diff --git a/examples/tests/doc_examples/valid/function.md_example_3/main.w b/examples/tests/doc_examples/valid/function.md_example_3/main.w new file mode 100644 index 00000000000..b74b18d78ce --- /dev/null +++ b/examples/tests/doc_examples/valid/function.md_example_3/main.w @@ -0,0 +1,17 @@ +// This file was auto generated from an example found in: function.md_example_3 +// Example metadata: {"valid":true} +bring aws; +bring cloud; + +let f = new cloud.Function(inflight () => { + log("Hello world!"); +}); +if let lambdaFn = aws.Function.from(f) { + lambdaFn.addPolicyStatements( + aws.PolicyStatement { + actions: ["ses:sendEmail"], + effect: aws.Effect.ALLOW, + resources: ["*"], + }, + ); +} diff --git a/examples/tests/doc_examples/valid/function.md_example_4/main.w b/examples/tests/doc_examples/valid/function.md_example_4/main.w new file mode 100644 index 00000000000..29b791e5c37 --- /dev/null +++ b/examples/tests/doc_examples/valid/function.md_example_4/main.w @@ -0,0 +1,14 @@ +// This file was auto generated from an example found in: function.md_example_4 +// Example metadata: {"valid":true} +bring aws; +bring cloud; + +let f = new cloud.Function(inflight () => { + if let ctx = aws.Function.context() { + log(ctx.logGroupName); // prints the log group name + log(ctx.logStreamName); // prints the log stream name + + let remainingTime = ctx.remainingTimeInMillis(); + assert(remainingTime > 0); + } +}); diff --git a/examples/tests/doc_examples/valid/on-deploy.md_example_1/main.w b/examples/tests/doc_examples/valid/on-deploy.md_example_1/main.w new file mode 100644 index 00000000000..63ccbe1cc73 --- /dev/null +++ b/examples/tests/doc_examples/valid/on-deploy.md_example_1/main.w @@ -0,0 +1,12 @@ +// This file was auto generated from an example found in: on-deploy.md_example_1 +// Example metadata: {"valid":true} +bring cloud; + +let bucket = new cloud.Bucket(); + +// each time the application is deployed, all objects in the bucket are deleted +let setup = new cloud.OnDeploy(inflight () => { + for key in bucket.list() { + bucket.delete(key); + } +}); diff --git a/examples/tests/doc_examples/valid/on-deploy.md_example_2/main.w b/examples/tests/doc_examples/valid/on-deploy.md_example_2/main.w new file mode 100644 index 00000000000..9d72bf0e725 --- /dev/null +++ b/examples/tests/doc_examples/valid/on-deploy.md_example_2/main.w @@ -0,0 +1,12 @@ +// This file was auto generated from an example found in: on-deploy.md_example_2 +// Example metadata: {"valid":true} +bring cloud; + +let counter = new cloud.Counter(); + +let setup2 = new cloud.OnDeploy(inflight () => { + counter.inc(); +}) as "setup2"; +let setup1 = new cloud.OnDeploy(inflight () => { + counter.set(10); +}, executeBefore: [setup2]) as "setup1"; diff --git a/examples/tests/doc_examples/valid/queue.md_example_1/main.w b/examples/tests/doc_examples/valid/queue.md_example_1/main.w new file mode 100644 index 00000000000..37a56c81144 --- /dev/null +++ b/examples/tests/doc_examples/valid/queue.md_example_1/main.w @@ -0,0 +1,14 @@ +// This file was auto generated from an example found in: queue.md_example_1 +// Example metadata: {"valid":true} +bring cloud; + +let q = new cloud.Queue(); + +q.setConsumer(inflight (m: str) => { + log("message ${m} consumed"); +}); + +new cloud.Function(inflight () => { + q.push("message a"); + q.push("message b"); +}); diff --git a/examples/tests/doc_examples/valid/queue.md_example_2/main.w b/examples/tests/doc_examples/valid/queue.md_example_2/main.w new file mode 100644 index 00000000000..817135ec890 --- /dev/null +++ b/examples/tests/doc_examples/valid/queue.md_example_2/main.w @@ -0,0 +1,16 @@ +// This file was auto generated from an example found in: queue.md_example_2 +// Example metadata: {"valid":true} +bring cloud; + +let q = new cloud.Queue(); + +new cloud.Function(inflight () => { + q.push("message a"); + q.push("message b", "message c", "message d"); + log("approxSize is ${q.approxSize()}"); + log("popping message ${q.pop()!}"); + log("popping message ${q.pop()!}"); + log("approxSize is ${q.approxSize()}"); + q.purge(); + log("approxSize is ${q.approxSize()}"); +}); diff --git a/examples/tests/doc_examples/valid/queue.md_example_3/main.w b/examples/tests/doc_examples/valid/queue.md_example_3/main.w new file mode 100644 index 00000000000..006252a9782 --- /dev/null +++ b/examples/tests/doc_examples/valid/queue.md_example_3/main.w @@ -0,0 +1,11 @@ +// This file was auto generated from an example found in: queue.md_example_3 +// Example metadata: {"valid":true} +bring cloud; + +let dlq = new cloud.Queue() as "dead-letter queue"; +let q = new cloud.Queue( + dlq: { + queue: dlq, + maxDeliveryAttempts: 2 + } +); diff --git a/examples/tests/doc_examples/valid/queue.md_example_4/main.w b/examples/tests/doc_examples/valid/queue.md_example_4/main.w new file mode 100644 index 00000000000..fb2d7cb32a6 --- /dev/null +++ b/examples/tests/doc_examples/valid/queue.md_example_4/main.w @@ -0,0 +1,10 @@ +// This file was auto generated from an example found in: queue.md_example_4 +// Example metadata: {"valid":true} +bring cloud; +bring aws; + +let outbox = new aws.QueueRef("arn:aws:sqs:us-east-1:111111111111:Outbox"); + +new cloud.Function(inflight () => { + outbox.push("send an email"); +}); diff --git a/examples/tests/doc_examples/valid/schedule.md_example_1/main.w b/examples/tests/doc_examples/valid/schedule.md_example_1/main.w new file mode 100644 index 00000000000..68808a3ae87 --- /dev/null +++ b/examples/tests/doc_examples/valid/schedule.md_example_1/main.w @@ -0,0 +1,9 @@ +// This file was auto generated from an example found in: schedule.md_example_1 +// Example metadata: {"valid":true} +bring cloud; + +let schedule = new cloud.Schedule(cron: "* * * * *"); + +schedule.onTick(inflight () => { + log("schedule: triggered"); +}); diff --git a/examples/tests/doc_examples/valid/schedule.md_example_2/main.w b/examples/tests/doc_examples/valid/schedule.md_example_2/main.w new file mode 100644 index 00000000000..409cbd0be76 --- /dev/null +++ b/examples/tests/doc_examples/valid/schedule.md_example_2/main.w @@ -0,0 +1,9 @@ +// This file was auto generated from an example found in: schedule.md_example_2 +// Example metadata: {"valid":true} +bring cloud; + +let schedule = new cloud.Schedule(rate: 1m); + +schedule.onTick(inflight () => { + log("schedule: triggered"); +}); diff --git a/examples/tests/doc_examples/valid/secret.md_example_1/main.w b/examples/tests/doc_examples/valid/secret.md_example_1/main.w new file mode 100644 index 00000000000..09598b0638f --- /dev/null +++ b/examples/tests/doc_examples/valid/secret.md_example_1/main.w @@ -0,0 +1,7 @@ +// This file was auto generated from an example found in: secret.md_example_1 +// Example metadata: {"valid":true} +bring cloud; + +let secret = new cloud.Secret( + name: "my-secret", // optional, defaults to a generated name +); diff --git a/examples/tests/doc_examples/valid/secret.md_example_2/main.w b/examples/tests/doc_examples/valid/secret.md_example_2/main.w new file mode 100644 index 00000000000..b4a310d0b84 --- /dev/null +++ b/examples/tests/doc_examples/valid/secret.md_example_2/main.w @@ -0,0 +1,12 @@ +// This file was auto generated from an example found in: secret.md_example_2 +// Example metadata: {"valid":true} +bring cloud; + +let secret = new cloud.Secret( + name: "my-api-key", +); + +new cloud.Function(inflight () => { + let secretValue = secret.value(); // retrieve the secret as a `str` value + let secretValueAsJson = secret.valueJson(); // retrieve the secret as a `Json` value +}); diff --git a/examples/tests/doc_examples/valid/topic.md_example_1/main.w b/examples/tests/doc_examples/valid/topic.md_example_1/main.w new file mode 100644 index 00000000000..749c67e6b4d --- /dev/null +++ b/examples/tests/doc_examples/valid/topic.md_example_1/main.w @@ -0,0 +1,5 @@ +// This file was auto generated from an example found in: topic.md_example_1 +// Example metadata: {"valid":true} +bring cloud; + +let topic = new cloud.Topic(); diff --git a/examples/tests/doc_examples/valid/topic.md_example_2/main.w b/examples/tests/doc_examples/valid/topic.md_example_2/main.w new file mode 100644 index 00000000000..d09ea4f2ced --- /dev/null +++ b/examples/tests/doc_examples/valid/topic.md_example_2/main.w @@ -0,0 +1,9 @@ +// This file was auto generated from an example found in: topic.md_example_2 +// Example metadata: {"valid":true} +bring cloud; + +let topic = new cloud.Topic(); + +topic.onMessage(inflight (message: str) => { + log("Topic published message: {message}"); +}); diff --git a/examples/tests/doc_examples/valid/topic.md_example_3/main.w b/examples/tests/doc_examples/valid/topic.md_example_3/main.w new file mode 100644 index 00000000000..169262a6f29 --- /dev/null +++ b/examples/tests/doc_examples/valid/topic.md_example_3/main.w @@ -0,0 +1,11 @@ +// This file was auto generated from an example found in: topic.md_example_3 +// Example metadata: {"valid":true} +bring cloud; + +let queue = new cloud.Queue(); +queue.setConsumer(inflight (message: str) => { + log("Topic published message: {message}"); +}); + +let topic = new cloud.Topic(); +topic.subscribeQueue(queue); diff --git a/examples/tests/doc_examples/valid/topic.md_example_4/main.w b/examples/tests/doc_examples/valid/topic.md_example_4/main.w new file mode 100644 index 00000000000..1180617f329 --- /dev/null +++ b/examples/tests/doc_examples/valid/topic.md_example_4/main.w @@ -0,0 +1,12 @@ +// This file was auto generated from an example found in: topic.md_example_4 +// Example metadata: {"valid":true} +bring cloud; + +let topic = new cloud.Topic(); + +inflight () => { + topic.publish( + "Topics can now publish", + "multiple messages at once" + ); +}; diff --git a/examples/tests/doc_examples/valid/topic.md_example_5/main.w b/examples/tests/doc_examples/valid/topic.md_example_5/main.w new file mode 100644 index 00000000000..28f99045003 --- /dev/null +++ b/examples/tests/doc_examples/valid/topic.md_example_5/main.w @@ -0,0 +1,25 @@ +// This file was auto generated from an example found in: topic.md_example_5 +// Example metadata: {"valid":true} +bring cloud; + +// First we create a topic +let topic = new cloud.Topic(); + +// Then we define a consumer inflight handler +let consumerHandler = inflight(message: str) => { + log("Doing some work with message: {message}"); +}; + +// Now we can use a preflight method of topic to register the consumer handler +// to be invoked when a message is published to the topic. +topic.onMessage(consumerHandler); + +// Then we define the producer inflight handler +let publisherHandler = inflight () => { + // Here we use the inflight api to publish a message to the topic. + topic.publish("Here are those launch codes you asked for."); +}; + +// Finally we can use multiple resources to invoke our publisher handler +// for simplicity sake we will just use a function. +new cloud.Function(publisherHandler); diff --git a/libs/wingsdk/src/cloud/api.md b/libs/wingsdk/src/cloud/api.md index 21d7d363eeb..ddf81b9cbbd 100644 --- a/libs/wingsdk/src/cloud/api.md +++ b/libs/wingsdk/src/cloud/api.md @@ -29,7 +29,7 @@ When a client invokes a route, the corresponding event handler function executes The following example shows a complete REST API implementation using `cloud.Api`, `ex.Table` & `cloud.Counter` -```ts playground +```ts playground example bring cloud; bring ex; diff --git a/libs/wingsdk/src/cloud/bucket.md b/libs/wingsdk/src/cloud/bucket.md index cfae2d71f18..1384616d717 100644 --- a/libs/wingsdk/src/cloud/bucket.md +++ b/libs/wingsdk/src/cloud/bucket.md @@ -26,7 +26,7 @@ Unlike other kinds of storage like file storage, data is not stored in a hierarc ### Defining a bucket -```js +```js example bring cloud; let bucket = new cloud.Bucket( @@ -38,7 +38,7 @@ let bucket = new cloud.Bucket( If you have static data that you want to upload to the bucket each time your app is deployed, you can call the preflight method `addObject`: -```js +```js example bring cloud; let bucket = new cloud.Bucket(); @@ -48,7 +48,7 @@ bucket.addObject("my-file.txt", "Hello, world!"); ### Using a bucket inflight -```js playground +```js playground example bring cloud; let bucket = new cloud.Bucket(); @@ -80,7 +80,7 @@ Use the `onEvent` method for responding to any event. Each method creates a new `cloud.Function` resource which will be triggered by the given event type. -```js playground +```js playground example bring cloud; let store = new cloud.Bucket(); diff --git a/libs/wingsdk/src/cloud/counter.md b/libs/wingsdk/src/cloud/counter.md index 18ca1456251..61d1e794f2c 100644 --- a/libs/wingsdk/src/cloud/counter.md +++ b/libs/wingsdk/src/cloud/counter.md @@ -20,7 +20,7 @@ The `cloud.Counter` resource represents a stateful container for one or more num ### Defining a counter -```js +```js example bring cloud; let counter = new cloud.Counter( @@ -30,7 +30,7 @@ let counter = new cloud.Counter( ### Using a counter inflight -```js playground +```js playground example bring cloud; let counter = new cloud.Counter(); @@ -51,7 +51,7 @@ new cloud.Function(counterFunc); ### Using keys to manage multiple counter values -```js playground +```js playground example bring cloud; let counter = new cloud.Counter(initial: 100); diff --git a/libs/wingsdk/src/cloud/endpoint.md b/libs/wingsdk/src/cloud/endpoint.md index 79f87fae61c..a03aad1fcd8 100644 --- a/libs/wingsdk/src/cloud/endpoint.md +++ b/libs/wingsdk/src/cloud/endpoint.md @@ -19,7 +19,7 @@ The `cloud.Endpoint` represents a publicly accessible endpoint and outputs it as ## Usage -```ts playground +```ts playground example bring cloud; let endpoint = new cloud.Endpoint("https://example.com"); @@ -54,7 +54,7 @@ represents a publicly accessible endpoint and outputs it as part of the compilat #### Initializers -```wing +```wing example bring cloud; new cloud.Endpoint("https://example.com"); diff --git a/libs/wingsdk/src/cloud/function.md b/libs/wingsdk/src/cloud/function.md index 0c292df201d..ea649f9c4ac 100644 --- a/libs/wingsdk/src/cloud/function.md +++ b/libs/wingsdk/src/cloud/function.md @@ -29,7 +29,7 @@ A function can be invoked in two ways: * **invoke()** - Executes the function with a payload and waits for the result. * **invokeAsync()** - Kicks off the execution of the function with a payload and returns immediately while the function is running. -```ts playground +```ts playground example bring cloud; bring util; @@ -61,7 +61,7 @@ It is possible to leverage this behavior to cache objects across function execut The following example reads the `bigdata.json` file once and reuses it every time `query()` is called. -```ts playground +```ts playground example bring cloud; let big = new cloud.Bucket(); @@ -98,6 +98,8 @@ The sim implementation of `cloud.Function` runs the inflight code as a JavaScrip By default, a maximum of 10 workers can be processing requests sent to a `cloud.Function` concurrently, but this number can be adjusted with the `concurrency` property: ```ts playground +bring cloud; + new cloud.Function(inflight () => { // ... code that shouldn't run concurrently ... }, concurrency: 1); @@ -109,7 +111,7 @@ The AWS implementation of `cloud.Function` uses [AWS Lambda](https://aws.amazon. To add extra IAM permissions to the function, you can use the `aws.Function` class as shown below. -```ts playground +```ts playground example bring aws; bring cloud; @@ -129,7 +131,7 @@ if let lambdaFn = aws.Function.from(f) { To access the AWS Lambda context object, you can use the `aws.Function` class as shown below. -```ts playground +```ts playground example bring aws; bring cloud; diff --git a/libs/wingsdk/src/cloud/on-deploy.md b/libs/wingsdk/src/cloud/on-deploy.md index 2e868a3dce2..8874d4feafd 100644 --- a/libs/wingsdk/src/cloud/on-deploy.md +++ b/libs/wingsdk/src/cloud/on-deploy.md @@ -20,7 +20,7 @@ The `cloud.OnDeploy` resource runs a block of inflight code each time the applic ## Usage -```ts playground +```ts playground example bring cloud; let bucket = new cloud.Bucket(); @@ -35,7 +35,7 @@ let setup = new cloud.OnDeploy(inflight () => { To specify that the `cloud.OnDeploy` resource should be run before or after another resource is created or updated, use the `executeBefore` or `executeAfter` properties: -```ts playground +```ts playground example bring cloud; let counter = new cloud.Counter(); diff --git a/libs/wingsdk/src/cloud/queue.md b/libs/wingsdk/src/cloud/queue.md index 04c656ccffb..0b45cb570a0 100644 --- a/libs/wingsdk/src/cloud/queue.md +++ b/libs/wingsdk/src/cloud/queue.md @@ -26,7 +26,7 @@ Queues by default are not FIFO (first in, first out) - so the order of messages ### Setting a Queue Consumer -```ts playground +```ts playground example bring cloud; let q = new cloud.Queue(); @@ -45,7 +45,7 @@ new cloud.Function(inflight () => { Pushing messages, popping them, and purging. -```ts playground +```ts playground example bring cloud; let q = new cloud.Queue(); @@ -54,8 +54,8 @@ new cloud.Function(inflight () => { q.push("message a"); q.push("message b", "message c", "message d"); log("approxSize is ${q.approxSize()}"); - log("popping message ${q.pop()}"); - log("popping message ${q.pop()}"); + log("popping message ${q.pop()!}"); + log("popping message ${q.pop()!}"); log("approxSize is ${q.approxSize()}"); q.purge(); log("approxSize is ${q.approxSize()}"); @@ -66,7 +66,7 @@ new cloud.Function(inflight () => { Creating a queue and adding a dead-letter queue with the maximum number of attempts configured -```ts playground +```ts playground example bring cloud; let dlq = new cloud.Queue() as "dead-letter queue"; @@ -88,7 +88,8 @@ If you would like to reference an existing queue from within your application yo The following example defines a reference to an Amazon SQS queue with a specific ARN and sends a message to the queue from the function: -```js +```js example +bring cloud; bring aws; let outbox = new aws.QueueRef("arn:aws:sqs:us-east-1:111111111111:Outbox"); diff --git a/libs/wingsdk/src/cloud/schedule.md b/libs/wingsdk/src/cloud/schedule.md index 86e69620639..44f37c09e1d 100644 --- a/libs/wingsdk/src/cloud/schedule.md +++ b/libs/wingsdk/src/cloud/schedule.md @@ -23,10 +23,10 @@ The timezone used in cron expressions is always UTC. ### From cron -```ts playground +```ts playground example bring cloud; -let schedule = new cloud.Schedule(cron: "* * * * ?"); +let schedule = new cloud.Schedule(cron: "* * * * *"); schedule.onTick(inflight () => { log("schedule: triggered"); @@ -35,7 +35,7 @@ schedule.onTick(inflight () => { ### From rate -```ts playground +```ts playground example bring cloud; let schedule = new cloud.Schedule(rate: 1m); diff --git a/libs/wingsdk/src/cloud/secret.md b/libs/wingsdk/src/cloud/secret.md index f5e434e7ebf..6acb91f4202 100644 --- a/libs/wingsdk/src/cloud/secret.md +++ b/libs/wingsdk/src/cloud/secret.md @@ -25,7 +25,7 @@ You can use the [`wing secrets`](https://www.winglang.io/docs/tools/cli#store-se ### Defining a secret -```js +```js example bring cloud; let secret = new cloud.Secret( @@ -37,7 +37,7 @@ Before deploying your application, you will be expected to store the secret valu ### Retrieving secret values -```js +```js example bring cloud; let secret = new cloud.Secret( diff --git a/libs/wingsdk/src/cloud/topic.md b/libs/wingsdk/src/cloud/topic.md index fae2cba4e32..b3b48e61d42 100644 --- a/libs/wingsdk/src/cloud/topic.md +++ b/libs/wingsdk/src/cloud/topic.md @@ -22,7 +22,7 @@ Topics are a staple of event-driven architectures, especially those that rely on ### Creating a topic -```js +```js example bring cloud; let topic = new cloud.Topic(); @@ -30,7 +30,7 @@ let topic = new cloud.Topic(); ### Subscribing to a topic -```js +```js example bring cloud; let topic = new cloud.Topic(); @@ -42,11 +42,11 @@ topic.onMessage(inflight (message: str) => { ### Subscribing a Queue to a Topic -```js +```js example bring cloud; let queue = new cloud.Queue(); -queue.setConsumer(inflight (message str) => { +queue.setConsumer(inflight (message: str) => { log("Topic published message: {message}"); }); @@ -58,7 +58,7 @@ topic.subscribeQueue(queue); The inflight method `publish` sends messages to all of the topic's subscribers. -```js +```js example bring cloud; let topic = new cloud.Topic(); @@ -76,7 +76,7 @@ inflight () => { Here is an example of combining the preflight and inflight apis for a topic and creating an adorable simple pub-sub application. -```js +```js example bring cloud; // First we create a topic diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b68f25c81e1..66e4efb8c76 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -380,7 +380,7 @@ importers: version: 5.3.3 vitest: specifier: ^0.34.6 - version: 0.34.6(happy-dom@9.20.3) + version: 0.34.6 apps/wing-api-checker: dependencies: @@ -538,7 +538,7 @@ importers: version: 5.2.2 vite: specifier: ^4.5.2 - version: 4.5.2(@types/node@20.11.0) + version: 4.5.2(@types/node@20.14.0) apps/wing-console/console/design-system: dependencies: @@ -626,7 +626,7 @@ importers: version: 5.2.2 vite: specifier: ^4.5.2 - version: 4.5.2(@types/node@20.11.0) + version: 4.5.2(@types/node@20.14.0) vitest: specifier: ^0.34.6 version: 0.34.6(happy-dom@9.20.3) @@ -732,7 +732,7 @@ importers: version: 5.2.2 vitest: specifier: ^0.34.6 - version: 0.34.6(happy-dom@9.20.3) + version: 0.34.6 ws: specifier: ^8.13.0 version: 8.14.2 @@ -904,10 +904,10 @@ importers: version: 5.2.2 vite: specifier: ^4.5.2 - version: 4.5.2(@types/node@20.11.0) + version: 4.5.2(@types/node@20.14.0) vitest: specifier: ^0.34.6 - version: 0.34.6(happy-dom@9.20.3) + version: 0.34.6 webpack: specifier: ^5.88.2 version: 5.88.2(esbuild@0.19.12) @@ -1018,6 +1018,18 @@ importers: specifier: workspace:^ version: link:../../libs/wingii + docs: + devDependencies: + '@types/node': + specifier: ^20.14.0 + version: 20.14.0 + tsx: + specifier: ^4.11.2 + version: 4.11.2 + typescript: + specifier: ^5.4.5 + version: 5.4.5 + docs/docs: {} examples/jsii-fixture: @@ -1026,6 +1038,8 @@ importers: specifier: ~5.3.11 version: 5.3.11(patch_hash=ckgthkljzwfnfbd5qz6x7vtvme) + examples/tests/doc_examples: {} + examples/tests/error: {} examples/tests/invalid: @@ -1173,7 +1187,7 @@ importers: version: 5.3.3 vitest: specifier: ^0.34.6 - version: 0.34.6(happy-dom@9.20.3) + version: 0.34.6 libs/compatibility-spy: dependencies: @@ -1195,7 +1209,7 @@ importers: version: 5.3.3 vitest: specifier: ^0.34.6 - version: 0.34.6(happy-dom@9.20.3) + version: 0.34.6 libs/tree-sitter-wing: dependencies: @@ -1257,7 +1271,7 @@ importers: version: 5.3.3 vitest: specifier: ^0.34.6 - version: 0.34.6(happy-dom@9.20.3) + version: 0.34.6 libs/wingii: {} @@ -1526,7 +1540,7 @@ importers: version: 5.3.3 vitest: specifier: ^0.34.6 - version: 0.34.6(happy-dom@9.20.3) + version: 0.34.6 tools/bump-pack: dependencies: @@ -1575,7 +1589,7 @@ importers: version: 5.2.2 vitest: specifier: ^0.34.6 - version: 0.34.6(happy-dom@9.20.3) + version: 0.34.6 tools/compatibility-matrix-automation: dependencies: @@ -1600,7 +1614,7 @@ importers: version: 5.3.3 vitest: specifier: ^0.34.6 - version: 0.34.6(happy-dom@9.20.3) + version: 0.34.6 tools/generate-workspace: dependencies: @@ -1676,7 +1690,7 @@ importers: version: 4.7.0 vitest: specifier: ^0.34.6 - version: 0.34.6(happy-dom@9.20.3) + version: 0.34.6 winglang: specifier: workspace:^ version: link:../../apps/wing @@ -5248,6 +5262,15 @@ packages: requiresBuild: true optional: true + /@esbuild/aix-ppc64@0.20.2: + resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-arm64@0.17.19: resolution: {integrity: sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==} engines: {node: '>=12'} @@ -5274,6 +5297,15 @@ packages: requiresBuild: true optional: true + /@esbuild/android-arm64@0.20.2: + resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-arm@0.15.18: resolution: {integrity: sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==} engines: {node: '>=12'} @@ -5309,6 +5341,15 @@ packages: requiresBuild: true optional: true + /@esbuild/android-arm@0.20.2: + resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-x64@0.17.19: resolution: {integrity: sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==} engines: {node: '>=12'} @@ -5335,6 +5376,15 @@ packages: requiresBuild: true optional: true + /@esbuild/android-x64@0.20.2: + resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/darwin-arm64@0.17.19: resolution: {integrity: sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==} engines: {node: '>=12'} @@ -5361,6 +5411,15 @@ packages: requiresBuild: true optional: true + /@esbuild/darwin-arm64@0.20.2: + resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /@esbuild/darwin-x64@0.17.19: resolution: {integrity: sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==} engines: {node: '>=12'} @@ -5387,6 +5446,15 @@ packages: requiresBuild: true optional: true + /@esbuild/darwin-x64@0.20.2: + resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /@esbuild/freebsd-arm64@0.17.19: resolution: {integrity: sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==} engines: {node: '>=12'} @@ -5413,6 +5481,15 @@ packages: requiresBuild: true optional: true + /@esbuild/freebsd-arm64@0.20.2: + resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/freebsd-x64@0.17.19: resolution: {integrity: sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==} engines: {node: '>=12'} @@ -5439,6 +5516,15 @@ packages: requiresBuild: true optional: true + /@esbuild/freebsd-x64@0.20.2: + resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-arm64@0.17.19: resolution: {integrity: sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==} engines: {node: '>=12'} @@ -5465,6 +5551,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-arm64@0.20.2: + resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-arm@0.17.19: resolution: {integrity: sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==} engines: {node: '>=12'} @@ -5491,6 +5586,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-arm@0.20.2: + resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-ia32@0.17.19: resolution: {integrity: sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==} engines: {node: '>=12'} @@ -5517,6 +5621,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-ia32@0.20.2: + resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-loong64@0.15.18: resolution: {integrity: sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==} engines: {node: '>=12'} @@ -5552,6 +5665,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-loong64@0.20.2: + resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-mips64el@0.17.19: resolution: {integrity: sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==} engines: {node: '>=12'} @@ -5578,6 +5700,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-mips64el@0.20.2: + resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-ppc64@0.17.19: resolution: {integrity: sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==} engines: {node: '>=12'} @@ -5604,6 +5735,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-ppc64@0.20.2: + resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-riscv64@0.17.19: resolution: {integrity: sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==} engines: {node: '>=12'} @@ -5630,6 +5770,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-riscv64@0.20.2: + resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-s390x@0.17.19: resolution: {integrity: sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==} engines: {node: '>=12'} @@ -5656,6 +5805,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-s390x@0.20.2: + resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-x64@0.17.19: resolution: {integrity: sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==} engines: {node: '>=12'} @@ -5682,6 +5840,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-x64@0.20.2: + resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/netbsd-x64@0.17.19: resolution: {integrity: sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==} engines: {node: '>=12'} @@ -5708,6 +5875,15 @@ packages: requiresBuild: true optional: true + /@esbuild/netbsd-x64@0.20.2: + resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/openbsd-x64@0.17.19: resolution: {integrity: sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==} engines: {node: '>=12'} @@ -5734,6 +5910,15 @@ packages: requiresBuild: true optional: true + /@esbuild/openbsd-x64@0.20.2: + resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/sunos-x64@0.17.19: resolution: {integrity: sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==} engines: {node: '>=12'} @@ -5760,6 +5945,15 @@ packages: requiresBuild: true optional: true + /@esbuild/sunos-x64@0.20.2: + resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-arm64@0.17.19: resolution: {integrity: sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==} engines: {node: '>=12'} @@ -5786,6 +5980,15 @@ packages: requiresBuild: true optional: true + /@esbuild/win32-arm64@0.20.2: + resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-ia32@0.17.19: resolution: {integrity: sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==} engines: {node: '>=12'} @@ -5812,6 +6015,15 @@ packages: requiresBuild: true optional: true + /@esbuild/win32-ia32@0.20.2: + resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-x64@0.17.19: resolution: {integrity: sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==} engines: {node: '>=12'} @@ -5838,6 +6050,15 @@ packages: requiresBuild: true optional: true + /@esbuild/win32-x64@0.20.2: + resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@eslint-community/eslint-utils@4.4.0(eslint@8.51.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -6011,7 +6232,7 @@ packages: engines: {node: ^8.13.0 || >=10.10.0} dependencies: '@grpc/proto-loader': 0.7.10 - '@types/node': 20.11.20 + '@types/node': 20.14.0 dev: false /@grpc/proto-loader@0.7.10: @@ -6120,7 +6341,7 @@ packages: dependencies: '@inquirer/type': 1.1.5 '@types/mute-stream': 0.0.1 - '@types/node': 20.11.20 + '@types/node': 20.14.0 '@types/wrap-ansi': 3.0.0 ansi-escapes: 4.3.2 chalk: 4.1.2 @@ -6140,7 +6361,7 @@ packages: dependencies: '@inquirer/type': 1.1.5 '@types/mute-stream': 0.0.2 - '@types/node': 20.11.20 + '@types/node': 20.14.0 '@types/wrap-ansi': 3.0.0 ansi-escapes: 4.3.2 chalk: 4.1.2 @@ -6318,7 +6539,7 @@ packages: dependencies: '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.2 - '@types/node': 20.11.20 + '@types/node': 20.14.0 '@types/yargs': 16.0.6 chalk: 4.1.2 dev: true @@ -6330,7 +6551,7 @@ packages: '@jest/schemas': 28.1.3 '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.2 - '@types/node': 20.11.20 + '@types/node': 20.14.0 '@types/yargs': 17.0.28 chalk: 4.1.2 dev: true @@ -6342,7 +6563,7 @@ packages: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.2 - '@types/node': 20.11.20 + '@types/node': 20.14.0 '@types/yargs': 17.0.28 chalk: 4.1.2 dev: true @@ -6361,7 +6582,7 @@ packages: magic-string: 0.27.0 react-docgen-typescript: 2.2.2(typescript@5.2.2) typescript: 5.2.2 - vite: 4.5.2(@types/node@20.11.0) + vite: 4.5.2(@types/node@20.14.0) dev: true /@jridgewell/gen-mapping@0.3.3: @@ -9946,7 +10167,7 @@ packages: remark-slug: 6.1.0 rollup: 3.29.4 typescript: 5.2.2 - vite: 4.5.2(@types/node@20.11.0) + vite: 4.5.2(@types/node@20.14.0) transitivePeerDependencies: - encoding - supports-color @@ -10315,7 +10536,7 @@ packages: react: 18.2.0 react-docgen: 6.0.0-alpha.3 react-dom: 18.2.0(react@18.2.0) - vite: 4.5.2(@types/node@20.11.0) + vite: 4.5.2(@types/node@20.14.0) transitivePeerDependencies: - '@preact/preset-vite' - encoding @@ -10743,7 +10964,7 @@ packages: resolution: {integrity: sha512-oyl4jvAfTGX9Bt6Or4H9ni1Z447/tQuxnZsytsCaExKlmJiU8sFgnIBRzJUpKwB5eWn9HuBYlUlVA74q/yN0eQ==} dependencies: '@types/connect': 3.4.36 - '@types/node': 20.11.20 + '@types/node': 20.14.0 dev: true /@types/btoa-lite@1.0.0: @@ -10753,7 +10974,7 @@ packages: /@types/cacache@17.0.0: resolution: {integrity: sha512-4BfoYFzkHdmINTyUIX9MSbKUkntVPR082FRnNc+5KlvvebrcxWWhfP3MRQ28QgfFncP3fTKCuemDYJqFjmWEAA==} dependencies: - '@types/node': 20.11.20 + '@types/node': 20.14.0 dev: true /@types/caseless@0.12.4: @@ -10773,7 +10994,7 @@ packages: /@types/connect@3.4.36: resolution: {integrity: sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==} dependencies: - '@types/node': 20.11.20 + '@types/node': 20.14.0 dev: true /@types/cors@2.8.14: @@ -10785,7 +11006,7 @@ packages: /@types/cross-spawn@6.0.3: resolution: {integrity: sha512-BDAkU7WHHRHnvBf5z89lcvACsvkz/n7Tv+HyD/uW76O29HoH1Tk/W6iQrepaZVbisvlEek4ygwT8IW7ow9XLAA==} dependencies: - '@types/node': 20.11.20 + '@types/node': 20.14.0 dev: true /@types/cross-spawn@6.0.6: @@ -10872,7 +11093,7 @@ packages: /@types/express-serve-static-core@4.17.37: resolution: {integrity: sha512-ZohaCYTgGFcOP7u6aJOhY9uIZQgZ2vxC2yWoArY+FeDXlqeH66ZVBjgvg+RLVAS/DWNq4Ap9ZXu1+SUQiiWYMg==} dependencies: - '@types/node': 20.11.20 + '@types/node': 20.14.0 '@types/qs': 6.9.8 '@types/range-parser': 1.2.5 '@types/send': 0.17.2 @@ -10895,7 +11116,7 @@ packages: resolution: {integrity: sha512-c0hrgAOVYr21EX8J0jBMXGLMgJqVf/v6yxi0dLaJboW9aQPh16Id+z6w2Tx1hm+piJOLv8xPfVKZCLfjPw/IMQ==} dependencies: '@types/jsonfile': 6.1.2 - '@types/node': 20.11.0 + '@types/node': 20.14.0 dev: true /@types/fs-extra@9.0.13: @@ -10908,20 +11129,20 @@ packages: resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.11.20 + '@types/node': 20.14.0 dev: true /@types/glob@8.1.0: resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==} dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.11.20 + '@types/node': 20.14.0 dev: false /@types/graceful-fs@4.1.7: resolution: {integrity: sha512-MhzcwU8aUygZroVwL2jeYk6JisJrPl/oov/gsgGCue9mkgl9wjGbzReYQClxiUgFDnib9FuHqTndccKeZKxTRw==} dependencies: - '@types/node': 20.11.20 + '@types/node': 20.14.0 dev: true /@types/hast@3.0.3: @@ -10937,7 +11158,7 @@ packages: /@types/ignore-walk@4.0.1: resolution: {integrity: sha512-jve9GxuPfapQBNbsmLB4yTUV/uT16xJTxgnlcEWKcA9D5i1uMqokpyq7eKjrTH0zb1sBx1SAY3xRXSbxqj0fAg==} dependencies: - '@types/node': 20.11.20 + '@types/node': 20.14.0 dev: true /@types/inquirer@9.0.7: @@ -10983,13 +11204,13 @@ packages: /@types/jsonfile@6.1.2: resolution: {integrity: sha512-8t92P+oeW4d/CRQfJaSqEwXujrhH4OEeHRjGU3v1Q8mUS8GPF3yiX26sw4svv6faL2HfBtGTe2xWIoVgN3dy9w==} dependencies: - '@types/node': 20.11.20 + '@types/node': 20.14.0 dev: true /@types/jsonwebtoken@9.0.3: resolution: {integrity: sha512-b0jGiOgHtZ2jqdPgPnP6WLCXZk1T8p06A/vPGzUvxpFGgKMbjXJDjC5m52ErqBnIuWZFgGoIJyRdeG5AyreJjA==} dependencies: - '@types/node': 20.11.20 + '@types/node': 20.14.0 dev: true /@types/lodash.debounce@4.0.7: @@ -11070,13 +11291,13 @@ packages: /@types/mute-stream@0.0.1: resolution: {integrity: sha512-0yQLzYhCqGz7CQPE3iDmYjhb7KMBFOP+tBkyw+/Y2YyDI5wpS7itXXxneN1zSsUwWx3Ji6YiVYrhAnpQGS/vkw==} dependencies: - '@types/node': 20.11.20 + '@types/node': 20.14.0 dev: true /@types/mute-stream@0.0.2: resolution: {integrity: sha512-FpiGjk6+IOrN0lZEfUUjdra1csU1VxwYFj4S0Zj+TJpu5x5mZW30RkEZojTadrNZHNmpCHgoE62IQZAH0OeuIA==} dependencies: - '@types/node': 20.11.20 + '@types/node': 20.14.0 dev: true /@types/node-fetch@2.6.6: @@ -11110,6 +11331,12 @@ packages: resolution: {integrity: sha512-7/rR21OS+fq8IyHTgtLkDK949uzsa6n8BkziAKtPVpugIkO6D+/ooXMvzXxDnZrmtXVfjb1bKQafYpb8s89LOg==} dependencies: undici-types: 5.26.5 + dev: false + + /@types/node@20.14.0: + resolution: {integrity: sha512-5cHBxFGJx6L4s56Bubp4fglrEpmyJypsqI6RgzMfBHWUJQGWAAi8cWcgetEbZXHYXo9C2Fa4EEds/uSyS4cxmA==} + dependencies: + undici-types: 5.26.5 /@types/normalize-package-data@2.4.2: resolution: {integrity: sha512-lqa4UEhhv/2sjjIQgjX8B+RBjj47eo0mzGasklVJ78UKGQY1r0VpB9XHDaZZO9qzEFDdy4MrXLuEaSmPrPSe/A==} @@ -11128,7 +11355,7 @@ packages: /@types/npm-registry-fetch@8.0.5: resolution: {integrity: sha512-mAyQmKTF/4dhXTeSicltEtMO+Vj/LEUoBkMgDn9tS2fGp8IsrZPkYv2GH0KKBcbFLXUq67wuzYwl0DCZGeRcpw==} dependencies: - '@types/node': 20.11.20 + '@types/node': 20.14.0 '@types/node-fetch': 2.6.6 '@types/npm-package-arg': 6.1.2 '@types/npmlog': 4.1.4 @@ -11155,7 +11382,7 @@ packages: /@types/pacote@11.1.6: resolution: {integrity: sha512-Uh0+ivCS2p+pMFZmU1u20sGi7O8BJnBOCuNXsBaAMD/6/NIcbI/CcnBUNpTeVhOuFmOwn9/z8BxprpPhL+UkVg==} dependencies: - '@types/node': 20.11.20 + '@types/node': 20.14.0 '@types/npm-registry-fetch': 8.0.5 '@types/npmlog': 4.1.4 '@types/ssri': 7.1.2 @@ -11197,7 +11424,7 @@ packages: resolution: {integrity: sha512-HuihY1+Vss5RS9ZHzRyTGIzwPTdrJBkCm/mAeLRYrOQu/MGqyezKXWOK1VhCnR+SDbp9G2mRUP+OVEqCrzpcfA==} dependencies: '@types/caseless': 0.12.4 - '@types/node': 20.11.20 + '@types/node': 20.14.0 '@types/tough-cookie': 4.0.4 form-data: 2.5.1 dev: false @@ -11216,7 +11443,7 @@ packages: resolution: {integrity: sha512-aAG6yRf6r0wQ29bkS+x97BIs64ZLxeE/ARwyS6wrldMm3C1MdKwCcnnEwMC1slI8wuxJOpiUH9MioC0A0i+GJw==} dependencies: '@types/mime': 1.3.3 - '@types/node': 20.11.20 + '@types/node': 20.14.0 dev: true /@types/serve-static@1.15.3: @@ -11224,7 +11451,7 @@ packages: dependencies: '@types/http-errors': 2.0.2 '@types/mime': 3.0.2 - '@types/node': 20.11.20 + '@types/node': 20.14.0 dev: true /@types/sinon@10.0.19: @@ -11240,7 +11467,7 @@ packages: /@types/ssri@7.1.2: resolution: {integrity: sha512-Mbo/NaBiZlXNlOFTLK+PXeVEzKFxi+ZVELuzmk4VxdRz6aqKpmP9bhcNqsIB2c/s78355WBHwUCGYhQDydcfEg==} dependencies: - '@types/node': 20.11.20 + '@types/node': 20.14.0 /@types/stack-utils@2.0.1: resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} @@ -11256,7 +11483,7 @@ packages: /@types/through@0.0.33: resolution: {integrity: sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==} dependencies: - '@types/node': 20.11.20 + '@types/node': 20.14.0 dev: true /@types/tough-cookie@4.0.4: @@ -11272,7 +11499,7 @@ packages: /@types/tunnel@0.0.3: resolution: {integrity: sha512-sOUTGn6h1SfQ+gbgqC364jLFBw2lnFqkgF3q0WovEHRLMrVD1sd5aufqi/aJObLekJO+Aq5z646U4Oxy6shXMA==} dependencies: - '@types/node': 20.11.20 + '@types/node': 20.14.0 dev: false /@types/unist@2.0.10: @@ -11306,7 +11533,7 @@ packages: /@types/ws@8.5.10: resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==} dependencies: - '@types/node': 20.11.20 + '@types/node': 20.14.0 dev: false /@types/ws@8.5.6: @@ -11335,7 +11562,7 @@ packages: resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} requiresBuild: true dependencies: - '@types/node': 20.11.20 + '@types/node': 20.14.0 dev: true optional: true @@ -11849,7 +12076,7 @@ packages: vite: ^4 || ^5 dependencies: '@swc/core': 1.4.2 - vite: 4.5.2(@types/node@20.11.0) + vite: 4.5.2(@types/node@20.14.0) transitivePeerDependencies: - '@swc/helpers' dev: true @@ -11865,7 +12092,7 @@ packages: '@babel/plugin-transform-react-jsx-source': 7.22.5(@babel/core@7.23.9) magic-string: 0.27.0 react-refresh: 0.14.0 - vite: 4.5.2(@types/node@20.11.0) + vite: 4.5.2(@types/node@20.14.0) transitivePeerDependencies: - supports-color dev: true @@ -11881,7 +12108,7 @@ packages: '@babel/plugin-transform-react-jsx-source': 7.23.3(@babel/core@7.23.9) '@types/babel__core': 7.20.5 react-refresh: 0.14.0 - vite: 4.5.2(@types/node@20.11.0) + vite: 4.5.2(@types/node@20.14.0) transitivePeerDependencies: - supports-color dev: true @@ -11897,7 +12124,7 @@ packages: magic-string: 0.30.4 picocolors: 1.0.0 std-env: 3.4.3 - vitest: 0.34.6(happy-dom@9.20.3) + vitest: 0.34.6 dev: true /@vitest/coverage-c8@0.33.0(vitest@0.34.6): @@ -11911,7 +12138,7 @@ packages: magic-string: 0.30.7 picocolors: 1.0.0 std-env: 3.7.0 - vitest: 0.34.6(happy-dom@9.20.3) + vitest: 0.34.6 dev: true /@vitest/expect@0.34.6: @@ -14633,7 +14860,7 @@ packages: dependencies: semver: 7.5.4 shelljs: 0.8.5 - typescript: 5.5.0-dev.20240530 + typescript: 5.5.0-dev.20240603 dev: true /dset@3.1.2: @@ -15215,6 +15442,37 @@ packages: '@esbuild/win32-ia32': 0.19.12 '@esbuild/win32-x64': 0.19.12 + /esbuild@0.20.2: + resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/aix-ppc64': 0.20.2 + '@esbuild/android-arm': 0.20.2 + '@esbuild/android-arm64': 0.20.2 + '@esbuild/android-x64': 0.20.2 + '@esbuild/darwin-arm64': 0.20.2 + '@esbuild/darwin-x64': 0.20.2 + '@esbuild/freebsd-arm64': 0.20.2 + '@esbuild/freebsd-x64': 0.20.2 + '@esbuild/linux-arm': 0.20.2 + '@esbuild/linux-arm64': 0.20.2 + '@esbuild/linux-ia32': 0.20.2 + '@esbuild/linux-loong64': 0.20.2 + '@esbuild/linux-mips64el': 0.20.2 + '@esbuild/linux-ppc64': 0.20.2 + '@esbuild/linux-riscv64': 0.20.2 + '@esbuild/linux-s390x': 0.20.2 + '@esbuild/linux-x64': 0.20.2 + '@esbuild/netbsd-x64': 0.20.2 + '@esbuild/openbsd-x64': 0.20.2 + '@esbuild/sunos-x64': 0.20.2 + '@esbuild/win32-arm64': 0.20.2 + '@esbuild/win32-ia32': 0.20.2 + '@esbuild/win32-x64': 0.20.2 + dev: true + /escalade@3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} @@ -16578,6 +16836,12 @@ packages: dependencies: resolve-pkg-maps: 1.0.0 + /get-tsconfig@4.7.5: + resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==} + dependencies: + resolve-pkg-maps: 1.0.0 + dev: true + /giget@1.1.3: resolution: {integrity: sha512-zHuCeqtfgqgDwvXlR84UNgnJDuUHQcNI5OqWqFxxuk2BshuKbYhJWdxBsEo4PvKqoGh23lUAIvBNpChMLv7/9Q==} hasBin: true @@ -17819,7 +18083,7 @@ packages: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.7 - '@types/node': 20.11.20 + '@types/node': 20.14.0 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -17862,7 +18126,7 @@ packages: engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: '@jest/types': 27.5.1 - '@types/node': 20.11.20 + '@types/node': 20.14.0 dev: true /jest-regex-util@29.6.3: @@ -17875,7 +18139,7 @@ packages: engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} dependencies: '@jest/types': 28.1.3 - '@types/node': 20.11.20 + '@types/node': 20.14.0 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -17887,7 +18151,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 20.11.20 + '@types/node': 20.14.0 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -17898,7 +18162,7 @@ packages: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} dependencies: - '@types/node': 20.11.20 + '@types/node': 20.14.0 merge-stream: 2.0.0 supports-color: 8.1.1 dev: true @@ -17907,7 +18171,7 @@ packages: resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@types/node': 20.11.20 + '@types/node': 20.14.0 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -20826,7 +21090,7 @@ packages: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 - '@types/node': 20.11.0 + '@types/node': 20.14.0 long: 5.2.3 dev: false patched: true @@ -23087,6 +23351,17 @@ packages: tslib: 1.14.1 typescript: 5.3.3 + /tsx@4.11.2: + resolution: {integrity: sha512-V5DL5v1BuItjsQ2FN9+4OjR7n5cr8hSgN+VGmm/fd2/0cgQdBIWHcQ3bFYm/5ZTmyxkTDBUIaRuW2divgfPe0A==} + engines: {node: '>=18.0.0'} + hasBin: true + dependencies: + esbuild: 0.20.2 + get-tsconfig: 4.7.5 + optionalDependencies: + fsevents: 2.3.3 + dev: true + /tsx@4.7.0: resolution: {integrity: sha512-I+t79RYPlEYlHn9a+KzwrvEwhJg35h/1zHsLC2JXvhC2mdynMv6Zxzvhv5EMV6VF5qJlLlkSnMVvdZV3PSIGcg==} engines: {node: '>=18.0.0'} @@ -23297,8 +23572,14 @@ packages: engines: {node: '>=14.17'} hasBin: true - /typescript@5.5.0-dev.20240530: - resolution: {integrity: sha512-r/4r/a9tbtPRHfif0An0GLycB70C3ci3m9fhpgiv6Ekyl7mxYc4w8aX/R+vQ4OJlmPosJJUCjUbljH11g6C56g==} + /typescript@5.4.5: + resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} + engines: {node: '>=14.17'} + hasBin: true + dev: true + + /typescript@5.5.0-dev.20240603: + resolution: {integrity: sha512-gdm3Sh1A+Pjj9ZlfBEJY3o2rs3tvpcSbu3vYqcCijMe09BePQBtZlsuShuPn+zCnP+qBLxdKjFiw5v1tkna3tA==} engines: {node: '>=14.17'} hasBin: true dev: true @@ -23675,6 +23956,28 @@ packages: - terser dev: true + /vite-node@0.34.6(@types/node@20.14.0): + resolution: {integrity: sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==} + engines: {node: '>=v14.18.0'} + hasBin: true + dependencies: + cac: 6.7.14 + debug: 4.3.4(supports-color@5.5.0) + mlly: 1.4.2 + pathe: 1.1.1 + picocolors: 1.0.0 + vite: 4.5.2(@types/node@20.14.0) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + /vite-node@1.3.1(@types/node@20.11.0): resolution: {integrity: sha512-azbRrqRxlWTJEVbzInZCTchx0X69M/XPTCz4H+TLvlTcR/xH/3hkRqhOakT41fMJCMzXTu4UvegkZiEoJAWvng==} engines: {node: ^18.0.0 || >=20.0.0} @@ -23732,6 +24035,42 @@ packages: fsevents: 2.3.3 dev: true + /vite@4.5.2(@types/node@20.14.0): + resolution: {integrity: sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + '@types/node': 20.14.0 + esbuild: 0.18.20 + postcss: 8.4.35 + rollup: 3.29.4 + optionalDependencies: + fsevents: 2.3.3 + dev: true + /vite@5.1.4(@types/node@20.11.0): resolution: {integrity: sha512-n+MPqzq+d9nMVTKyewqw6kSt+R3CkvF9QAKY8obiQn8g1fwTscKxyfaYnC632HtBXAQGc1Yjomphwn1dtwGAHg==} engines: {node: ^18.0.0 || >=20.0.0} @@ -23768,7 +24107,7 @@ packages: fsevents: 2.3.3 dev: true - /vitest@0.34.6(happy-dom@9.20.3): + /vitest@0.34.6: resolution: {integrity: sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==} engines: {node: '>=v14.18.0'} hasBin: true @@ -23812,7 +24151,6 @@ packages: cac: 6.7.14 chai: 4.3.10 debug: 4.3.4(supports-color@5.5.0) - happy-dom: 9.20.3 local-pkg: 0.4.3 magic-string: 0.30.4 pathe: 1.1.1 @@ -23834,6 +24172,72 @@ packages: - terser dev: true + /vitest@0.34.6(happy-dom@9.20.3): + resolution: {integrity: sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==} + engines: {node: '>=v14.18.0'} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@vitest/browser': '*' + '@vitest/ui': '*' + happy-dom: '*' + jsdom: '*' + playwright: '*' + safaridriver: '*' + webdriverio: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + playwright: + optional: true + safaridriver: + optional: true + webdriverio: + optional: true + dependencies: + '@types/chai': 4.3.6 + '@types/chai-subset': 1.3.3 + '@types/node': 20.14.0 + '@vitest/expect': 0.34.6 + '@vitest/runner': 0.34.6 + '@vitest/snapshot': 0.34.6 + '@vitest/spy': 0.34.6 + '@vitest/utils': 0.34.6 + acorn: 8.10.0 + acorn-walk: 8.2.0 + cac: 6.7.14 + chai: 4.3.10 + debug: 4.3.4(supports-color@5.5.0) + happy-dom: 9.20.3 + local-pkg: 0.4.3 + magic-string: 0.30.4 + pathe: 1.1.1 + picocolors: 1.0.0 + std-env: 3.4.3 + strip-literal: 1.3.0 + tinybench: 2.5.1 + tinypool: 0.7.0 + vite: 4.5.2(@types/node@20.14.0) + vite-node: 0.34.6(@types/node@20.14.0) + why-is-node-running: 2.2.2 + transitivePeerDependencies: + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + /vitest@1.3.1(@types/node@20.11.0): resolution: {integrity: sha512-/1QJqXs8YbCrfv/GPQ05wAZf2eakUPLPa18vkJAKE7RXOKfVHqMZZ1WlTjiwl6Gcn65M5vpNUB6EFLnEdRdEXQ==} engines: {node: ^18.0.0 || >=20.0.0} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 63c56bbfe6c..49189862465 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -3,6 +3,7 @@ packages: - "libs/*" - "libs/@wingcloud/*" - "tools/*" + - "docs" - "docs/docs" - "apps/wing-console/packages/*" - "apps/wing-console/console/*" diff --git a/tools/hangar/package.json b/tools/hangar/package.json index 295ed462009..7f00d835bef 100644 --- a/tools/hangar/package.json +++ b/tools/hangar/package.json @@ -5,6 +5,7 @@ "scripts": { "test": "vitest run --update", "test:generate": "tsx src/generate_tests.ts", + "test:doc_examples": "vitest run src/test_corpus/doc_examples", "test:watch": "vitest watch", "bench": "vitest bench --run" }, diff --git a/tools/hangar/src/generate_tests.ts b/tools/hangar/src/generate_tests.ts index a38c5b4223c..0895c20771d 100644 --- a/tools/hangar/src/generate_tests.ts +++ b/tools/hangar/src/generate_tests.ts @@ -1,13 +1,16 @@ import { mkdirSync, readdirSync, rmSync, writeFileSync } from "fs"; -import { appWithParamsDir, sdkTestsDir, validTestDir } from "./paths"; +import { appWithParamsDir, sdkTestsDir, validTestDir, docsRoot, docsExamplesDir, validDocExamplesDir } from "./paths"; import { join, extname } from "path"; import { parseMetaCommentFromPath } from "./meta_comment"; +import { searchDirectoryForWingExamples } from "./test_examples"; const generatedTestDir = join(__dirname, "test_corpus", "valid"); const generatedSDKTestDir = join(__dirname, "test_corpus", "sdk_tests"); +const generatedWingExamplesDir = join(__dirname, "test_corpus", "doc_examples"); rmSync(generatedTestDir, { recursive: true, force: true }); rmSync(generatedSDKTestDir, { recursive: true, force: true }); +rmSync(generatedWingExamplesDir, { recursive: true, force: true }); interface GenerateTestsOptions { sourceDir: string; @@ -15,6 +18,7 @@ interface GenerateTestsOptions { isRecursive?: boolean; level?: number; includeJavaScriptInSnapshots?: boolean; + skipMarkdownSnapshot?: boolean; } function generateTests(options: GenerateTestsOptions) { @@ -24,6 +28,7 @@ function generateTests(options: GenerateTestsOptions) { isRecursive = true, level = 0, includeJavaScriptInSnapshots = true, + skipMarkdownSnapshot = false, } = options; for (const fileInfo of readdirSync(sourceDir, { withFileTypes: true })) { if (fileInfo.isDirectory() && isRecursive) { @@ -38,6 +43,7 @@ function generateTests(options: GenerateTestsOptions) { isRecursive, level: level + 1, includeJavaScriptInSnapshots, + skipMarkdownSnapshot }); continue; } @@ -76,13 +82,13 @@ function generateTests(options: GenerateTestsOptions) { test${skipText}("wing compile -t tf-aws", async () => { await compileTest("${escapedSourceDir}", "${filename}", ${JSON.stringify( metaComment?.env - )}, ${includeJavaScriptInSnapshots}); + )}, ${includeJavaScriptInSnapshots}, ${skipMarkdownSnapshot}); }); test${skipText}("wing test -t sim", async () => { await testTest("${escapedSourceDir}", "${filename}", ${JSON.stringify( metaComment?.env - )}, ${includeJavaScriptInSnapshots}); + )}, ${skipMarkdownSnapshot}); });`; mkdirSync(destination, { recursive: true }); @@ -90,6 +96,13 @@ function generateTests(options: GenerateTestsOptions) { } } +generateTests({ + sourceDir: validDocExamplesDir, + destination: generatedWingExamplesDir, + isRecursive: true, + includeJavaScriptInSnapshots: false, + skipMarkdownSnapshot: true +}); generateTests({ sourceDir: validTestDir, destination: generatedTestDir, diff --git a/tools/hangar/src/generated_test_targets.ts b/tools/hangar/src/generated_test_targets.ts index d7ff5016ae2..5707c0072ac 100644 --- a/tools/hangar/src/generated_test_targets.ts +++ b/tools/hangar/src/generated_test_targets.ts @@ -13,7 +13,8 @@ export async function compileTest( sourceDir: string, wingFile: string, env?: Record, - includeJavaScriptInSnapshots: boolean = true + includeJavaScriptInSnapshots: boolean = true, + skipMarkdownSnapshot: boolean = false ) { const fileMap: Record = {}; const wingBasename = basename(wingFile); @@ -71,13 +72,17 @@ export async function compileTest( fileMap[subpath] = fileContents; } - await createMarkdownSnapshot(fileMap, absoluteWingPath, "compile", "tf-aws"); + if (!skipMarkdownSnapshot) { + await createMarkdownSnapshot(fileMap, absoluteWingPath, "compile", "tf-aws"); + } + } export async function testTest( sourceDir: string, wingFile: string, - env?: Record + env?: Record, + skipMarkdownSnapshot: boolean = false ) { const fileMap: Record = {}; const platforms = ["sim"]; @@ -106,8 +111,9 @@ export async function testTest( if (out.stderr) fileMap["stderr.log"] = out.stderr; if (out.stdout) fileMap["stdout.log"] = out.stdout; - - await createMarkdownSnapshot(fileMap, absoluteWingPath, "test", "sim"); + if (!skipMarkdownSnapshot) { + await createMarkdownSnapshot(fileMap, absoluteWingPath, "test", "sim"); + } } function isEntrypointFile(path: string) { diff --git a/tools/hangar/src/invalid.test.ts b/tools/hangar/src/invalid.test.ts index ccb1764d77d..b0609dd99d9 100644 --- a/tools/hangar/src/invalid.test.ts +++ b/tools/hangar/src/invalid.test.ts @@ -1,6 +1,6 @@ import * as path from "path"; import { test } from "vitest"; -import { invalidTestDir, invalidWingFiles, tmpDir } from "./paths"; +import { invalidDocExampleWingFiles, invalidTestDir, invalidWingFiles, tmpDir } from "./paths"; import { runWingCommand } from "./utils"; import { parseMetaCommentFromPath } from "./meta_comment"; @@ -33,6 +33,26 @@ invalidWingFiles.forEach((wingFile) => { }); }); +invalidDocExampleWingFiles.forEach((wingFile) => { + test(wingFile, async ({ expect }) => { + const platforms = ["sim"]; + const args = ["test"]; + + const absoluteWingFile = path.join(invalidTestDir, wingFile); + const relativeWingFile = path.relative(tmpDir, absoluteWingFile); + + const out = await runWingCommand({ + cwd: tmpDir, + wingFile: relativeWingFile, + platforms, + args, + expectFailure: true + }); + + expect(out.stdout).toMatchSnapshot(); + }); +}) + const invalidLibDir = path.join(invalidTestDir, "lib"); test("invalid compile directory", async ({ expect }) => { const platforms = ["sim"]; diff --git a/tools/hangar/src/paths.ts b/tools/hangar/src/paths.ts index 5b8f5db8491..6e6fcce51fc 100644 --- a/tools/hangar/src/paths.ts +++ b/tools/hangar/src/paths.ts @@ -18,6 +18,10 @@ export const tmpDir = path.join(hangarDir, "tmp"); export const npmCacheDir = path.join(tmpDir, ".npm"); export const tmpNodeModulesDir = path.join(tmpDir, "node_modules"); export const wingSdkDir = path.join(tmpNodeModulesDir, "@winglang/sdk"); +export const docsRoot = path.join(repoRoot, "docs"); +export const docsExamplesDir = path.join(testDir, "doc_examples"); +export const invalidDocExamplesDir = path.join(docsExamplesDir, "invalid"); +export const validDocExamplesDir = path.join(docsExamplesDir, "valid"); export const npmBin = path.join(hangarDir, "node_modules/.bin/npm"); export const wingBin = path.join(tmpNodeModulesDir, ".bin/wing"); @@ -42,6 +46,11 @@ export const compatibilityTestFiles = fs .filter((f) => f.endsWith(".w")) .filter((f) => !f.endsWith("skip.w")); +export const invalidDocExampleWingFiles = fs + .readdirSync(invalidDocExamplesDir) + .filter((f) => f.endsWith(".w")) + .filter((f) => !f.endsWith("skip.w")); + /** Recursively walk a directory, yielding each file path. */ export async function* walkdir(dir: string): AsyncGenerator { for await (const d of await fs.promises.opendir(dir)) { diff --git a/tools/hangar/turbo.json b/tools/hangar/turbo.json index 00201ad03c4..1f9456b9ad6 100644 --- a/tools/hangar/turbo.json +++ b/tools/hangar/turbo.json @@ -10,10 +10,12 @@ "src/generated_test_targets.ts" ], "dependsOn": [ + "@winglang/docs#compile", "examples-valid#topo", "examples-invalid#topo", "examples-error#topo", - "examples-sdk#topo" + "examples-sdk#topo", + "examples-docs#topo" ], "outputs": ["src/test_corpus/**"] }, @@ -21,6 +23,13 @@ "dependsOn": ["^package", "test:generate"], "env": ["CI"] }, + "test:doc_examples": { + "dependsOn": [ + "^package", + "test:generate" + ], + "env": ["CI"] + }, "bench": { "dependsOn": ["^package", "examples-valid#topo"], "env": ["CI"]