diff --git a/.mergify.yml b/.mergify.yml index 433aa10c071..530fa5fc7e3 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -2,6 +2,10 @@ queue_rules: - name: default speculative_checks: 2 + merge_method: squash + commit_message_template: |- + {{ title }} (#{{ number }}) + {{ body }} pull_request_rules: - name: automatic merge @@ -11,10 +15,6 @@ pull_request_rules: Thanks for contributing, @{{author}}! This PR will now be added to the [merge queue](https://mergify.com/merge-queue), or immediately merged if `{{head}}` is up-to-date with `{{base}}` and the queue is empty. queue: name: default - merge_method: squash - commit_message_template: |- - {{ title }} (#{{ number }}) - {{ body }} conditions: - -files=.mergify.yml - -title~=(?i)wip diff --git a/docs/api/05-language-reference.md b/docs/api/05-language-reference.md index f3240ad485e..f280f6fa600 100644 --- a/docs/api/05-language-reference.md +++ b/docs/api/05-language-reference.md @@ -593,6 +593,7 @@ the following properties (given an example intrinsic `@x`): | `@assert()` | checks a condition and _throws_ if evaluated to false | | `@filename` | absolute path of the source file | | `@dirname` | absolute path of the source file's directory | +| `@target` | a string identifying the current target platform | | `@app` | the root of the construct tree | | `@unsafeCast()` | cast a value into a different type | | `@nodeof()` | obtain the [tree node](/docs/concepts/application-tree) of a preflight object | diff --git a/docs/by-example/01-introduction.md b/docs/by-example/01-introduction.md new file mode 100644 index 00000000000..9016898f11f --- /dev/null +++ b/docs/by-example/01-introduction.md @@ -0,0 +1,16 @@ +--- +title: Wing by example +id: wing-by-example +slug: / +sidebar_label: Introduction +description: Hands-on introduction to Wing using annotated code +keywords: [Wing language, api] +image: /img/wing-by-example.png +--- + + +Wing is an open source programming language for the cloud. Wing combines infrastructure and runtime code in one language, enabling developers to stay in their creative flow, and to deliver better software, faster and more securely. + +**Wing by Example** is a hands-on introduction to Wing using annotated example programs. Check out the first example or browse the list using the navigation. + +Unless stated otherwise, examples here assume the latest major release of Wing and may use new language features. If something isn't working and upgrading to the latest version doesn't fix it, please [open an issue on our GitHub](https://github.com/winglang/wing/issues/new/choose) or [send us a message on Discord](https://t.winglang.io/discord)! \ No newline at end of file diff --git a/docs/by-example/02-hello-world.md b/docs/by-example/02-hello-world.md new file mode 100644 index 00000000000..4c6d74542ca --- /dev/null +++ b/docs/by-example/02-hello-world.md @@ -0,0 +1,24 @@ +--- +title: Wing by example +id: hello-world +slug: /hello-world +sidebar_label: Hello world +description: Hello world wing example +keywords: [Wing language, example] +image: /img/wing-by-example.png +--- + +# Hello world + +By default, Wing code is executed when it's compiled. + +```js playground title="main.w" +log("Hello world!"); +``` + +```bash title="Wing console output" +# Run locally with wing console +wing it + +Hello world! +``` diff --git a/docs/by-example/03-values.md b/docs/by-example/03-values.md new file mode 100644 index 00000000000..43c1350ae80 --- /dev/null +++ b/docs/by-example/03-values.md @@ -0,0 +1,38 @@ +--- +title: Primitive values +id: primitives +slug: /primitive-values +sidebar_label: Primitive values +description: Hello world wing example +keywords: [Wing language, example, primitives, values] +image: /img/wing-by-example.png +--- + +Wing has primitive types including strings, integers, floats, booleans, etc. Here are a few basic examples. + +- Strings, which can be added together with + +- Integers and floats +- Booleans, with boolean operators as you'd expect + +```js playground title="main.w" +log("Hello " + "Wing"); + +log("1+1 = {1+1}"); +log("7.0/3.0 = {7.0/3.0}"); + +log(true && true); +log(true || false); +log(!true); +``` + +```bash title="Wing console output" +# Run locally with wing console +wing it + +Hello Wing +1+1 = 2 +7.0/3.0 = 2.3333333333333335 +true +true +false +``` \ No newline at end of file diff --git a/docs/by-example/04-variables.md b/docs/by-example/04-variables.md new file mode 100644 index 00000000000..f3cf2fb1519 --- /dev/null +++ b/docs/by-example/04-variables.md @@ -0,0 +1,45 @@ +--- +title: Variables +id: Variables +slug: /Variables +sidebar_label: Variables +description: Using variables with Wing +keywords: [Wing language, example] +image: /img/wing-by-example.png +--- + +Variables are declared with the `let` keyword. The type of most variables can be inferred automatically, but you can also add an explicit type annotation if needed. + +By default, Wing doesn't let you reassign to variables, unless you add the `var` modifier. See [this blog post](https://www.winglang.io/blog/2023/02/02/good-cognitive-friction) for more details. + +```js title="main.w" + +// var delcares a varaible. Wing infers the type +let a = "initial"; +log(a); + + +// type can also be declared +let b: num = 1; +let c: num = 2; +log("{b}, {c}"); + +// variables cannot be changed using let without var +let d: str = "Hello"; +// d = "Test"; // error: Variable is not reassignable + +// makes variable reassignable +let var s = "hello"; +s = "hello world"; // compiles +log(s); + +``` + +```bash title="Wing console output" +# Run locally with wing console +wing it + +initial +1, 2 +hello world +``` \ No newline at end of file diff --git a/docs/by-example/05-for.md b/docs/by-example/05-for.md new file mode 100644 index 00000000000..62257f924f7 --- /dev/null +++ b/docs/by-example/05-for.md @@ -0,0 +1,60 @@ +--- +title: For +id: for +slug: /for +sidebar_label: For +description: Using for loops with Wing +keywords: [Wing language, example] +image: /img/wing-by-example.png +--- + +Wing supports looping over collections with `for..in` statements. + +[for..in](/docs/api/language-reference#26-for) is used to iterate over an array, a set or a range. + +```js playground title="main.w" +// a standard for loop +for item in 1..3 { + log(item); +} + +// for-in with arrays +let arr = [1, 2, 3]; +for item in arr { + log(item); +} + +// break a loop +let items = Set[1, 2, 3]; +for item in items { + if item == 1 { + break; + } + log(item); +} + +// continue the next iteration of the loop +for item in 1..10 { + if item % 2 == 0 { + continue; + } + log(item); +} + +``` + +```bash title="Wing console output" +# Run locally with wing console +wing it + +1 +2 +1 +2 +3 +1 +3 +5 +7 +9 +``` \ No newline at end of file diff --git a/docs/by-example/06-ifelse.md b/docs/by-example/06-ifelse.md new file mode 100644 index 00000000000..0925ba156d4 --- /dev/null +++ b/docs/by-example/06-ifelse.md @@ -0,0 +1,47 @@ +--- +title: If/Else +id: if-else +slug: /if-else +sidebar_label: If/Else +description: Using if else with Wing +keywords: [Wing language, example] +image: /img/wing-by-example.png +--- + +Flow control can be done with if/else statements. The `if` statement is optionally followed by any number of `else if` clauses and a final `else` clause. + +```js playground title="main.w" +if 7 % 2 == 0 { + log("7 is even"); +} else { + log("7 is odd"); +} + +if 8 % 4 == 0 { + log("8 is divisble by 4"); +} + +if 8 % 2 == 0 || 7 % 2 == 0 { + log("either 8 or 7 are even"); +} + +let value = 9; +if value < 0 { + log("${value} is negative"); +} else if value < 10 { + log("${value} has 1 digit"); +} else { + log("{value} has multiple digits"); +} + +``` + +```bash title="Wing console output" +# Run locally with wing console +wing it + +7 is odd +8 is divisble by 4 +either 8 or 7 are even +9 has 1 digit +``` \ No newline at end of file diff --git a/docs/by-example/07-while.md b/docs/by-example/07-while.md new file mode 100644 index 00000000000..78db5b0717a --- /dev/null +++ b/docs/by-example/07-while.md @@ -0,0 +1,28 @@ +--- +title: While +id: while +slug: /while +sidebar_label: While +description: Using while statements with Wing +keywords: [Wing language, example] +image: /img/wing-by-example.png +--- + +While loops repeatedly check a condition and run a block of code until the condition is `false`. + +```js playground title="main.w" +let var i = 0; + +while i < 2 { + log("while {i}"); + i = i + 1; +} +``` + +```bash title="Wing console output" +# Run locally with wing console +wing it + +while 0 +while 1 +``` \ No newline at end of file diff --git a/docs/by-example/08-optionality.md b/docs/by-example/08-optionality.md new file mode 100644 index 00000000000..90f391318b4 --- /dev/null +++ b/docs/by-example/08-optionality.md @@ -0,0 +1,31 @@ +--- +title: Optionality +id: optionality +slug: /optionality +sidebar_label: Optionality +description: Using while statements with Wing +keywords: [Wing language, example] +image: /img/wing-by-example.png +--- + +Nullity is a primary source of bugs in software. Being able to guarantee that a value will never be null makes it easier to write safe code without constantly having to take nullity into account. + +An optional value can be either "nil" or a non-nil value. The type of an optional variable is represented by adding a question mark (`?`) to its end. + +```js playground title="main.w" +let monday: str = "doctor"; +let tuesday: str? = nil; + +// Set next to tuesday if there is a value otherwise use monday value +let next = tuesday ?? monday; + +log(next); + +``` + +```bash title="Wing console output" +# Run locally with wing console +wing it + +doctor +``` \ No newline at end of file diff --git a/docs/by-example/09-arrays.md b/docs/by-example/09-arrays.md new file mode 100644 index 00000000000..589f920945c --- /dev/null +++ b/docs/by-example/09-arrays.md @@ -0,0 +1,45 @@ +--- +title: Arrays +id: arrays +slug: /arrays +sidebar_label: Arrays +description: Using arrays with Wing +keywords: [Wing language, example] +image: /img/wing-by-example.png +--- + +Arrays are dynamically sized in Wing and are created with the [] syntax. +Individual array items can be accessed using index operation, `array[index]`, or with the `.at(index: num)` method. +Arrays are similar to dynamically sized arrays or vectors in other languages. + +```js playground example title="main.w" +let a = MutArray[1, 2, 3]; + +log("{a[0]}, {a[1]}, {a[2]}"); + +a[2] = 4; + +log("mutated value: {a[2]}"); +log("len: {a.length}"); + +let data = MutArray[1, 2, 3]; +let twoD = MutArray>[data]; + +for array in twoD { + for item in array { + log(item * 10); + } +} +``` + +```bash title="Wing console output" +# Run locally with wing console +wing it + +1, 2, 3 +mutated value: 4 +len: 3 +10 +20 +30 +``` \ No newline at end of file diff --git a/docs/by-example/10-maps.md b/docs/by-example/10-maps.md new file mode 100644 index 00000000000..c896f640364 --- /dev/null +++ b/docs/by-example/10-maps.md @@ -0,0 +1,44 @@ +--- +title: Maps +id: maps +slug: /maps +sidebar_label: Maps +description: Using maps with Wing +keywords: [Wing language, example] +image: /img/wing-by-example.png +--- + +Maps are key-value data structures that let you associate strings with any kinds of other values. + +```js playground example title="main.w" +// immutable map +let configration = Map{ + "URL" => "https://winglang.io" +}; + +// mutable map +let listOfPrices = MutMap{ + "PRODUCT_1" => 100.00, + "PRODUCT_2" => 200.00, + "PRODUCT_3" => 300.00 +}; + +// Map is inferred +let values = {"a" => 1, "b" => 2}; // immutable map, Map is inferred + +// Change the values of the mutable map +listOfPrices.set("PRODUCT_1", 500); + +log(configration.get("URL")); +log(Json.stringify(values.keys())); +log(Json.stringify(listOfPrices.get("PRODUCT_1"))); +``` + +```bash title="Wing console output" +# Run locally with wing console +wing it + +https://winglang.io +["a","b"] +500 +``` \ No newline at end of file diff --git a/docs/by-example/11-sets.md b/docs/by-example/11-sets.md new file mode 100644 index 00000000000..9e36bc8655a --- /dev/null +++ b/docs/by-example/11-sets.md @@ -0,0 +1,38 @@ +--- +title: Sets +id: sets +slug: /sets +sidebar_label: Sets +description: Using sets with Wing +keywords: [Wing language, example] +image: /img/wing-by-example.png +--- + + +A set keeps track of collection of unique values - a specific value can only be added to a set once. Sets are immutable by default `Set`, and you can make them immutable using `MutSet`. + + +```js playground example title="main.w" +// mutable set +let unqiueNumbers = MutSet[1, 2, 3, 3, 3]; +unqiueNumbers.add(4); +unqiueNumbers.delete(1); + +// immutable set, values cannot be added or removed +let uniqueStrings = Set["unique", "values", "values"]; + + +log(Json.stringify(unqiueNumbers.toArray())); +log(Json.stringify(unqiueNumbers.size)); + +log(Json.stringify(uniqueStrings.toArray())); +``` + +```bash title="Wing console output" +# Run locally with wing console +wing it + +[2,3,4] +3 +["unique", "values"] +``` \ No newline at end of file diff --git a/docs/by-example/12-structs.md b/docs/by-example/12-structs.md new file mode 100644 index 00000000000..28d6db99748 --- /dev/null +++ b/docs/by-example/12-structs.md @@ -0,0 +1,49 @@ +--- +title: Structs +id: structs +slug: /structs +sidebar_label: Structs +description: Using arrays with Wing +keywords: [Wing language, example] +image: /img/wing-by-example.png +--- + +Structs are custom data types you can define to store structured information. They're loosely modeled after typed JSON literals in JavaScript. + +```js playground example title="main.w" +// Define a simple structure called `Example` +struct Example { + a: str; + b: num; + c: bool?; +} + +// Define another structure called `MyData` that includes composition +struct MyData { + a: str; + b: num?; + c: Example; +} + +// Creating an instance of `MyData` with some fields initialized +let data = MyData { + a: "hello", + c: { + a: "world", + b: 42, + } +}; + +log(data.a); +log(data.c.a); +log(data.c.b); +``` + +```bash title="Wing console output" +# Run locally with wing console +wing it + +hello +world +42 +``` \ No newline at end of file diff --git a/docs/by-example/13-bytes.md b/docs/by-example/13-bytes.md new file mode 100644 index 00000000000..38eaaca0ed9 --- /dev/null +++ b/docs/by-example/13-bytes.md @@ -0,0 +1,42 @@ +--- +title: Bytes +id: bytes +slug: /bytes +sidebar_label: Bytes +description: Hash values in Wing with SHA256 +keywords: [Wing language, Hash, SHA256] +image: /img/wing-by-example.png +--- + +When working with binary files like images, audio, or other binary formats, you often need to manipulate data at the byte level. + +```js playground example title="main.w" +// get bytes from raw value +let rawData: bytes = bytes.fromRaw([104, 101, 108, 108, 111]); + +// get the bytes from a string +let rawString: bytes = bytes.fromString("hello"); + +// get bytes from base64 encoded value +let base64: bytes = bytes.fromBase64("aGVsbG8="); + +// get bytes from hex value +let hex: bytes = bytes.fromHex("68656c6c6f"); + +log(Json.stringify(rawData)); +log(Json.stringify(rawString)); +log(Json.stringify(base64)); +log(Json.stringify(hex)); +``` + +```bash title="Wing console output" +# Run locally with wing console +{"_data":{"0":104,"1":101,"2":108,"3":108,"4":111}} +{"_data":{"0":104,"1":101,"2":108,"3":108,"4":111}} +{"_data":{"0":104,"1":101,"2":108,"3":108,"4":111}} +{"_data":{"0":104,"1":101,"2":108,"3":108,"4":111}} +``` + + + + diff --git a/docs/by-example/13-trailing-struct-parameters.md b/docs/by-example/13-trailing-struct-parameters.md new file mode 100644 index 00000000000..a9d14c24922 --- /dev/null +++ b/docs/by-example/13-trailing-struct-parameters.md @@ -0,0 +1,45 @@ +--- +title: Trailing struct parameters +id: trailing-structs-parameters +slug: /trailing-structs-parameters +sidebar_label: Trailing struct parameters +description: Passing fields directly to a function +keywords: [Wing language, example] +image: /img/wing-by-example.png +--- + +If the last parameter of a function is a struct, then you can pass its fields directly. + +```js playground example title="main.w" +// struct for the function params +struct NameOptions { + formal: bool; + caps: bool; +} + +let greet = (name: str, options: NameOptions) => { + let var prefix = "Hi, "; + if options.formal { + prefix = "Greetings, "; + } + let var message = "{prefix}{name}"; + if options.caps { + message = message.uppercase(); + } + log(message); +}; + +greet("kermit", NameOptions { formal: true, caps: false }); + +// Pass fields directly as the last param is a Struct +greet("kermit", formal: true, caps: false); + +``` + +```bash title="Wing console output" +# Run locally with wing console +wing it + +Greetings, kermit +Greetings, kermit +``` \ No newline at end of file diff --git a/docs/by-example/14-async-functions.md b/docs/by-example/14-async-functions.md new file mode 100644 index 00000000000..e381fc6b093 --- /dev/null +++ b/docs/by-example/14-async-functions.md @@ -0,0 +1,53 @@ +--- +title: Inflight functions +id: inflight-functions +slug: /inflight-functions +sidebar_label: Async inflight functions +description: Using functions with Wing +keywords: [Wing language, example] +image: /img/wing-by-example.png +--- + +Wing supports two function types, [preflight and inflight](/docs/concepts/inflights). + +- Preflight: Code that runs once, at compile time, and generates the infrastructure configuration of your cloud application. For example, setting up databases, queues, storage buckets, API endpoints, etc. + +- Inflight: Code that runs at runtime and implements your application's behavior. For example, handling API requests, processing queue messages, etc. Inflight code can be executed on various compute platforms in the cloud, such as function services (such as AWS Lambda or Azure Functions), containers (such as ECS or Kubernetes), VMs or even physical servers. + +By default, most functions are preflight. A function is inflight if it has the `inflight` keyword or if the function is defined inside of another inflight function. + +```js playground example title="main.w" +bring cloud; +bring util; + +// defining a cloud.Function resource +let countWords = new cloud.Function(inflight (payload: Json?): Json => { + return "{payload?.tryAsStr()?.split(" ")?.length ?? 0}"; +}) as "countWords"; + +// simulate a long running task, to run async +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"); + + // invokes async + longTask.invokeAsync(""); + + // continue to execute + log("task started"); +}) as "Invoke Me"; +``` + +```bash title="Wing console output" +# Run locally with wing console +wing it + +3 +``` \ No newline at end of file diff --git a/docs/by-example/14-functions.md b/docs/by-example/14-functions.md new file mode 100644 index 00000000000..f7015cefd4f --- /dev/null +++ b/docs/by-example/14-functions.md @@ -0,0 +1,43 @@ +--- +title: Functions +id: functions +slug: /functions +sidebar_label: Functions +description: Using functions with Wing +keywords: [Wing language, example] +image: /img/wing-by-example.png +--- + +Wing supports two function types [preflight and inflight](/docs/concepts/inflights). + +- Preflight: Code that runs once, at compile time, and generates the infrastructure configuration of your cloud application. For example, setting up databases, queues, storage buckets, API endpoints, etc. + +- Inflight: Code that runs at runtime and implements your application's behavior. For example, handling API requests, processing queue messages, etc. Inflight code can be executed on various compute platforms in the cloud, such as function services (such as AWS Lambda or Azure Functions), containers (such as ECS or Kubernetes), VMs or even physical servers. + +By default functions are preflight functions. + +```js playground example title="main.w" +bring cloud; + +// preflight function - can be called at compile time +let plus = (num1: num, num2: num) => { + return num1 + num2; +}; + +// Inflight code here is run at runtime +let func = new cloud.Function(inflight (payload:Json?) => { + // When when the function it excuted on the cloud + log(Json.stringify(payload)); +}); + +let value = plus(1, 2); + +log(value); +``` + +```bash title="Wing console output" +# Run locally with wing console +wing it + +3 +``` \ No newline at end of file diff --git a/docs/by-example/15-variadic-functions.md b/docs/by-example/15-variadic-functions.md new file mode 100644 index 00000000000..92e0598f502 --- /dev/null +++ b/docs/by-example/15-variadic-functions.md @@ -0,0 +1,39 @@ +--- +title: Variadic Functions +id: variadic-functions +slug: /variadic-functions +sidebar_label: Variadic Functions +description: Using variadic functions with Wing +keywords: [Wing language, variadic] +image: /img/wing-by-example.png +--- + + +Variadic functions can be called with any number of trailing arguments. + +```js playground example title="main.w" +// Function that will take an arbitrary number of numbers as arguments. +let plus = (...numbers: Array) => { + let var value = 0; + + for number in numbers { + value = value + number; + } + + return value; +}; + +// in this example you can pass any many numbers as you want +log(plus(1, 2)); +log(plus(1, 2, 3)); +log(plus(1, 2, 3, 4)); +``` + +```bash title="Wing console output" +# Run locally with wing console +wing it + +3 +6 +10 +``` \ No newline at end of file diff --git a/docs/by-example/16-closures.md b/docs/by-example/16-closures.md new file mode 100644 index 00000000000..b38d28d9910 --- /dev/null +++ b/docs/by-example/16-closures.md @@ -0,0 +1,38 @@ +--- +title: Closures +id: closures +slug: /closures +sidebar_label: Closures +description: Closures with Wing +keywords: [Wing language, variadic] +image: /img/wing-by-example.png +--- + +[Closures](https://en.wikipedia.org/wiki/Closure_(computer_programming)) are functions that captures variables from its surrounding lexical scope, allowing those variables to persist even after the function is executed outside its original context. + + +```js playground example title="main.w" +let createCounter = (): (): num => { + let var count = 0; // This variable is part of the closure + + return () => { + count = count + 1; + return count; + }; +}; + +let counter = createCounter(); + +log(counter()); +log(counter()); +log(counter()); +``` + +```bash title="Wing console output" +# Run locally with wing console +wing it + +1 +2 +3 +``` \ No newline at end of file diff --git a/docs/by-example/17-recursion.md b/docs/by-example/17-recursion.md new file mode 100644 index 00000000000..22e545a1d44 --- /dev/null +++ b/docs/by-example/17-recursion.md @@ -0,0 +1,28 @@ +--- +title: Recursion +id: recursion +slug: /recursion +sidebar_label: Recursion +description: Recursion with Wing +keywords: [Wing language, variadic] +image: /img/wing-by-example.png +--- + +```js playground example title="main.w" +let fact = (n: num): num => { + if n == 0 { + return 1; + } + return n * fact(n - 1); +}; + + +log(fact(7)); +``` + +```bash title="Wing console output" +# Run locally with wing console +wing it + +5040 +``` \ No newline at end of file diff --git a/docs/by-example/18-methods.md b/docs/by-example/18-methods.md new file mode 100644 index 00000000000..0b283b78ea0 --- /dev/null +++ b/docs/by-example/18-methods.md @@ -0,0 +1,70 @@ +--- +title: Methods +id: methods +slug: /methods +sidebar_label: Methods +description: Methods with Wing +keywords: [Wing language, variadic] +image: /img/wing-by-example.png +--- + +```js playground example title="main.w" +// Rect type +struct Rect { + width: num; + height: num; +} + +// methods accepting Rect type +let area = (r: Rect): num => { + return r.height * r.width; +}; + +// methods accepting Rect type +let perim = (r: Rect): num => { + return 2 * r.height + 2 * r.width; +}; + +let r = Rect { + height: 5, + width: 10 +}; + +log("area: {area(r)}"); +log("perim: {perim(r)}"); + +// Or Rectangle class with public methods +class Rectangle { + height: num; + width: num; + + new(height: num, width: num) { + this.height = height; + this.width = width; + } + + pub area(): num { + return this.height * this.width; + } + + pub perim(): num { + return 2 * this.height + 2 * this.width; + } + +} + +let x = new Rectangle(5, 10); +log(x.area()); +log(x.perim()); + +``` + +```bash title="Wing console output" +# Run locally with wing console +wing it + +area: 50 +perim: 30 +50 +30 +``` \ No newline at end of file diff --git a/docs/by-example/19-interfaces.md b/docs/by-example/19-interfaces.md new file mode 100644 index 00000000000..7171084c6bc --- /dev/null +++ b/docs/by-example/19-interfaces.md @@ -0,0 +1,71 @@ +--- +title: Interfaces +id: interfaces +slug: /interfaces +sidebar_label: Interfaces +description: Interfaces with Wing +keywords: [Wing language, interfaces] +image: /img/wing-by-example.png +--- + +```js playground example title="main.w" +bring math; + +interface Geometry { + area(): num; + perim(): num; +} + +class Rect impl Geometry { + width: num; + height: num; + new(width: num, height: num) { + this.width = width; + this.height = height; + } + + pub area(): num { + return this.height * this.width; + } + + pub perim(): num { + return 2 * this.height + 2 * this.width; + } +} + +class Circle impl Geometry { + radius: num; + new(radius: num) { + this.radius = radius; + } + + pub area(): num { + return math.PI * this.radius * this.radius; + } + + pub perim(): num { + return 2 * math.PI * this.radius; + } +} + + + +let r = new Rect(3, 4); +let c = new Circle(5); + +log(r.area()); +log(r.perim()); + +log(c.area()); +log(c.perim()); +``` + +```bash title="Wing console output" +# Run locally with wing console +wing it + +12 +14 +78.53981633974483 +31.41592653589793 +``` \ No newline at end of file diff --git a/docs/by-example/20-sleep.md b/docs/by-example/20-sleep.md new file mode 100644 index 00000000000..1acf0811c04 --- /dev/null +++ b/docs/by-example/20-sleep.md @@ -0,0 +1,50 @@ +--- +title: Sleep +id: sleep +slug: /sleep +sidebar_label: Sleep +description: Suspends execution for a given duration. +keywords: [Wing language, sleep] +image: /img/wing-by-example.png +--- + +`util.sleep` is an [inflight](/docs/concepts/inflights) api. + +You cannot sleep in preflight code. + +```js playground example title="main.w" +bring util; +bring cloud; + +// util.sleep has inflight api for sleep +inflight () => { + util.sleep(40s); +}; + +// example showing cloud function that sleeps +let longTask = new cloud.Function(inflight () => { + + let timer1 = () => { + log("Time 1 fired"); + util.sleep(5s); + }; + + let timer2 = () => { + log("Time 2 fired"); + util.sleep(2s); + }; + + timer1(); + timer2(); +}); + +``` + +```bash title="Wing console output" +# Run locally with wing console +wing it + +# Run the cloud function using the console (to trigger the inflight function) +Time 1 fired +Time 2 fired +``` \ No newline at end of file diff --git a/docs/by-example/21-string-functions.md b/docs/by-example/21-string-functions.md new file mode 100644 index 00000000000..20e6c174fe0 --- /dev/null +++ b/docs/by-example/21-string-functions.md @@ -0,0 +1,45 @@ +--- +title: String functions +id: string-functions +slug: /string-functions +sidebar_label: String functions +description: Functions for string values in Wing +keywords: [Wing language, string, functions] +image: /img/wing-by-example.png +--- + +Wing provides many useful [string-related functions](/docs/api/standard-library/std/string#string-). Here are some examples to give you a sense of the usage. + +```js playground example title="main.w" +log("test".contains("es")); +log("test".length); +log("test".startsWith("te")); +log("test".endsWith("st")); +log("test".indexOf("e")); + +let x = ["a", "b"]; +log(x.join("-")); + +log("foo".replace("o", "0")); +log("foo".replaceAll("o", "0")); +log(Json.stringify(("a-b-c-d-e".split("-")))); +log("TEST".lowercase()); +log("test".uppercase()); +``` + +```bash title="Wing console output" +# Run locally with wing console +wing it + +true +4 +true +true +1 +a-b +f0o +f00 +["a","b","c","d","e"] +test +TEST +``` \ No newline at end of file diff --git a/docs/by-example/22-regex.md b/docs/by-example/22-regex.md new file mode 100644 index 00000000000..5e0432bd153 --- /dev/null +++ b/docs/by-example/22-regex.md @@ -0,0 +1,57 @@ +--- +title: Regular expressions +id: regex +slug: /regex +sidebar_label: Regular expressions +description: Functions for string values in Wing +keywords: [Wing language, string, functions] +image: /img/wing-by-example.png +--- + +Wing offers built-in support for regular expressions. Here are some examples of common regexp-related tasks in Wing. + + +```js playground example title="main.w" + +let r = regex.compile("p([a-z]+)ch"); + +// Checks if the regular expression matches the provided text. +log(r.test("peach")); + +// Finds the first occurrence of the pattern within the text. +log(r.find("peach peach") ?? ""); + +// Finds all non-overlapping occurrences of the pattern within the text. +log(Json.stringify(r.findAll("peach punch pinch"))); + +// Finds the start and end index of all matches within the text. +log(Json.stringify(r.findAllIndex("peach punch pinch"))); + +// Finds the start and end index of the first match within the text. +log(Json.stringify(r.findIndex("peach"))); + +// Finds the first match and its submatches. +log(Json.stringify(r.findSubmatch("peach punch"))); + +// Finds the start and end index of the match and all submatches. +log(Json.stringify(r.findSubmatchIndex("peach punch"))); + +// Replaces all occurrences of the match with a replacement string. +log(r.replaceAll("a peach", "")); +``` + +```bash title="Wing console output" +# Run locally with wing console +wing it + +true +peach +["peach","punch","pinch"] +[[0,5],[6,11],[12,17]] +[0,5] +["peach","ea"] +[[0,5],[1,3]] +a +``` + + diff --git a/docs/by-example/23-Json.md b/docs/by-example/23-Json.md new file mode 100644 index 00000000000..31427a441b9 --- /dev/null +++ b/docs/by-example/23-Json.md @@ -0,0 +1,88 @@ +--- +title: Json +id: json +slug: /json +sidebar_label: Json +description: Create Json values in Wing +keywords: [Wing language, json] +image: /img/wing-by-example.png +--- + +Wing has a dedicated type named `Json` for representing [JSON](https://www.json.org/json-en.html). A `Json` value can be an object, but it can also be an array, string, boolean, number, or null. + +```js playground example title="main.w" +let person = Json { + firstName: "John", + lastName: "Smith" +}; + +// stringify +log(Json.stringify(person)); + +// parse +log(Json.parse("\{\"firstName\":\"John\",\"lastName\":\"Smith\"}")); + +// Try and parse +if let jsonFromTryParse = Json.tryParse("\{\"firstName\":\"John\",\"lastName\":\"Smith\"}") { + log("{jsonFromTryParse}"); +} else { + log("failed to parse string to JSON"); +} + +// Deep copy of Json +let newPerson = Json.deepCopy(person); +log(Json.stringify(person)); + +// iterate over keys +for k in Json.keys(person) { + let value = person.get(k); + log("found key {k} with value {value}"); +} + +// iterate over values +for value in Json.values(person) { + log("found value {value}"); +} + +// iterate over array +let arrayValue = Json ["a", "b", "c"]; +for v in Json.values(arrayValue) { + log(str.fromJson(v)); +} + +// Convert to structs +struct Foo { + val1: str; + val2: num; +} + +let jFoo = { + val1: "cool", + val2: 21 +}; + +let foo = Foo.fromJson(jFoo); +log(Json.stringify(foo)); +``` + +```bash title="Wing console output" +# Run locally with wing console +wing it + +{"firstName":"John","lastName":"Smith"} +{ firstName: 'John', lastName: 'Smith' } +{"firstName":"John","lastName":"Smith"} +{"firstName":"John","lastName":"Smith"} +found key firstName with value "John" +found key lastName with value "Smith" +found value "John" +found value "Smith" +a +b +c +{"val1":"cool","val2":21} +``` + + + + diff --git a/docs/by-example/24-time.md b/docs/by-example/24-time.md new file mode 100644 index 00000000000..a3223afea9c --- /dev/null +++ b/docs/by-example/24-time.md @@ -0,0 +1,52 @@ +--- +title: Time +id: time +slug: /time +sidebar_label: Time +description: Create time/date values in Wing +keywords: [Wing language, time, date] +image: /img/wing-by-example.png +--- + +```js playground example title="main.w" +let now = datetime.utcNow(); + +log(now.toIso()); + +let then = datetime.fromIso("2020-09-09"); +log(then.toIso()); + +log(then.year); +log(then.month); +log(then.dayOfWeek); +log(then.dayOfMonth); +log(then.hours); +log(then.min); +log(then.sec); +log(then.ms); + +log(then.timestamp); +log(then.timestampMs); +log(then.timezone); +``` + +```bash title="Wing console output" +# Run locally with wing console +2024-09-09T12:25:01.080Z +2020-09-09T00:00:00.000Z +2020 +8 +3 +9 +0 +0 +0 +0 +1599609600 +1599609600000 +0 +``` + + + + diff --git a/docs/by-example/25-random.md b/docs/by-example/25-random.md new file mode 100644 index 00000000000..badc2474458 --- /dev/null +++ b/docs/by-example/25-random.md @@ -0,0 +1,36 @@ +--- +title: Random +id: random +slug: /random +sidebar_label: Random +description: Create random values in Wing +keywords: [Wing language, random] +image: /img/wing-by-example.png +--- + +Using the [math standard library](/docs/api/standard-library/math/api-reference) you can generate random numbers. + +_Note: The random numbers that are generated are not random enough for sensitive security tasks, such as generating encryption keys, tokens for authentication, or anything requiring unpredictable randomness for security purposes._ + + +```js playground example title="main.w" +bring math; + +log(math.random(100)); + +log(math.ceil(math.random(100))); + +log((math.random()*5)+5); + +``` + +```bash title="Wing console output" +# Run locally with wing console, output will vary +46.58171364582826 +4 +5.721934646951212 +``` + + + + diff --git a/docs/by-example/26-number-parsing.md b/docs/by-example/26-number-parsing.md new file mode 100644 index 00000000000..8041de31e83 --- /dev/null +++ b/docs/by-example/26-number-parsing.md @@ -0,0 +1,29 @@ +--- +title: Number parsing +id: number-parsing +slug: /number-parsing +sidebar_label: Number Parsing +description: Parse values into numbers +keywords: [Wing language, random] +image: /img/wing-by-example.png +--- + +```js playground example title="main.w" +let j = Json { a: 100 }; + +let x: num = num.fromStr("1"); +let y: num = num.fromJson(j.get("a")); + +log(x); +log(y); +``` + +```bash title="Wing console output" +# Run locally with wing console +1 +100 +``` + + + + diff --git a/docs/by-example/27-url-parsing.md b/docs/by-example/27-url-parsing.md new file mode 100644 index 00000000000..28d005632df --- /dev/null +++ b/docs/by-example/27-url-parsing.md @@ -0,0 +1,50 @@ +--- +title: URL parsing +id: url-parsing +slug: /url-parsing +sidebar_label: URL parsing +description: Parse urls in Wing +keywords: [Wing language, URL] +image: /img/wing-by-example.png +--- + +Parse urls using the http module, works with inflight closures. + +```js playground example title="main.w" +bring http; +bring cloud; + +new cloud.Function(inflight () => { + let parts = http.parseUrl("postgres://user:pass@host.com:5432/path?k=v#f"); + + log(parts.hostname); + log(parts.host); + log(parts.hash); + log(parts.origin); + log(parts.username); + log(parts.password); + log(parts.pathname); + log(parts.port); + log(parts.protocol); + log(parts.search); + +}); +``` + +```bash title="Wing console output" +# Run locally with wing console and invoke the cloud function +host.com +host.com:5432 +#f +null +user +pass +/path +5432 +postgres: +?k=v +``` + + + + diff --git a/docs/by-example/28-sha256.md b/docs/by-example/28-sha256.md new file mode 100644 index 00000000000..45f5d63162b --- /dev/null +++ b/docs/by-example/28-sha256.md @@ -0,0 +1,26 @@ +--- +title: SHA256 Hashes +id: sha256 +slug: /sha256 +sidebar_label: SHA256 Hashes +description: Hash values in Wing with SHA256 +keywords: [Wing language, Hash, SHA256] +image: /img/wing-by-example.png +--- + +```js playground example title="main.w" +bring util; + +let value = util.sha256("sha256 this string"); + +log(value); +``` + +```bash title="Wing console output" +# Run locally with wing console +1af1dfa857bf1d8814fe1af8983c18080019922e557f15a8a0d3db739d77aacb +``` + + + + diff --git a/docs/by-example/29-base64-encoding.md b/docs/by-example/29-base64-encoding.md new file mode 100644 index 00000000000..096ffcccd38 --- /dev/null +++ b/docs/by-example/29-base64-encoding.md @@ -0,0 +1,32 @@ +--- +title: Base64 Encoding +id: base64-encoding +slug: /base64-encoding +sidebar_label: Base64 Encoding +description: Encode and decode Base64 values +keywords: [Wing language, Base64] +image: /img/wing-by-example.png +--- + +```js playground example title="main.w" +bring util; + +let data = "abc123!?$*&()'-=@~"; + +let encoded = util.base64Encode(data); +log(encoded); + + +let decoded = util.base64Decode(encoded); +log(decoded); +``` + +```bash title="Wing console output" +# Run locally with wing console +YWJjMTIzIT8kKiYoKSctPUB+ +abc123!?$*&()'-=@~ +``` + + + + diff --git a/docs/by-example/30-reading-writing-files.md b/docs/by-example/30-reading-writing-files.md new file mode 100644 index 00000000000..b624ff9c867 --- /dev/null +++ b/docs/by-example/30-reading-writing-files.md @@ -0,0 +1,45 @@ +--- +title: Reading and writing files +id: reading-and-writing-files +slug: /reading-and-writing-files +sidebar_label: Reading and writing files +description: Reading and writing files with Wing +keywords: [Wing language, Reading files, Writing files] +image: /img/wing-by-example.png +--- + +```js playground example title="main.w" +bring fs; + +let filename: str = "/tmp/test.txt"; + +log(fs.exists(filename)); + +fs.writeFile(filename, "hello world!"); +fs.exists(filename); + +let file: str = fs.readFile(filename); + +log(file); +log(fs.extension(filename) ?? ""); +log(fs.isDir(filename)); + +fs.appendFile(filename, "testing"); + +let extendedValue = fs.readFile(filename); + +log(extendedValue); +``` + +```bash title="Wing console output" +# Run locally with wing console +true +hello world! +txt +false +hello world!testing +``` + + + + diff --git a/docs/by-example/31-directories.md b/docs/by-example/31-directories.md new file mode 100644 index 00000000000..27aac338783 --- /dev/null +++ b/docs/by-example/31-directories.md @@ -0,0 +1,43 @@ +--- +title: Directories +id: directories +slug: /directories +sidebar_label: Directories +description: Directories +keywords: [Wing language, Directories] +image: /img/wing-by-example.png +--- + +Use the `fs` ("filesystem") module to make, read, check, remove directories. + +```js playground example title="main.w" +bring fs; + +// Make directory +fs.mkdir("subdir"); + +// Check if path is directory +fs.isDir("subdir"); + +// Set permissions on directory +fs.setPermissions("subdir", "0755"); + +// Try and parse +if let dirTryFrom = fs.tryReaddir("random-folder") { + log("Directory is there"); +} else { + log("No directory found"); +} + +// Remove a directory +fs.remove("subdir"); +``` + +```bash title="Wing console output" +# Run locally with wing console +No directory found +``` + + + + diff --git a/docs/by-example/32-testing.md b/docs/by-example/32-testing.md new file mode 100644 index 00000000000..7274e2f1397 --- /dev/null +++ b/docs/by-example/32-testing.md @@ -0,0 +1,45 @@ +--- +title: Testing +id: testing +slug: /testing +sidebar_label: Testing +description: Directories +keywords: [Wing language, Directories] +image: /img/wing-by-example.png +--- + +Wing incorporates a [lightweight testing framework](/docs/concepts/tests), which is built around the `wing test` command and the `test` keyword. + +```js playground example title="main.w" +bring math; +bring cloud; +let b = new cloud.Bucket(); + +test "abs" { + assert(1 == math.abs(-1)); +} + +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 fails" { + throw("test throws an exception fails"); +} +``` + +```bash title="Wing console output" +# Run locally with wing console +No directory found +``` + + + + diff --git a/docs/by-example/33-http-client.md b/docs/by-example/33-http-client.md new file mode 100644 index 00000000000..ab71152f8c0 --- /dev/null +++ b/docs/by-example/33-http-client.md @@ -0,0 +1,45 @@ +--- +title: HTTP Client +id: http-client +slug: /http-client +sidebar_label: HTTP Client +description: Directories +keywords: [Wing language, HTTP] +image: /img/wing-by-example.png +--- + +The Wing standard library comes with [HTTP support](/docs/api/standard-library/http/api-reference). + +In this example we’ll use it to issue a simple HTTP request. + +```js playground example title="main.w" +bring http; +bring cloud; + +struct Pokemon { + id: num; + name: str; + order: num; + weight: num; +} + +new cloud.Function(inflight () => { + let x = http.get("https://pokeapi.co/api/v2/pokemon/ditto"); + + // response status + log(x.status); + + // parse string response as a JSON object + let data = Json.parse(x.body); + + // cast JSON response into struct + let ditto = Pokemon.fromJson(data); + log(ditto.name); +}); +``` + +```bash title="Wing console output" +# Run locally with wing console +200 +ditto +``` diff --git a/docs/by-example/34-http-server.md b/docs/by-example/34-http-server.md new file mode 100644 index 00000000000..61e702d4926 --- /dev/null +++ b/docs/by-example/34-http-server.md @@ -0,0 +1,76 @@ +--- +title: HTTP Server +id: http-server +slug: /http-server +sidebar_label: HTTP Server +description: Directories +keywords: [Wing language, HTTP] +image: /img/wing-by-example.png +--- + +You can create HTTP servers using the [cloud.Api](/docs/api/standard-library/cloud/api) standard library. + +This example shows an example of using an API with a GET and PUT endpoint that interacts with a bucket. + + +```js playground example title="main.w" +bring cloud; +bring http; + +let noteBucket = new cloud.Bucket(); + +let api = new cloud.Api(); + +api.get("/note", inflight (request) => { + let noteName = request.query.get("name"); + let note = noteBucket.get(noteName); + + return { + status: 200, + body: note + }; +}); + +api.put("/note/:name", inflight (request) => { + let note = request.body; + let noteName = request.vars.get("name"); + + if (note == "") { + return { + status: 400, + body: "note is required" + }; + } + + noteBucket.put(noteName, note ?? ""); + // handler implicitly returns `status: 200` by default +}); + +// Consumer functions (not required for the app to work, but useful for testing) +new cloud.Function(inflight (event: Json?) => { + if let event = event { + let parts = event.asStr().split(":"); + let name = parts.at(0); + let note = parts.at(1); + + let response = http.put("{api.url}/note/{name}", { + body: "{note}" + }); + return response.body; + } + + return "event is required `NAME:NOTE`"; +}) as "Consumer-PUT"; + +new cloud.Function(inflight (event: Json?) => { + if let event = event { + return http.get("{api.url}/note?name={event}").body; + } + + return "event is required `NAME`"; +}) as "Consumer-GET"; +``` + + + + diff --git a/docs/by-example/35-exec-processes.md b/docs/by-example/35-exec-processes.md new file mode 100644 index 00000000000..f3a10ee6868 --- /dev/null +++ b/docs/by-example/35-exec-processes.md @@ -0,0 +1,39 @@ +--- +title: Exec processes +id: exec-processed +slug: /exec-processed +sidebar_label: Exec processes +description: Exec'ing Processes +keywords: [Wing language, HTTP] +image: /img/wing-by-example.png +--- + +```js playground example title="main.w" +bring util; + +let output = util.exec("echo", ["-n", "Hello, Wing!"]); + +// exec with custom environment variables +let output2 = util.exec("bash", ["--norc", "--noprofile", "-c", "echo $WING_TARGET $ENV_VAR"], { env: { ENV_VAR: "Wing" } }); + +// exec with inherited environment variables +let output3 = util.exec("bash", ["--norc", "--noprofile", "-c", "echo $WING_TARGET $ENV_VAR"], { inheritEnv: true }); + +// exec with current working directory +let output4 = util.exec("bash", ["--norc", "--noprofile", "-c", "echo Hello"], { cwd: "/tmp" }); + +log(output); +log(output2); +log(output3); +log(output4); +``` + +```bash title="Wing console output" +# Run locally with wing console +Hello, Wing! +Wing +sim +Hello +``` + + diff --git a/docs/contributing/998-archived/01-compile-targets.md b/docs/contributing/998-archived/01-compile-targets.md index 8bac3608889..9ce21c51ff4 100644 --- a/docs/contributing/998-archived/01-compile-targets.md +++ b/docs/contributing/998-archived/01-compile-targets.md @@ -74,7 +74,7 @@ new cloud.Function(inflight ()=> { // push a message to queue queue.push("m"); // sleep according to target - if util.env("WING_TARGET") == "sim" { + if @target == "sim" { log("Running on Simulator, sleeping for 1s"); util.sleep(1s); } else { @@ -85,7 +85,7 @@ new cloud.Function(inflight ()=> { }); ``` -In this example, we want to sleep briefly for the Simulator target and for 30 seconds for cloud targets, this is achieved using the `WING_TARGET` environment variable. +In this example, we want to sleep briefly for the simulator target and for 30 seconds for cloud targets, this is achieved using the `@target` intrinsic function. ## Compiler plugins diff --git a/docs/docs/03-platforms/01-understanding-platforms.md b/docs/docs/03-platforms/01-understanding-platforms.md index 52b5c7db29e..a8ae8638259 100644 --- a/docs/docs/03-platforms/01-understanding-platforms.md +++ b/docs/docs/03-platforms/01-understanding-platforms.md @@ -121,7 +121,7 @@ vpc_api_gateway = true There might be times when you need to write code that is specific to a particular platform target. For example, you may want to activate a verbose logging service only when testing locally to save on cloud log storage costs. -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: +The `@target` intrinsic returns the current platform target as a string value, which you can use to conditionally run target-specific code. See the example below: ```js playground example bring cloud; @@ -138,7 +138,7 @@ new cloud.Function(inflight ()=> { // push a message to queue queue.push("m"); // sleep according to target - if util.env("WING_TARGET") == "sim" { + if @target == "sim" { log("Running on Simulator, sleeping for 1s"); util.sleep(1s); } else { diff --git a/packages/@winglang/sdk/src/cloud/function.ts b/packages/@winglang/sdk/src/cloud/function.ts index ea4a33653f7..ba7ee65a63e 100644 --- a/packages/@winglang/sdk/src/cloud/function.ts +++ b/packages/@winglang/sdk/src/cloud/function.ts @@ -122,10 +122,6 @@ export class Function extends Resource implements IInflightHost { const entrypoint = join(workdir, `${assetName}.cjs`); this.entrypoint = entrypoint; - if (process.env.WING_TARGET) { - this.addEnvironment("WING_TARGET", process.env.WING_TARGET); - } - if (props.concurrency !== undefined && props.concurrency <= 0) { throw new Error( "concurrency option on cloud.Function must be a positive integer" diff --git a/packages/@winglang/sdk/src/cloud/service.ts b/packages/@winglang/sdk/src/cloud/service.ts index 1289da7eb3e..4d67f7ac8f9 100644 --- a/packages/@winglang/sdk/src/cloud/service.ts +++ b/packages/@winglang/sdk/src/cloud/service.ts @@ -107,10 +107,6 @@ export class Service extends Resource implements IInflightHost { const entrypoint = join(workdir, `${this.assetName}.cjs`); this.entrypoint = entrypoint; - if (process.env.WING_TARGET) { - this.addEnvironment("WING_TARGET", process.env.WING_TARGET); - } - this.handler = handler; } diff --git a/packages/@winglang/sdk/src/core/lifting.ts b/packages/@winglang/sdk/src/core/lifting.ts index 41d2bb7fad0..544f79d2e1a 100644 --- a/packages/@winglang/sdk/src/core/lifting.ts +++ b/packages/@winglang/sdk/src/core/lifting.ts @@ -423,5 +423,9 @@ export class Lifting { // no lift-related methods to call - it's probably a primitive // so no capabilities need to be added to the inflight host } + + if (process.env.WING_TARGET) { + host.addEnvironment("WING_TARGET", process.env.WING_TARGET!); + } } } diff --git a/packages/@winglang/sdk/src/target-sim/resource.ts b/packages/@winglang/sdk/src/target-sim/resource.ts index 7b2fa17cb5a..75ff2f1ff83 100644 --- a/packages/@winglang/sdk/src/target-sim/resource.ts +++ b/packages/@winglang/sdk/src/target-sim/resource.ts @@ -120,10 +120,6 @@ export class Resource const entrypoint = join(workdir, `${assetName}.cjs`); this.entrypoint = entrypoint; - if (process.env.WING_TARGET) { - this.addEnvironment("WING_TARGET", process.env.WING_TARGET); - } - this.factory = factory; } diff --git a/packages/@winglang/wingc/src/ast.rs b/packages/@winglang/wingc/src/ast.rs index 9cd4395ee48..19f3c207547 100644 --- a/packages/@winglang/wingc/src/ast.rs +++ b/packages/@winglang/wingc/src/ast.rs @@ -597,6 +597,7 @@ pub enum IntrinsicKind { Dirname, Filename, App, + Target, } impl Display for IntrinsicKind { @@ -606,6 +607,7 @@ impl Display for IntrinsicKind { IntrinsicKind::Dirname => write!(f, "@dirname"), IntrinsicKind::Filename => write!(f, "@filename"), IntrinsicKind::App => write!(f, "@app"), + IntrinsicKind::Target => write!(f, "@target"), } } } @@ -616,6 +618,7 @@ impl IntrinsicKind { "@dirname" => IntrinsicKind::Dirname, "@filename" => IntrinsicKind::Filename, "@app" => IntrinsicKind::App, + "@target" => IntrinsicKind::Target, _ => IntrinsicKind::Unknown, } } @@ -635,6 +638,7 @@ impl IntrinsicKind { Phase::Preflight => true, _ => false, }, + IntrinsicKind::Target => true, } } } diff --git a/packages/@winglang/wingc/src/docs.rs b/packages/@winglang/wingc/src/docs.rs index 1900389cb25..960b0c34187 100644 --- a/packages/@winglang/wingc/src/docs.rs +++ b/packages/@winglang/wingc/src/docs.rs @@ -349,7 +349,7 @@ fn render_docs(markdown: &mut CodeMaker, docs: &Docs) { // Psuedo-abstract marker, mostly useful internally | "abstract" // Marker type use, not for users - | "skipDocs" | "wingType" + | "skipDocs" | "wingType" | "noinflight" ) { return; } diff --git a/packages/@winglang/wingc/src/jsify.rs b/packages/@winglang/wingc/src/jsify.rs index 7837a1d5d14..9b163f4d8b5 100644 --- a/packages/@winglang/wingc/src/jsify.rs +++ b/packages/@winglang/wingc/src/jsify.rs @@ -764,6 +764,9 @@ impl<'a> JSifier<'a> { IntrinsicKind::App => { new_code!(expr_span, HELPERS_VAR, ".nodeof(this).app") } + IntrinsicKind::Target => { + new_code!(expr_span, "process.env.WING_TARGET") + } }, ExprKind::TypeIntrinsic(TypeIntrinsic { type_ }) => self.jsify_reflection_udt(&type_, &expr_span, ctx), ExprKind::Call { callee, arg_list } => { diff --git a/packages/@winglang/wingc/src/lib.rs b/packages/@winglang/wingc/src/lib.rs index 7d6260a0d5d..79688ff374d 100644 --- a/packages/@winglang/wingc/src/lib.rs +++ b/packages/@winglang/wingc/src/lib.rs @@ -131,6 +131,11 @@ const WINGSDK_SIM_IRESOURCE_FQN: &'static str = formatcp!( assembly = WINGSDK_ASSEMBLY_NAME, iface = WINGSDK_SIM_IRESOURCE ); +const WINGSDK_RESOURCE_FQN: &'static str = formatcp!( + "{assembly}.{class}", + assembly = WINGSDK_ASSEMBLY_NAME, + class = WINGSDK_RESOURCE +); const CONSTRUCT_BASE_CLASS: &'static str = "constructs.Construct"; const CONSTRUCT_BASE_INTERFACE: &'static str = "constructs.IConstruct"; diff --git a/packages/@winglang/wingc/src/lsp/hover.rs b/packages/@winglang/wingc/src/lsp/hover.rs index dcb30179c7a..dedbcfa4a11 100644 --- a/packages/@winglang/wingc/src/lsp/hover.rs +++ b/packages/@winglang/wingc/src/lsp/hover.rs @@ -560,6 +560,97 @@ Json.stringify({}); "#, ); + test_hover_list!( + parent_class_docs_are_inherited_on_declaration, + r#" + /// Some parent docs +class Parent { + /// Some method docs + pub method() {} +} + +class Child extends Parent { + //^ + pub method() {} +} + +new Child().method(); + "#, + ); + + test_hover_list!( + parent_class_docs_are_inherited_on_method_declaration, + r#" + /// Some parent docs +class Parent { + /// Some method docs + pub method() {} +} + +class Child extends Parent { + pub method() {} + //^ +} + +new Child().method(); + "#, + ); + + test_hover_list!( + parent_class_docs_are_inherited_on_call, + r#" + /// Some parent docs +class Parent { + /// Some method docs + pub method() {} +} + +class Child extends Parent { + pub method() {} +} + +new Child().method(); + //^ + "#, + ); + + test_hover_list!( + parent_class_docs_are_inherited_on_method_call, + r#" + /// Some parent docs +class Parent { + /// Some method docs + pub method() {} +} + +class Child extends Parent { + pub method() {} + //^ +} + +new Child().method(); + //^ + "#, + ); + + test_hover_list!( + parent_class_docs_are_overridden, + r#" + /// Some parent docs +class Parent { + /// Some method docs + pub method() {} +} + + /// Some child docs +class Child extends Parent { +} + +new Child().method(); + //^ + "#, + ); + test_hover_list!( ignoe_empty_lines_in_doc, r#" diff --git a/packages/@winglang/wingc/src/lsp/snapshots/completions/hide_abstract_members.snap b/packages/@winglang/wingc/src/lsp/snapshots/completions/hide_abstract_members.snap index 811810d696f..bedb4208c6d 100644 --- a/packages/@winglang/wingc/src/lsp/snapshots/completions/hide_abstract_members.snap +++ b/packages/@winglang/wingc/src/lsp/snapshots/completions/hide_abstract_members.snap @@ -5,7 +5,7 @@ source: packages/@winglang/wingc/src/lsp/completions.rs kind: 7 documentation: kind: markdown - value: "```wing\nclass Button extends VisualComponent {\n static isVisualComponent(...): bool;\n}\n```\n---\nA button can be used to perform an action.\n\n*@noinflight*" + value: "```wing\nclass Button extends VisualComponent {\n static isVisualComponent(...): bool;\n}\n```\n---\nA button can be used to perform an action." sortText: gg|Button insertText: Button($1) insertTextFormat: 2 @@ -16,7 +16,7 @@ source: packages/@winglang/wingc/src/lsp/completions.rs kind: 7 documentation: kind: markdown - value: "```wing\nclass Field extends VisualComponent {\n static isVisualComponent(...): bool;\n}\n```\n---\nA field can be used to display a value.\n\n*@noinflight*" + value: "```wing\nclass Field extends VisualComponent {\n static isVisualComponent(...): bool;\n}\n```\n---\nA field can be used to display a value." sortText: gg|Field insertText: Field($1) insertTextFormat: 2 @@ -27,7 +27,7 @@ source: packages/@winglang/wingc/src/lsp/completions.rs kind: 7 documentation: kind: markdown - value: "```wing\nclass FileBrowser extends VisualComponent {\n static isVisualComponent(...): bool;\n}\n```\n---\nA file browser can be used to browse files.\n\n*@noinflight*" + value: "```wing\nclass FileBrowser extends VisualComponent {\n static isVisualComponent(...): bool;\n}\n```\n---\nA file browser can be used to browse files." sortText: gg|FileBrowser insertText: FileBrowser($1) insertTextFormat: 2 @@ -38,7 +38,7 @@ source: packages/@winglang/wingc/src/lsp/completions.rs kind: 7 documentation: kind: markdown - value: "```wing\nclass HttpClient extends VisualComponent {\n static isVisualComponent(...): bool;\n}\n```\n---\nAn HttpClient can be used to make HTTP requests.\n\n*@noinflight*" + value: "```wing\nclass HttpClient extends VisualComponent {\n static isVisualComponent(...): bool;\n}\n```\n---\nAn HttpClient can be used to make HTTP requests." sortText: gg|HttpClient insertText: HttpClient($1) insertTextFormat: 2 @@ -49,7 +49,7 @@ source: packages/@winglang/wingc/src/lsp/completions.rs kind: 7 documentation: kind: markdown - value: "```wing\nclass Section extends VisualComponent {\n add(...): void;\n addButton(...): void;\n addField(...): void;\n static isVisualComponent(...): bool;\n}\n```\n---\nA section can be used to group other visual components.\n\n*@noinflight*" + value: "```wing\nclass Section extends VisualComponent {\n add(...): void;\n addButton(...): void;\n addField(...): void;\n static isVisualComponent(...): bool;\n}\n```\n---\nA section can be used to group other visual components." sortText: gg|Section insertText: Section($1) insertTextFormat: 2 @@ -60,7 +60,7 @@ source: packages/@winglang/wingc/src/lsp/completions.rs kind: 7 documentation: kind: markdown - value: "```wing\nclass Table extends VisualComponent {\n static isVisualComponent(...): bool;\n}\n```\n---\nA table can be used to browse files.\n\n*@noinflight*" + value: "```wing\nclass Table extends VisualComponent {\n static isVisualComponent(...): bool;\n}\n```\n---\nA table can be used to browse files." sortText: gg|Table insertText: Table($1) insertTextFormat: 2 @@ -71,7 +71,7 @@ source: packages/@winglang/wingc/src/lsp/completions.rs kind: 7 documentation: kind: markdown - value: "```wing\nclass ValueField extends Field {\n static isVisualComponent(...): bool;\n}\n```\n---\nA value field can be used to display a string value.\n\n*@noinflight*" + value: "```wing\nclass ValueField extends Field {\n static isVisualComponent(...): bool;\n}\n```\n---\nA value field can be used to display a string value." sortText: gg|ValueField insertText: ValueField($1) insertTextFormat: 2 diff --git a/packages/@winglang/wingc/src/lsp/snapshots/completions/intrinsics.snap b/packages/@winglang/wingc/src/lsp/snapshots/completions/intrinsics.snap index df4afd74925..b79b34d2f83 100644 --- a/packages/@winglang/wingc/src/lsp/snapshots/completions/intrinsics.snap +++ b/packages/@winglang/wingc/src/lsp/snapshots/completions/intrinsics.snap @@ -22,4 +22,11 @@ source: packages/@winglang/wingc/src/lsp/completions.rs kind: markdown value: "Get the normalized absolute path of the current Wing source file.\n\nThe resolved path represents a path during preflight only and is not guaranteed to be valid while inflight." sortText: bb|@filename +- label: "@target" + kind: 6 + detail: str + documentation: + kind: markdown + value: "Returns a string identifying the current compilation platform.\n\nThis value is set by the CLI at compile time and can be used to conditionally compile code that is dependent on the target platform." + sortText: bb|@target diff --git a/packages/@winglang/wingc/src/lsp/snapshots/completions/intrinsics_partial.snap b/packages/@winglang/wingc/src/lsp/snapshots/completions/intrinsics_partial.snap index df4afd74925..b79b34d2f83 100644 --- a/packages/@winglang/wingc/src/lsp/snapshots/completions/intrinsics_partial.snap +++ b/packages/@winglang/wingc/src/lsp/snapshots/completions/intrinsics_partial.snap @@ -22,4 +22,11 @@ source: packages/@winglang/wingc/src/lsp/completions.rs kind: markdown value: "Get the normalized absolute path of the current Wing source file.\n\nThe resolved path represents a path during preflight only and is not guaranteed to be valid while inflight." sortText: bb|@filename +- label: "@target" + kind: 6 + detail: str + documentation: + kind: markdown + value: "Returns a string identifying the current compilation platform.\n\nThis value is set by the CLI at compile time and can be used to conditionally compile code that is dependent on the target platform." + sortText: bb|@target diff --git a/packages/@winglang/wingc/src/lsp/snapshots/hovers/parent_class_docs_are_inherited_on_call.snap b/packages/@winglang/wingc/src/lsp/snapshots/hovers/parent_class_docs_are_inherited_on_call.snap new file mode 100644 index 00000000000..d6a30791c62 --- /dev/null +++ b/packages/@winglang/wingc/src/lsp/snapshots/hovers/parent_class_docs_are_inherited_on_call.snap @@ -0,0 +1,14 @@ +--- +source: packages/@winglang/wingc/src/lsp/hover.rs +--- +contents: + kind: markdown + value: "```wing\nnew(): Child\n```\n---\nSome parent docs" +range: + start: + line: 11 + character: 4 + end: + line: 11 + character: 9 + diff --git a/packages/@winglang/wingc/src/lsp/snapshots/hovers/parent_class_docs_are_inherited_on_declaration.snap b/packages/@winglang/wingc/src/lsp/snapshots/hovers/parent_class_docs_are_inherited_on_declaration.snap new file mode 100644 index 00000000000..02ae5e13529 --- /dev/null +++ b/packages/@winglang/wingc/src/lsp/snapshots/hovers/parent_class_docs_are_inherited_on_declaration.snap @@ -0,0 +1,14 @@ +--- +source: packages/@winglang/wingc/src/lsp/hover.rs +--- +contents: + kind: markdown + value: "```wing\nclass Child extends Parent {\n method(): void;\n}\n```\n---\nSome parent docs" +range: + start: + line: 7 + character: 6 + end: + line: 7 + character: 11 + diff --git a/packages/@winglang/wingc/src/lsp/snapshots/hovers/parent_class_docs_are_inherited_on_method_call.snap b/packages/@winglang/wingc/src/lsp/snapshots/hovers/parent_class_docs_are_inherited_on_method_call.snap new file mode 100644 index 00000000000..4a54721be47 --- /dev/null +++ b/packages/@winglang/wingc/src/lsp/snapshots/hovers/parent_class_docs_are_inherited_on_method_call.snap @@ -0,0 +1,14 @@ +--- +source: packages/@winglang/wingc/src/lsp/hover.rs +--- +contents: + kind: markdown + value: "```wing\npreflight method(): void\n```\n---\nSome method docs" +range: + start: + line: 8 + character: 6 + end: + line: 8 + character: 12 + diff --git a/packages/@winglang/wingc/src/lsp/snapshots/hovers/parent_class_docs_are_inherited_on_method_declaration.snap b/packages/@winglang/wingc/src/lsp/snapshots/hovers/parent_class_docs_are_inherited_on_method_declaration.snap new file mode 100644 index 00000000000..4a54721be47 --- /dev/null +++ b/packages/@winglang/wingc/src/lsp/snapshots/hovers/parent_class_docs_are_inherited_on_method_declaration.snap @@ -0,0 +1,14 @@ +--- +source: packages/@winglang/wingc/src/lsp/hover.rs +--- +contents: + kind: markdown + value: "```wing\npreflight method(): void\n```\n---\nSome method docs" +range: + start: + line: 8 + character: 6 + end: + line: 8 + character: 12 + diff --git a/packages/@winglang/wingc/src/lsp/snapshots/hovers/parent_class_docs_are_overridden.snap b/packages/@winglang/wingc/src/lsp/snapshots/hovers/parent_class_docs_are_overridden.snap new file mode 100644 index 00000000000..e57ce9dca9a --- /dev/null +++ b/packages/@winglang/wingc/src/lsp/snapshots/hovers/parent_class_docs_are_overridden.snap @@ -0,0 +1,14 @@ +--- +source: packages/@winglang/wingc/src/lsp/hover.rs +--- +contents: + kind: markdown + value: "```wing\nnew(): Child\n```\n---\nSome child docs" +range: + start: + line: 11 + character: 4 + end: + line: 11 + character: 9 + diff --git a/packages/@winglang/wingc/src/lsp/snapshots/hovers/static_method.snap b/packages/@winglang/wingc/src/lsp/snapshots/hovers/static_method.snap index 9b2d87b76b2..d3c41fe20f2 100644 --- a/packages/@winglang/wingc/src/lsp/snapshots/hovers/static_method.snap +++ b/packages/@winglang/wingc/src/lsp/snapshots/hovers/static_method.snap @@ -1,5 +1,5 @@ --- -source: libs/wingc/src/lsp/hover.rs +source: packages/@winglang/wingc/src/lsp/hover.rs --- contents: kind: markdown diff --git a/packages/@winglang/wingc/src/lsp/snapshots/hovers/user_defined_type_annotation.snap b/packages/@winglang/wingc/src/lsp/snapshots/hovers/user_defined_type_annotation.snap index 6b13f2f31fc..0f7fec75880 100644 --- a/packages/@winglang/wingc/src/lsp/snapshots/hovers/user_defined_type_annotation.snap +++ b/packages/@winglang/wingc/src/lsp/snapshots/hovers/user_defined_type_annotation.snap @@ -1,5 +1,5 @@ --- -source: libs/wingc/src/lsp/hover.rs +source: packages/@winglang/wingc/src/lsp/hover.rs --- contents: kind: markdown diff --git a/packages/@winglang/wingc/src/lsp/snapshots/hovers/user_defined_type_reference_property.snap b/packages/@winglang/wingc/src/lsp/snapshots/hovers/user_defined_type_reference_property.snap index c27d7bf34b3..4db37987892 100644 --- a/packages/@winglang/wingc/src/lsp/snapshots/hovers/user_defined_type_reference_property.snap +++ b/packages/@winglang/wingc/src/lsp/snapshots/hovers/user_defined_type_reference_property.snap @@ -1,5 +1,5 @@ --- -source: libs/wingc/src/lsp/hover.rs +source: packages/@winglang/wingc/src/lsp/hover.rs --- contents: kind: markdown diff --git a/packages/@winglang/wingc/src/lsp/snapshots/hovers/user_defined_type_reference_type.snap b/packages/@winglang/wingc/src/lsp/snapshots/hovers/user_defined_type_reference_type.snap index 12427da76ad..6b8331e43b4 100644 --- a/packages/@winglang/wingc/src/lsp/snapshots/hovers/user_defined_type_reference_type.snap +++ b/packages/@winglang/wingc/src/lsp/snapshots/hovers/user_defined_type_reference_type.snap @@ -1,5 +1,5 @@ --- -source: libs/wingc/src/lsp/hover.rs +source: packages/@winglang/wingc/src/lsp/hover.rs --- contents: kind: markdown diff --git a/packages/@winglang/wingc/src/lsp/snapshots/hovers/user_defined_types.snap b/packages/@winglang/wingc/src/lsp/snapshots/hovers/user_defined_types.snap index dcdd73534f3..a0b6e6a9d20 100644 --- a/packages/@winglang/wingc/src/lsp/snapshots/hovers/user_defined_types.snap +++ b/packages/@winglang/wingc/src/lsp/snapshots/hovers/user_defined_types.snap @@ -1,5 +1,5 @@ --- -source: libs/wingc/src/lsp/hover.rs +source: packages/@winglang/wingc/src/lsp/hover.rs --- contents: kind: markdown diff --git a/packages/@winglang/wingc/src/lsp/snapshots/hovers/variadic_args.snap b/packages/@winglang/wingc/src/lsp/snapshots/hovers/variadic_args.snap index b5b91c403d4..d3c17ce441b 100644 --- a/packages/@winglang/wingc/src/lsp/snapshots/hovers/variadic_args.snap +++ b/packages/@winglang/wingc/src/lsp/snapshots/hovers/variadic_args.snap @@ -1,5 +1,5 @@ --- -source: libs/wingc/src/lsp/hover.rs +source: packages/@winglang/wingc/src/lsp/hover.rs --- contents: kind: markdown diff --git a/packages/@winglang/wingc/src/parser.rs b/packages/@winglang/wingc/src/parser.rs index f24c3e3ce2e..9550d4cf5c8 100644 --- a/packages/@winglang/wingc/src/parser.rs +++ b/packages/@winglang/wingc/src/parser.rs @@ -2528,7 +2528,7 @@ impl<'s> Parser<'s> { }; if matches!(kind, IntrinsicKind::Unknown) { - self.add_error("Invalid intrinsic", &expression_node); + self.add_error(format!("Unknown intrinsic: @{}", name), &expression_node); } Ok(Expr::new( diff --git a/packages/@winglang/wingc/src/type_check.rs b/packages/@winglang/wingc/src/type_check.rs index 6c9f66f76d7..5de84b0b5d8 100644 --- a/packages/@winglang/wingc/src/type_check.rs +++ b/packages/@winglang/wingc/src/type_check.rs @@ -18,7 +18,7 @@ use crate::ast::{ }; use crate::comp_ctx::{CompilationContext, CompilationPhase}; use crate::diagnostic::{report_diagnostic, Diagnostic, DiagnosticAnnotation, DiagnosticSeverity, TypeError, WingSpan}; -use crate::docs::Docs; +use crate::docs::{Docs, Documented}; use crate::file_graph::{File, FileGraph}; use crate::parser::normalize_path; use crate::type_check::has_type_stmt::HasStatementVisitor; @@ -32,7 +32,8 @@ use crate::{ UTIL_CLASS_NAME, WINGSDK_APP, WINGSDK_ARRAY, WINGSDK_ASSEMBLY_NAME, WINGSDK_BRINGABLE_MODULES, WINGSDK_BYTES, WINGSDK_DATETIME, WINGSDK_DURATION, WINGSDK_GENERIC, WINGSDK_IRESOURCE, WINGSDK_JSON, WINGSDK_MAP, WINGSDK_MUT_ARRAY, WINGSDK_MUT_JSON, WINGSDK_MUT_MAP, WINGSDK_MUT_SET, WINGSDK_NODE, WINGSDK_REFLECT_TYPE, WINGSDK_REGEX, - WINGSDK_RESOURCE, WINGSDK_SET, WINGSDK_SIM_IRESOURCE_FQN, WINGSDK_STD_MODULE, WINGSDK_STRING, WINGSDK_STRUCT, + WINGSDK_RESOURCE, WINGSDK_RESOURCE_FQN, WINGSDK_SET, WINGSDK_SIM_IRESOURCE_FQN, WINGSDK_STD_MODULE, WINGSDK_STRING, + WINGSDK_STRUCT, }; use camino::{Utf8Path, Utf8PathBuf}; use derivative::Derivative; @@ -935,18 +936,6 @@ impl FunctionSignature { } } -impl PartialEq for FunctionSignature { - fn eq(&self, other: &Self) -> bool { - self - .parameters - .iter() - .zip(other.parameters.iter()) - .all(|(x, y)| x.typeref.is_same_type_as(&y.typeref)) - && self.return_type.is_same_type_as(&other.return_type) - && self.phase == other.phase - } -} - impl Display for SymbolKind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -2397,6 +2386,28 @@ See https://www.winglang.io/docs/concepts/application-tree for more information. AccessModifier::Public, StatementIdx::Top, ); + + // @target + let _ = self.types + .intrinsics + .define( + &Symbol::global(IntrinsicKind::Target.to_string()), + SymbolKind::Variable(VariableInfo { + access: AccessModifier::Public, + name: Symbol::global(IntrinsicKind::Target.to_string()), + docs: Some(Docs::with_summary( + r#"Returns a string identifying the current compilation platform. + +This value is set by the CLI at compile time and can be used to conditionally compile code that is dependent on the target platform."#, + )), + kind: VariableKind::StaticMember, + phase: Phase::Independent, + type_: self.types.string(), + reassignable: false, + }), + AccessModifier::Public, + StatementIdx::Top, + ); } fn add_builtin(&mut self, name: &str, typ: Type, scope: &mut Scope) { @@ -3046,7 +3057,11 @@ See https://www.winglang.io/docs/concepts/application-tree for more information. } match intrinsic.kind { - IntrinsicKind::Dirname | IntrinsicKind::Filename | IntrinsicKind::App | IntrinsicKind::Unknown => { + IntrinsicKind::Dirname + | IntrinsicKind::Filename + | IntrinsicKind::App + | IntrinsicKind::Target + | IntrinsicKind::Unknown => { return (sig.return_type, sig.phase); } } @@ -4213,7 +4228,7 @@ See https://www.winglang.io/docs/concepts/application-tree for more information. let interface_spec = Interface { name: iface.name.clone(), fqn: format!("{}.{}", self.base_fqn_for_current_file(), iface.name), - docs: doc.as_ref().map_or(Docs::default(), |s| Docs::with_summary(s)), + docs: doc.as_ref().map_or(Docs::default(), |s: &String| Docs::with_summary(s)), env: dummy_env, extends: extend_interfaces.clone(), phase: iface.phase, @@ -4804,6 +4819,21 @@ See https://www.winglang.io/docs/concepts/application-tree for more information. } } + let mut default_docs = Docs::default(); + // if parent docs exist we use them as the defualt + if let Some(parent_class) = parent_class { + // New classes defined in Wing shouldn't inherit docs from std.Resource + let is_parent_resource = parent_class + .as_class() + .map(|c| c.fqn.as_deref() == Some(WINGSDK_RESOURCE_FQN)) + .unwrap_or(false); + if !is_parent_resource { + if let Some(parent_docs) = parent_class.docs() { + default_docs = parent_docs.clone(); + } + } + } + // Create the resource/class type and add it to the current environment (so class implementation can reference itself) let class_spec = Class { name: ast_class.name.clone(), @@ -4814,7 +4844,7 @@ See https://www.winglang.io/docs/concepts/application-tree for more information. is_abstract: false, phase: ast_class.phase, defined_in_phase: env.phase, - docs: stmt.doc.as_ref().map_or(Docs::default(), |s| Docs::with_summary(s)), + docs: stmt.doc.as_ref().map_or(default_docs, |s| Docs::with_summary(s)), std_construct_args: ast_class.phase == Phase::Preflight, lifts: None, uid: self.types.class_counter, @@ -4877,6 +4907,7 @@ See https://www.winglang.io/docs/concepts/application-tree for more information. method_def.access, &mut class_env, method_name, + parent_class, ); method_types.insert(&method_name, method_type); } @@ -4895,6 +4926,7 @@ See https://www.winglang.io/docs/concepts/application-tree for more information. ast_class.initializer.access, &mut class_env, &init_symb, + parent_class, ); method_types.insert(&init_symb, init_func_type); @@ -4913,6 +4945,7 @@ See https://www.winglang.io/docs/concepts/application-tree for more information. ast_class.inflight_initializer.access, &mut class_env, &inflight_init_symb, + parent_class, ); method_types.insert(&inflight_init_symb, inflight_init_func_type); @@ -5815,6 +5848,7 @@ See https://www.winglang.io/docs/concepts/application-tree for more information. access: AccessModifier, class_env: &mut SymbolEnv, method_name: &Symbol, + parent_class: Option>, ) { // Modify the method's type based on the fact we know it's a method and not just a function let method_sig = method_type @@ -5885,6 +5919,16 @@ See https://www.winglang.io/docs/concepts/application-tree for more information. let method_phase = method_type.as_function_sig().unwrap().phase; + // use the parent's method docs as default, if exist. + let mut default_method_docs = None; + if let Some(parent_class) = parent_class { + if let Some(c) = parent_class.as_class() { + if let Some(parent_method) = c.methods(true).find(|m| m.1.name.eq(&method_name)) { + default_method_docs = parent_method.1.docs; + } + } + }; + match class_env.define( method_name, SymbolKind::make_member_variable( @@ -5894,7 +5938,11 @@ See https://www.winglang.io/docs/concepts/application-tree for more information. instance_type.is_none(), method_phase, access, - method_def.doc.as_ref().map(|s| Docs::with_summary(s)), + method_def + .doc + .as_ref() + .map(|s| Docs::with_summary(s)) + .or(default_method_docs), ), access, StatementIdx::Top, diff --git a/packages/winglang/project-templates/wing/private-api/main.w b/packages/winglang/project-templates/wing/private-api/main.w index 15a34c521a5..495be7679cc 100644 --- a/packages/winglang/project-templates/wing/private-api/main.w +++ b/packages/winglang/project-templates/wing/private-api/main.w @@ -1,6 +1,5 @@ bring cloud; bring http; -bring util; /** * The example below is a simple note-taking app. @@ -96,7 +95,7 @@ bring util; let noteService = new NoteService(); // Consumer functions (not required for the app to work, but useful for testing) -if util.env("WING_TARGET") == "tf-aws" { +if @target == "tf-aws" { new cloud.Function(inflight (event) => { if let event = event?.tryAsStr() { let parts = event.split(":"); @@ -128,4 +127,4 @@ if util.env("WING_TARGET") == "tf-aws" { return "event is required `NAME`"; }) as "Consumer-GET"; -} \ No newline at end of file +} diff --git a/tests/doc_examples/valid/01-understanding-platforms.md_example_1/main.w b/tests/doc_examples/valid/01-understanding-platforms.md_example_1/main.w index 3f8f521da20..0adc4312683 100644 --- a/tests/doc_examples/valid/01-understanding-platforms.md_example_1/main.w +++ b/tests/doc_examples/valid/01-understanding-platforms.md_example_1/main.w @@ -14,7 +14,7 @@ new cloud.Function(inflight ()=> { // push a message to queue queue.push("m"); // sleep according to target - if util.env("WING_TARGET") == "sim" { + if @target == "sim" { log("Running on Simulator, sleeping for 1s"); util.sleep(1s); } else { diff --git a/tests/error/invalid-token.test.w b/tests/error/invalid-token.test.w index 37dcb73a218..5da625c9941 100644 --- a/tests/error/invalid-token.test.w +++ b/tests/error/invalid-token.test.w @@ -1,5 +1,4 @@ bring sim; -bring util; inflight class MyResourceBackend impl sim.IResource { ctx: sim.IResourceContext; @@ -22,7 +21,7 @@ class MyResource { } // Only run these tests in the simulator -if util.env("WING_TARGET") == "sim" { +if @target == "sim" { let r = new MyResource(); let fakeAttr = r.fakeAttr(); diff --git a/tests/sdk_tests/api/aws-api.test.w b/tests/sdk_tests/api/aws-api.test.w index 9edfcc1c1de..b1cb9c74089 100644 --- a/tests/sdk_tests/api/aws-api.test.w +++ b/tests/sdk_tests/api/aws-api.test.w @@ -1,8 +1,5 @@ bring cloud; bring aws; -bring util; - -let target = util.env("WING_TARGET"); let api = new cloud.Api() as "api"; api.get("/api", inflight (req: cloud.ApiRequest): cloud.ApiResponse => { @@ -39,4 +36,4 @@ test "validates the AWS Api" { // If the test is not on AWS, it should not fail, so I am returning true. assert(true); } -} \ No newline at end of file +} diff --git a/tests/sdk_tests/api/cycle.test.w b/tests/sdk_tests/api/cycle.test.w index 8e87d265631..2bf274a7e4e 100644 --- a/tests/sdk_tests/api/cycle.test.w +++ b/tests/sdk_tests/api/cycle.test.w @@ -5,7 +5,7 @@ bring util; // This test checks that an API can have a route whose handler // references the API's URL. -if ["sim", "tf-aws", "awscdk"].contains(util.env("WING_TARGET")) { +if ["sim", "tf-aws", "awscdk"].contains(@target) { let api = new cloud.Api(); api.get("/my_url", inflight () => { diff --git a/tests/sdk_tests/bucket/aws-bucket.test.w b/tests/sdk_tests/bucket/aws-bucket.test.w index f9385552455..d9e6078e232 100644 --- a/tests/sdk_tests/bucket/aws-bucket.test.w +++ b/tests/sdk_tests/bucket/aws-bucket.test.w @@ -1,8 +1,5 @@ bring cloud; bring aws; -bring util; - -let target = util.env("WING_TARGET"); let bucket = new cloud.Bucket() as "aws-wing-bucket"; @@ -20,7 +17,7 @@ let bucketInfo = getBucketInfo(bucket); test "validates the AWS Bucket" { if let bucket = bucketInfo { - if target == "tf-aws" { + if @target == "tf-aws" { assert(bucket.get("bucketArn").contains("arn:aws:s3:::aws-wing-bucket")); assert(bucket.get("bucketName").contains("aws-wing-bucket")); } else { // If it's not a 'tf-aws' target, it's an 'awscdk' @@ -32,4 +29,4 @@ test "validates the AWS Bucket" { // If the test is not on AWS, it should not fail, so I am returning true. assert(true); } -} \ No newline at end of file +} diff --git a/tests/sdk_tests/bucket/bucket-ref.test.w b/tests/sdk_tests/bucket/bucket-ref.test.w index 7a4537a0c83..e7b6c6abcd7 100644 --- a/tests/sdk_tests/bucket/bucket-ref.test.w +++ b/tests/sdk_tests/bucket/bucket-ref.test.w @@ -1,7 +1,7 @@ bring cloud; bring aws; -bring util; bring expect; + let b = new cloud.Bucket(); // this will only work if we are testing on tf-aws @@ -14,7 +14,7 @@ if let name = aws.Bucket.from(b)?.bucketName { } } -if util.env("WING_TARGET") == "sim" { +if @target == "sim" { let dummyName = "wing-dummy-bucket"; let dummyArn = "arn:aws:s3:::{dummyName}"; let br = new aws.BucketRef(dummyName); diff --git a/tests/sdk_tests/bucket/events.test.w b/tests/sdk_tests/bucket/events.test.w index 13a1dd176b7..79ff51b9f15 100644 --- a/tests/sdk_tests/bucket/events.test.w +++ b/tests/sdk_tests/bucket/events.test.w @@ -62,7 +62,7 @@ new std.Test(inflight () => { b.delete("c"); // https://github.com/winglang/wing/issues/2724 - if (util.env("WING_TARGET") != "tf-aws") { + if @target != "tf-aws" { // assert that onCreate events about the "a", "b", and "c" objects were each produced exactly 1 time checkHitCount(key: "a", type: "OnCreate()", source: Source.anyEvent, count: 1); checkHitCount(key: "b", type: "OnCreate()", source: Source.anyEvent, count: 1); diff --git a/tests/sdk_tests/bucket/signed_url.test.w b/tests/sdk_tests/bucket/signed_url.test.w index 8c31d91acfa..94ff2dd8bae 100644 --- a/tests/sdk_tests/bucket/signed_url.test.w +++ b/tests/sdk_tests/bucket/signed_url.test.w @@ -51,14 +51,13 @@ test "signedUrl PUT" { test "signedUrl duration option is respected" { let isExpiredTokenError = (output: str) => { - let target = util.env("WING_TARGET"); let var result = false; - if target == "tf-aws" { + if @target == "tf-aws" { result = output.contains("AccessDeniedRequest has expired"); - } else if target == "tf-gcp" { + } else if @target == "tf-gcp" { result = output.contains("ExpiredTokenInvalid argument."); - } else if target == "sim" { + } else if @target == "sim" { result = output.contains("Signed URL has expired"); } diff --git a/tests/sdk_tests/container/container.test.w b/tests/sdk_tests/container/container.test.w index c21f2562537..9a89acad4f2 100644 --- a/tests/sdk_tests/container/container.test.w +++ b/tests/sdk_tests/container/container.test.w @@ -6,12 +6,10 @@ skipPlatforms: bring sim; bring http; -bring util; bring expect; // only relevant in simulator -if util.env("WING_TARGET") == "sim" { - +if @target == "sim" { let echo = new sim.Container( name: "http-echo", image: "hashicorp/http-echo", diff --git a/tests/sdk_tests/container/entrypoint.test.w b/tests/sdk_tests/container/entrypoint.test.w index c2799745c82..0dff2145ef3 100644 --- a/tests/sdk_tests/container/entrypoint.test.w +++ b/tests/sdk_tests/container/entrypoint.test.w @@ -6,11 +6,10 @@ skipPlatforms: bring sim; bring http; -bring util; bring expect; // only relevant in simulator -if util.env("WING_TARGET") == "sim" { +if @target == "sim" { let entrypoint = new sim.Container( name: "my-entrypoint-app", image: "./my-docker-image", diff --git a/tests/sdk_tests/container/mount.test.w b/tests/sdk_tests/container/mount.test.w index ab2588ff53e..7ea694c69f1 100644 --- a/tests/sdk_tests/container/mount.test.w +++ b/tests/sdk_tests/container/mount.test.w @@ -4,10 +4,9 @@ skipPlatforms: - darwin \*/ bring sim; -bring util; // only relevant in simulator -if util.env("WING_TARGET") == "sim" { +if @target == "sim" { let container = new sim.Container( name: "postgres", image: "postgres:15", diff --git a/tests/sdk_tests/container/network.test.w b/tests/sdk_tests/container/network.test.w index 41c43afd399..4ff3eafecae 100644 --- a/tests/sdk_tests/container/network.test.w +++ b/tests/sdk_tests/container/network.test.w @@ -6,11 +6,10 @@ skipPlatforms: bring sim; bring http; -bring util; bring expect; // only relevant in simulator -if util.env("WING_TARGET") == "sim" { +if @target == "sim" { let networkHost = new sim.Container( name: "http-echo", image: "hashicorp/http-echo", diff --git a/tests/sdk_tests/counter/aws-counter.test.w b/tests/sdk_tests/counter/aws-counter.test.w index 7dd1d5d2f25..acb5d2a53e7 100644 --- a/tests/sdk_tests/counter/aws-counter.test.w +++ b/tests/sdk_tests/counter/aws-counter.test.w @@ -1,8 +1,5 @@ bring cloud; bring aws; -bring util; - -let target = util.env("WING_TARGET"); let counter = new cloud.Counter(initial: 1) as "aws-wing-counter"; @@ -20,7 +17,7 @@ let counterInfo = getCounterInfo(counter); test "validates the AWS counter name" { if let counter = counterInfo { - if target == "tf-aws" { + if @target == "tf-aws" { assert(counter.get("dynamoTableArn").contains("arn:aws:dynamodb:")); assert(counter.get("dynamoTableArn").contains("aws-wing-counter")); assert(counter.get("dynamoTableName").contains("aws-wing-counter")); @@ -33,4 +30,4 @@ test "validates the AWS counter name" { // If the test is not on AWS, it should not fail, so I am returning true. assert(true); } -} \ No newline at end of file +} diff --git a/tests/sdk_tests/function/aws-function.test.w b/tests/sdk_tests/function/aws-function.test.w index 0164c3455ed..10c26c65629 100644 --- a/tests/sdk_tests/function/aws-function.test.w +++ b/tests/sdk_tests/function/aws-function.test.w @@ -1,9 +1,6 @@ bring aws; bring cloud; bring expect; -bring util; - -let target = util.env("WING_TARGET"); let getFunctionInfo = (f: cloud.Function): Map? => { if let lambda = aws.Function.from(f) { @@ -27,7 +24,7 @@ let fn = new cloud.Function(inflight (msg: Json?) => { let remainingTime = ctx.remainingTimeInMillis(); assert(remainingTime > 0); } else { - if target == "tf-aws" || target == "awscdk" { + if @target == "tf-aws" || @target == "awscdk" { expect.fail("Expected to have a context object"); } } @@ -39,18 +36,18 @@ let fnInfo = getFunctionInfo(fn); new std.Test(inflight () => { if let info = fnInfo { - if target == "tf-aws" { + if @target == "tf-aws" { assert(info.get("functionArn").contains("arn:aws:lambda:")); assert(info.get("functionArn").contains(":function:")); assert(info.get("functionArn").contains("aws-wing-function")); assert(info.get("functionName").contains("aws-wing-function")); - } else if target == "awscdk" { + } else if @target == "awscdk" { assert(info.get("functionArn").contains("arn:aws:lambda:")); assert(info.get("functionArn").contains(":function:")); assert(info.get("functionArn").contains("awswingfunction")); assert(info.get("functionName").contains("awswingfunction")); } else { - expect.fail("Unexpected target " + target); + expect.fail("Unexpected target " + @target); } } else { // If the test is not on AWS, it should not fail, so I am returning true. diff --git a/tests/sdk_tests/function/aws-layer.test.w b/tests/sdk_tests/function/aws-layer.test.w index 06124776aa5..26e640c8506 100644 --- a/tests/sdk_tests/function/aws-layer.test.w +++ b/tests/sdk_tests/function/aws-layer.test.w @@ -1,9 +1,8 @@ bring aws; bring cloud; bring expect; -bring util; -if util.env("WING_TARGET") == "tf-aws" { +if @target == "tf-aws" { let fn = new cloud.Function(inflight () => { return "Hello world!"; }); diff --git a/tests/sdk_tests/function/concurrency.test.w b/tests/sdk_tests/function/concurrency.test.w index 699c22e028c..f204c91cb05 100644 --- a/tests/sdk_tests/function/concurrency.test.w +++ b/tests/sdk_tests/function/concurrency.test.w @@ -3,7 +3,7 @@ bring util; // TODO: support concurrency on AWS -if util.env("WING_TARGET") == "sim" { +if @target == "sim" { let c = new cloud.Counter(); let f1 = new cloud.Function(inflight () => { diff --git a/tests/sdk_tests/function/function-ref.test.w b/tests/sdk_tests/function/function-ref.test.w index 0c2c29a0b7b..479f1b69792 100644 --- a/tests/sdk_tests/function/function-ref.test.w +++ b/tests/sdk_tests/function/function-ref.test.w @@ -22,7 +22,7 @@ if let arn = aws.Function.from(f)?.functionArn { } } -if util.env("WING_TARGET") == "sim" { +if @target == "sim" { bring expect; let dummyArn = "arn:aws:lambda:us-east-1:111111111111:function:Function-11111111"; diff --git a/tests/sdk_tests/function/timeout.test.w b/tests/sdk_tests/function/timeout.test.w index cc1da9c7c3b..e70618079b9 100644 --- a/tests/sdk_tests/function/timeout.test.w +++ b/tests/sdk_tests/function/timeout.test.w @@ -5,9 +5,9 @@ bring expect; let c = new cloud.Counter(); let ERROR_MSG_BY_TARGET: Map = {"tf-gcp": "upstream request timeout"}; -let timeoutError = ERROR_MSG_BY_TARGET.tryGet(util.env("WING_TARGET")) ?? "Function timed out"; +let timeoutError = ERROR_MSG_BY_TARGET.tryGet(@target) ?? "Function timed out"; let TIMEOUT_BY_TARGET: Map = {"tf-gcp": 120}; -let timeoutValue = TIMEOUT_BY_TARGET.tryGet(util.env("WING_TARGET")) ?? 60; +let timeoutValue = TIMEOUT_BY_TARGET.tryGet(@target) ?? 60; let f1 = new cloud.Function(inflight () => { util.sleep(1.5s); diff --git a/tests/sdk_tests/queue/aws-queue.test.w b/tests/sdk_tests/queue/aws-queue.test.w index c42fd4d69cc..bc99e349fe6 100644 --- a/tests/sdk_tests/queue/aws-queue.test.w +++ b/tests/sdk_tests/queue/aws-queue.test.w @@ -2,8 +2,6 @@ bring cloud; bring aws; bring util; -let target = util.env("WING_TARGET"); - let queue = new cloud.Queue() as "aws-wing-queue"; let getQueueInfo = (q: cloud.Queue): Map? => { @@ -21,7 +19,7 @@ let queueInfo = getQueueInfo(queue); test "validates the AWS queue name" { if let queue = queueInfo { - if target == "tf-aws" { + if @target == "tf-aws" { assert(queue.get("queueArn").contains("arn:aws:sqs:")); assert(queue.get("queueArn").contains("aws-wing-queue")); assert(queue.get("queueName").contains("aws-wing-queue")); @@ -34,4 +32,4 @@ test "validates the AWS queue name" { // If the test is not on AWS, it should not fail, so I am returning true. assert(true); } -} \ No newline at end of file +} diff --git a/tests/sdk_tests/queue/push.test.w b/tests/sdk_tests/queue/push.test.w index 817a7fd99dd..1afa08ac39d 100644 --- a/tests/sdk_tests/queue/push.test.w +++ b/tests/sdk_tests/queue/push.test.w @@ -41,7 +41,7 @@ new std.Test(inflight () => { }); q.purge(); - if util.env("WING_TARGET") != "sim" { + if @target != "sim" { // In a real cloud, purging is expensive so we should wait a minute regardless of .approxSize() // e.g. See AWS docs for queue purging (https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-sqs/classes/purgequeuecommand.html) util.sleep(1m); diff --git a/tests/sdk_tests/queue/queue-ref.test.w b/tests/sdk_tests/queue/queue-ref.test.w index fff25baefa4..39c0a16bdaf 100644 --- a/tests/sdk_tests/queue/queue-ref.test.w +++ b/tests/sdk_tests/queue/queue-ref.test.w @@ -31,7 +31,7 @@ if let arn = aws.Queue.from(q)?.queueArn { } } -if util.env("WING_TARGET") == "sim" { +if @target == "sim" { bring expect; let dummyArn = "arn:aws:sqs:us-east-1:111111111111:Queue-11111111"; @@ -51,4 +51,4 @@ if util.env("WING_TARGET") == "sim" { assert(err); } -} \ No newline at end of file +} diff --git a/tests/sdk_tests/queue/retention_period.main.w b/tests/sdk_tests/queue/retention_period.main.w index 9f664f2c9e9..41ab3f4052a 100644 --- a/tests/sdk_tests/queue/retention_period.main.w +++ b/tests/sdk_tests/queue/retention_period.main.w @@ -2,7 +2,7 @@ bring cloud; bring util; // TODO: timeout is not supported in sim - https://github.com/winglang/wing/issues/2401 -if util.env("WING_TARGET") != "sim" { +if @target != "sim" { let var timeout = 30s; let var retentionPeriod = 60s; diff --git a/tests/sdk_tests/queue/timeout.test.w b/tests/sdk_tests/queue/timeout.test.w index 604315a96b9..5ff40483ea9 100644 --- a/tests/sdk_tests/queue/timeout.test.w +++ b/tests/sdk_tests/queue/timeout.test.w @@ -7,7 +7,7 @@ bring util; let var timeout: duration = 30s; let var sleep: duration = 31s; -if (util.env("WING_TARGET") == "sim") { +if @target == "sim" { timeout = 1s; sleep = 2s; } @@ -29,7 +29,7 @@ new std.Test(inflight () => { util.sleep(duration.fromSeconds(timeout.seconds + 1)); // The queue should have 2 messages still due to timeout - doesn't work on aws or sim unfortunately // for aws- https://github.com/winglang/wing/issues/3354 - if (util.env("WING_TARGET") != "tf-aws") { + if @target != "tf-aws" { assert(q.approxSize() == 2); } }, timeout: 2m) as "timeout"; diff --git a/tests/sdk_tests/resource/call.test.w b/tests/sdk_tests/resource/call.test.w index 9ea58686123..bdb25e1f3ae 100644 --- a/tests/sdk_tests/resource/call.test.w +++ b/tests/sdk_tests/resource/call.test.w @@ -154,7 +154,7 @@ class MyResource { } // Only run these tests in the simulator -if util.env("WING_TARGET") == "sim" { +if @target == "sim" { let r1 = new MyResource(); test "resource.call with a field name returns the field value" { diff --git a/tests/sdk_tests/resource/no-stop.test.w b/tests/sdk_tests/resource/no-stop.test.w index cbd1d4b985d..77b7f37aa44 100644 --- a/tests/sdk_tests/resource/no-stop.test.w +++ b/tests/sdk_tests/resource/no-stop.test.w @@ -1,6 +1,5 @@ bring sim; bring expect; -bring util; class Simple { pub foo: str; @@ -14,7 +13,7 @@ class Simple { } // Only run these tests in the simulator -if util.env("WING_TARGET") == "sim" { +if @target == "sim" { let s = new Simple(); test "token is resolved" { diff --git a/tests/sdk_tests/resource/on-start.test.w b/tests/sdk_tests/resource/on-start.test.w index a1426e06092..a1505d91f18 100644 --- a/tests/sdk_tests/resource/on-start.test.w +++ b/tests/sdk_tests/resource/on-start.test.w @@ -1,5 +1,4 @@ bring sim; -bring util; inflight class OnStartThrowerBackend impl sim.IResource { new() { @@ -24,7 +23,7 @@ class OnStartThrower { } // Only run these tests in the simulator -if util.env("WING_TARGET") == "sim" { +if @target == "sim" { let r = new OnStartThrower(); test "method calls fail if the resource fails to start" { diff --git a/tests/sdk_tests/resource/on-stop.test.w b/tests/sdk_tests/resource/on-stop.test.w index ac4739d32f8..31f939ac967 100644 --- a/tests/sdk_tests/resource/on-stop.test.w +++ b/tests/sdk_tests/resource/on-stop.test.w @@ -1,5 +1,4 @@ bring sim; -bring util; inflight class OnStopThrowerBackend impl sim.IResource { pub onStop() { @@ -23,7 +22,7 @@ class OnStopThrower { } // Only run these tests in the simulator -if util.env("WING_TARGET") == "sim" { +if @target == "sim" { let r = new OnStopThrower(); test "if a resource throws an error on stopping, it doesn't crash the simulation" { diff --git a/tests/sdk_tests/resource/resource.test.w b/tests/sdk_tests/resource/resource.test.w index f3e7d320073..23a006ea2ef 100644 --- a/tests/sdk_tests/resource/resource.test.w +++ b/tests/sdk_tests/resource/resource.test.w @@ -1,6 +1,5 @@ bring cloud; bring sim; -bring util; inflight class CounterBackend impl sim.IResource { var counter: num; @@ -59,7 +58,7 @@ class Counter { let c = new Counter(); // Only run these tests in the simulator -if util.env("WING_TARGET") == "sim" { +if @target == "sim" { test "Counter" { assert(c.inc() == 0); assert(c.inc() == 1); @@ -80,7 +79,7 @@ class DoubleCounter extends Counter { let dc = new DoubleCounter(); -if util.env("WING_TARGET") == "sim" { +if @target == "sim" { test "DoubleCounter" { assert(dc.inc() == 0); assert(dc.inc() == 2); diff --git a/tests/sdk_tests/resource/state.test.w b/tests/sdk_tests/resource/state.test.w index a04ba5fac61..4606d3ae9ee 100644 --- a/tests/sdk_tests/resource/state.test.w +++ b/tests/sdk_tests/resource/state.test.w @@ -1,6 +1,5 @@ bring fs; bring sim; -bring util; inflight class ResourceWithStateBackend impl sim.IResource { ctx: sim.IResourceContext; @@ -37,7 +36,7 @@ class ResourceWithState { } // Only run these tests in the simulator -if util.env("WING_TARGET") == "sim" { +if @target == "sim" { let r = new ResourceWithState(); test "sim.Resource can read and write state" { diff --git a/tests/sdk_tests/resource/tokens.test.w b/tests/sdk_tests/resource/tokens.test.w index 1d80c62dbe2..ee4b9c9d738 100644 --- a/tests/sdk_tests/resource/tokens.test.w +++ b/tests/sdk_tests/resource/tokens.test.w @@ -1,5 +1,4 @@ bring sim; -bring util; inflight class BadTokenResolverBackend impl sim.IResource { ctx: sim.IResourceContext; @@ -26,7 +25,7 @@ class BadTokenResolver { } // Only run these tests in the simulator -if util.env("WING_TARGET") == "sim" { +if @target == "sim" { let r = new BadTokenResolver(); test "calling resolveToken during a method call emits an error" { diff --git a/tests/sdk_tests/schedule/init.test.w b/tests/sdk_tests/schedule/init.test.w index ee6cdcbda87..c60ce7afb3b 100644 --- a/tests/sdk_tests/schedule/init.test.w +++ b/tests/sdk_tests/schedule/init.test.w @@ -1,50 +1,42 @@ -/*\ -skip: true -\*/ - bring cloud; -bring util; bring expect; new cloud.Schedule( rate: 5m ) as "s0"; -// doesn't work on sim: https://github.com/winglang/wing/issues/2732 -if (util.env("WING_TARGET") != "sim") { - // Those are testing the many errors in initialization of a cloud.Schedule - let var error = ""; - try { - new cloud.Schedule( rate: nil, cron: nil ) as "s1"; - } catch e { - error = e; - } - expect.equal(error, "rate or cron need to be filled."); - - try { - new cloud.Schedule( rate: 2m, cron: "* * * * *" ) as "s2"; - } catch e { - error = e; - } - expect.equal(error, "rate and cron cannot be configured simultaneously."); - - - try { - new cloud.Schedule( rate: 1s ) as "s3"; - } catch e { - error = e; - } - expect.equal(error, "rate can not be set to less than 1 minute."); - - try { - new cloud.Schedule( cron: "* * * * * *" ) as "s4"; - } catch e { - error = e; - } - expect.equal(error, "cron string must be in UNIX cron format"); - - try { - new cloud.Schedule( cron: "* * * * ?" ) as "s5"; - } catch e { - error = e; - } - expect.equal(error, "cron string must be in UNIX cron format"); -} \ No newline at end of file +// Those are testing the many errors in initialization of a cloud.Schedule +let var error = ""; +try { + new cloud.Schedule( rate: nil, cron: nil ) as "s1"; +} catch e { + error = e; +} +expect.equal(error, "rate or cron need to be filled."); + +try { + new cloud.Schedule( rate: 2m, cron: "* * * * *" ) as "s2"; +} catch e { + error = e; +} +expect.equal(error, "rate and cron cannot be configured simultaneously."); + + +try { + new cloud.Schedule( rate: 1s ) as "s3"; +} catch e { + error = e; +} +expect.equal(error, "rate can not be set to less than 1 minute."); + +try { + new cloud.Schedule( cron: "* * * * * *" ) as "s4"; +} catch e { + error = e; +} +expect.equal(error, "cron string must be in UNIX cron format"); + +try { + new cloud.Schedule( cron: "* * * * ?" ) as "s5"; +} catch e { + error = e; +} +expect.equal(error, "cron string must be in UNIX cron format"); diff --git a/tests/sdk_tests/secret/secret-ref.test.w b/tests/sdk_tests/secret/secret-ref.test.w index e6adbc23720..13612d02eca 100644 --- a/tests/sdk_tests/secret/secret-ref.test.w +++ b/tests/sdk_tests/secret/secret-ref.test.w @@ -1,12 +1,11 @@ -bring util; bring aws; bring expect; -if util.env("WING_TARGET") == "tf-aws" { +if @target == "tf-aws" { let someExistingSecretArn = "arn:aws:secretsmanager:::secret:mysecret"; let secret = new aws.SecretRef(someExistingSecretArn); test "secretArn" { expect.equal(someExistingSecretArn, secret.secretArn); } -} \ No newline at end of file +} diff --git a/tests/sdk_tests/service/callbacks.test.w b/tests/sdk_tests/service/callbacks.test.w index dae377a4811..2b5074455d2 100644 --- a/tests/sdk_tests/service/callbacks.test.w +++ b/tests/sdk_tests/service/callbacks.test.w @@ -1,9 +1,8 @@ bring cloud; -bring util; bring http; -// hack: only supported in the "sim" target for now -if util.env("WING_TARGET") == "sim" { +// only supported in the "sim" target for now +if @target == "sim" { let b = new cloud.Bucket(); let startCounter = new cloud.Counter(); let status = "status"; diff --git a/tests/sdk_tests/service/http-server.test.w b/tests/sdk_tests/service/http-server.test.w index 52486f3ae8b..2d13352c6fb 100644 --- a/tests/sdk_tests/service/http-server.test.w +++ b/tests/sdk_tests/service/http-server.test.w @@ -1,5 +1,4 @@ bring cloud; -bring util; bring http; struct Address { @@ -12,8 +11,8 @@ inflight interface IHttpServer { } -// hack: only supported in the "sim" target for now -if util.env("WING_TARGET") == "sim" { +// only supported in the "sim" target for now +if @target == "sim" { class MyService { b: cloud.Bucket; body: str; diff --git a/tests/sdk_tests/service/minimal.test.w b/tests/sdk_tests/service/minimal.test.w index c1a0544027d..4dce1e770ce 100644 --- a/tests/sdk_tests/service/minimal.test.w +++ b/tests/sdk_tests/service/minimal.test.w @@ -1,9 +1,7 @@ bring cloud; -bring util; // hack: only supported in the "sim" target for now -if util.env("WING_TARGET") == "sim" { - +if @target == "sim" { let s = new cloud.Service(inflight () => { log("hello, service!"); @@ -17,4 +15,4 @@ if util.env("WING_TARGET") == "sim" { s.stop(); assert(!s.started()); } -} \ No newline at end of file +} diff --git a/tests/sdk_tests/service/stateful.test.w b/tests/sdk_tests/service/stateful.test.w index 6e6ba08cffc..80e8f177b85 100644 --- a/tests/sdk_tests/service/stateful.test.w +++ b/tests/sdk_tests/service/stateful.test.w @@ -3,7 +3,7 @@ bring util; bring http; // hack: only supported in the "sim" target for now -if util.env("WING_TARGET") == "sim" { +if @target == "sim" { class MyService { b: cloud.Bucket; body: str; @@ -46,4 +46,4 @@ if util.env("WING_TARGET") == "sim" { test "service is ready only after onStart finishes" { foo.access(); } -} \ No newline at end of file +} diff --git a/tests/sdk_tests/service/tokens.test.w b/tests/sdk_tests/service/tokens.test.w index 551be44b0db..771cff56c39 100644 --- a/tests/sdk_tests/service/tokens.test.w +++ b/tests/sdk_tests/service/tokens.test.w @@ -2,8 +2,8 @@ bring cloud; bring util; bring http; -// hack: only supported in the "sim" target for now -if util.env("WING_TARGET") == "sim" { +// only supported in the "sim" target for now +if @target == "sim" { let b = new cloud.Bucket(); let api = new cloud.Api(); api.get("/", inflight () => { diff --git a/tests/sdk_tests/state/get.test.w b/tests/sdk_tests/state/get.test.w index ff0951859d5..223e23e4c09 100644 --- a/tests/sdk_tests/state/get.test.w +++ b/tests/sdk_tests/state/get.test.w @@ -1,8 +1,6 @@ bring "./my-service.w" as my; -bring util; - -if util.env("WING_TARGET") == "sim" { +if @target == "sim" { let svc = new my.MyService(); test "state.get() returns the runtime value" { diff --git a/tests/sdk_tests/state/set.test.w b/tests/sdk_tests/state/set.test.w index f59658f3778..b062485145b 100644 --- a/tests/sdk_tests/state/set.test.w +++ b/tests/sdk_tests/state/set.test.w @@ -1,13 +1,10 @@ bring "./my-service.w" as my; -bring util; - -if util.env("WING_TARGET") == "sim" { +if @target == "sim" { let svc = new my.MyService(); test "token resolved at runtime" { log(svc.startTime); assert(svc.startTime == "2023-10-16T20:47:39.511Z"); } - -} \ No newline at end of file +} diff --git a/tests/sdk_tests/topic/aws-topic.test.w b/tests/sdk_tests/topic/aws-topic.test.w index d585b1a6b21..7d0d73e8389 100644 --- a/tests/sdk_tests/topic/aws-topic.test.w +++ b/tests/sdk_tests/topic/aws-topic.test.w @@ -1,8 +1,5 @@ bring cloud; bring aws; -bring util; - -let target = util.env("WING_TARGET"); let topic = new cloud.Topic() as "aws-wing-topic"; @@ -20,7 +17,7 @@ let topicInfo = getTopicInfo(topic); test "validates the AWS topic name" { if let topic = topicInfo { - if target == "tf-aws" { + if @target == "tf-aws" { assert(topic.get("topicArn").contains("arn:aws:sns:")); assert(topic.get("topicArn").contains("aws-wing-topic")); assert(topic.get("topicName").contains("aws-wing-topic")); @@ -32,4 +29,4 @@ test "validates the AWS topic name" { } // If the test is not on AWS, it should not fail, so I am returning true. assert(true); -} \ No newline at end of file +} diff --git a/tests/sdk_tests/util/shell.test.w b/tests/sdk_tests/util/shell.test.w index 5939d02b2e9..624e2108e35 100644 --- a/tests/sdk_tests/util/shell.test.w +++ b/tests/sdk_tests/util/shell.test.w @@ -2,10 +2,6 @@ bring util; bring expect; bring fs; -class Util { - extern "./util.js" pub static inflight platform(): str; -} - let assertThrows = inflight (expected: str, block: (): void) => { let var error = false; try { @@ -22,7 +18,7 @@ test "shell() with valid command" { let output = util.shell(command); - if Util.platform() != "win32" { + if util.os() != "win32" { expect.equal(output, "Hello, Wing!\n"); } else { expect.equal(output, "Hello, Wing!\r\n"); @@ -51,7 +47,7 @@ test "shell() with explicit non-zero exit status" { test "shell() with env option" { let var command = ""; - if Util.platform() != "win32" { + if util.os() != "win32" { command = "echo $WING_TARGET $ENV_VAR"; } else { command = "echo %WING_TARGET% %ENV_VAR%"; @@ -62,7 +58,7 @@ test "shell() with env option" { let output = util.shell(command, opts); - if Util.platform() != "win32" { + if util.os() != "win32" { expect.equal(output, "Wing\n"); } else { expect.equal(output, "%WING_TARGET% Wing\r\n"); @@ -70,10 +66,8 @@ test "shell() with env option" { } test "shell() with inheritEnv option" { - let target = util.env("WING_TARGET"); - let var command = ""; - if Util.platform() != "win32" { + if util.os() != "win32" { command = "echo $WING_TARGET"; } else { command = "echo %WING_TARGET%"; @@ -85,15 +79,15 @@ test "shell() with inheritEnv option" { let output1 = util.shell(command); let output2 = util.shell(command, opts); - if Util.platform() != "win32" { + if util.os() != "win32" { // \n expect.equal(output1.length, 1); } else { // %WING_TARGET%\r\n expect.equal(output1.length, 15); } - assert(output1.contains(target) == false); - assert(output2.contains(target) == true); + assert(output1.contains(@target) == false); + assert(output2.contains(@target) == true); } test "shell() with cwd option" { @@ -115,4 +109,4 @@ test "shell() with cwd option" { let output2 = util.shell(command2, opts2); expect.equal(output2, "Error executing command \"exit 1\". Exited with error code: 1"); -} \ No newline at end of file +} diff --git a/tests/sdk_tests/util/util.extern.d.ts b/tests/sdk_tests/util/util.extern.d.ts deleted file mode 100644 index 06d5b1d6059..00000000000 --- a/tests/sdk_tests/util/util.extern.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default interface extern { - platform: () => Promise, -} diff --git a/tests/sdk_tests/util/util.js b/tests/sdk_tests/util/util.js deleted file mode 100644 index 52c30974b28..00000000000 --- a/tests/sdk_tests/util/util.js +++ /dev/null @@ -1,5 +0,0 @@ -const os = require("os"); - -exports.platform = function () { - return os.platform(); -}; \ No newline at end of file diff --git a/tests/sdk_tests/website/aws-website.test.w b/tests/sdk_tests/website/aws-website.test.w index 70a8f5062ab..59406caaac8 100644 --- a/tests/sdk_tests/website/aws-website.test.w +++ b/tests/sdk_tests/website/aws-website.test.w @@ -1,9 +1,5 @@ bring cloud; bring aws; -bring util; - -let target = util.env("WING_TARGET"); - let website = new cloud.Website(path: "./website") as "aws-wing-website"; @@ -21,7 +17,7 @@ let websiteName = getWebsiteInfo(website); test "validates the AWS bucket name" { if let website = websiteName { - if target == "tf-aws" { + if @target == "tf-aws" { assert(website.get("bucketArn").contains("arn:aws:s3:::")); assert(website.get("bucketArn").contains("aws-wing-website")); assert(website.get("bucketName").contains("aws-wing-website")); @@ -33,4 +29,4 @@ test "validates the AWS bucket name" { } // If the test is not on AWS, it should not fail, so I am returning true. assert(true); -} \ No newline at end of file +} diff --git a/tests/valid/casting.test.w b/tests/valid/casting.test.w index e4ecffbbd1e..58412dcd403 100644 --- a/tests/valid/casting.test.w +++ b/tests/valid/casting.test.w @@ -1,10 +1,9 @@ bring cloud; -bring util; bring "@cdktf/provider-aws" as aws; let b = new cloud.Bucket(); -if util.env("WING_TARGET") == "tf-aws" { +if @target == "tf-aws" { let s3Bucket: aws.s3Bucket.S3Bucket = unsafeCast(nodeof(b).findChild("Default")); s3Bucket.addOverride("bucket_prefix", "my-prefix-"); diff --git a/tests/valid/dynamo.test.w b/tests/valid/dynamo.test.w index eda854e8be5..f5af47b99ae 100644 --- a/tests/valid/dynamo.test.w +++ b/tests/valid/dynamo.test.w @@ -6,7 +6,6 @@ skip: true bring "@cdktf/provider-aws" as tfaws; bring aws; bring cloud; -bring util; enum AttributeType { String, @@ -23,9 +22,8 @@ class DynamoTable { table: tfaws.dynamodbTable.DynamodbTable; tableName: str; new() { - let target = util.env("WING_TARGET"); - if target != "tf-aws" { - throw "Unsupported target: {target} (expected 'tf-aws')"; + if @target != "tf-aws" { + throw "Unsupported target: {@target} (expected 'tf-aws')"; } this.table = new tfaws.dynamodbTable.DynamodbTable( diff --git a/tests/valid/dynamo_awscdk.test.w b/tests/valid/dynamo_awscdk.test.w index c4cbb3b4cbb..d5a041bb04d 100644 --- a/tests/valid/dynamo_awscdk.test.w +++ b/tests/valid/dynamo_awscdk.test.w @@ -23,9 +23,8 @@ class DynamoTable { table: awscdk.aws_dynamodb.Table; tableName: str; new() { - let target = util.env("WING_TARGET"); - if target != "awscdk" { - throw "Unsupported target: {target} (expected 'awscdk')"; + if @target != "awscdk" { + throw "Unsupported target: {@target} (expected 'awscdk')"; } this.table = new awscdk.aws_dynamodb.Table( diff --git a/tests/valid/inflight_handler_singleton.test.w b/tests/valid/inflight_handler_singleton.test.w index c4cf053c5d8..379d301c0c4 100644 --- a/tests/valid/inflight_handler_singleton.test.w +++ b/tests/valid/inflight_handler_singleton.test.w @@ -30,8 +30,6 @@ let fn2 = new cloud.Function(inflight () => { return "{n}-fn2"; }) as "fn2"; -let sim = util.env("WING_TARGET") == "sim"; - test "single instance of Foo" { let x = fn.invoke(""); let y = fn.invoke(""); @@ -41,7 +39,7 @@ test "single instance of Foo" { // the simulator intentionally reuses the sandbox across invocations // but we can't trust that this will always happen on the cloud - if sim { + if @target == "sim" { expect.equal(y, "101"); log("client has been reused"); } diff --git a/tests/valid/intrinsics.test.w b/tests/valid/intrinsics.test.w index ee23acf5f96..ca9775f9d64 100644 --- a/tests/valid/intrinsics.test.w +++ b/tests/valid/intrinsics.test.w @@ -19,3 +19,8 @@ expect.equal(bar.Bar.getSubdir(), fs.join(@dirname, "subdir")); expect.equal(@filename, currentFile); expect.equal(fs.dirname(currentFile), @dirname); expect.equal(bar.Bar.getSubfile(), fs.join(@dirname, "subdir", "bar.w")); + +// @target + +// some of the targets we are testing in the monorepo - but any string is valid +expect.ok(["sim", "tf-aws", "tf-azure", "tf-gcp", "awscdk"].contains(@target)); diff --git a/tools/hangar/__snapshots__/test_corpus/sdk_tests/resource/on-start.test.w_test_sim.md b/tools/hangar/__snapshots__/test_corpus/sdk_tests/resource/on-start.test.w_test_sim.md index dd4557439b3..7a2968f04e6 100644 --- a/tools/hangar/__snapshots__/test_corpus/sdk_tests/resource/on-start.test.w_test_sim.md +++ b/tools/hangar/__snapshots__/test_corpus/sdk_tests/resource/on-start.test.w_test_sim.md @@ -3,14 +3,14 @@ ## stdout.log ```log [ERROR] method calls fail if the resource fails to start | Error: unexpected error! - --> on-start.test.w:6:5 + --> on-start.test.w:5:5 | | inflight class OnStartThrowerBackend impl sim.IResource { | new() { -6 | throw "unexpected error!"; +5 | throw "unexpected error!"; | ^ -at $inflight_init /on-start.test.w:6:5 -at /on-start.test.w:17:18 +at $inflight_init /on-start.test.w:5:5 +at /on-start.test.w:16:18 [ERROR] method calls fail if the resource fails to start | Error: root/Default/OnStartThrower/Resource failed to start: Error: unexpected error! [ERROR] method calls fail if the resource fails to start | Error: Resource is not running (it may have crashed or stopped) pass ─ on-start.test.wsim » root/Default/test:method calls fail if the resource fails to start diff --git a/tools/hangar/__snapshots__/test_corpus/sdk_tests/resource/on-stop.test.w_test_sim.md b/tools/hangar/__snapshots__/test_corpus/sdk_tests/resource/on-stop.test.w_test_sim.md index da5227a4fdf..5e6cb205fb8 100644 --- a/tools/hangar/__snapshots__/test_corpus/sdk_tests/resource/on-stop.test.w_test_sim.md +++ b/tools/hangar/__snapshots__/test_corpus/sdk_tests/resource/on-stop.test.w_test_sim.md @@ -3,13 +3,13 @@ ## stdout.log ```log [ERROR] if a resource throws an error on stopping, it doesn't crash the simulation | Error: unexpected error! - --> on-stop.test.w:6:5 + --> on-stop.test.w:5:5 | | inflight class OnStopThrowerBackend impl sim.IResource { | pub onStop() { -6 | throw "unexpected error!"; +5 | throw "unexpected error!"; | ^ -at onStop /on-stop.test.w:6:5 +at onStop /on-stop.test.w:5:5 pass ─ on-stop.test.wsim » root/Default/test:if a resource throws an error on stopping, it doesn't crash the simulation Tests 1 passed (1) diff --git a/tools/hangar/__snapshots__/test_corpus/sdk_tests/schedule/init.test.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/sdk_tests/schedule/init.test.w_compile_tf-aws.md new file mode 100644 index 00000000000..e93a393f163 --- /dev/null +++ b/tools/hangar/__snapshots__/test_corpus/sdk_tests/schedule/init.test.w_compile_tf-aws.md @@ -0,0 +1,33 @@ +# [init.test.w](../../../../../../tests/sdk_tests/schedule/init.test.w) | compile | tf-aws + +## main.tf.json +```json +{ + "//": { + "metadata": { + "backend": "local", + "stackName": "root" + }, + "outputs": {} + }, + "provider": { + "aws": [ + {} + ] + }, + "resource": { + "aws_cloudwatch_event_rule": { + "s0_Schedule_7FE1E150": { + "//": { + "metadata": { + "path": "root/Default/Default/s0/Schedule", + "uniqueId": "s0_Schedule_7FE1E150" + } + }, + "schedule_expression": "rate(5 minutes)" + } + } + } +} +``` + diff --git a/tools/hangar/__snapshots__/test_corpus/sdk_tests/schedule/init.test.w_test_sim.md b/tools/hangar/__snapshots__/test_corpus/sdk_tests/schedule/init.test.w_test_sim.md new file mode 100644 index 00000000000..9329ccefd9c --- /dev/null +++ b/tools/hangar/__snapshots__/test_corpus/sdk_tests/schedule/init.test.w_test_sim.md @@ -0,0 +1,12 @@ +# [init.test.w](../../../../../../tests/sdk_tests/schedule/init.test.w) | test | sim + +## stdout.log +```log +pass ─ init.test.wsim (no tests) + +Tests 1 passed (1) +Snapshots 1 skipped +Test Files 1 passed (1) +Duration +``` + diff --git a/tools/hangar/__snapshots__/test_corpus/valid/casting.test.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/valid/casting.test.w_compile_tf-aws.md index 47b9f5b4e68..86887482149 100644 --- a/tools/hangar/__snapshots__/test_corpus/valid/casting.test.w_compile_tf-aws.md +++ b/tools/hangar/__snapshots__/test_corpus/valid/casting.test.w_compile_tf-aws.md @@ -85,11 +85,10 @@ class $Root extends $stdlib.std.Resource { $helpers.nodeof(this).root.$preflightTypesMap = { }; let $preflightTypesMap = {}; const cloud = $stdlib.cloud; - const util = $stdlib.util; const aws = require("@cdktf/provider-aws"); $helpers.nodeof(this).root.$preflightTypesMap = $preflightTypesMap; const b = globalThis.$ClassFactory.new("@winglang/sdk.cloud.Bucket", cloud.Bucket, this, "Bucket"); - if ($helpers.eq((util.Util.env("WING_TARGET")), "tf-aws")) { + if ($helpers.eq(process.env.WING_TARGET, "tf-aws")) { const s3Bucket = ($helpers.nodeof(b).findChild("Default")); (s3Bucket.addOverride("bucket_prefix", "my-prefix-")); console.log($helpers.nodeof(s3Bucket).path); diff --git a/tools/hangar/__snapshots__/test_corpus/valid/inflight_handler_singleton.test.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/valid/inflight_handler_singleton.test.w_compile_tf-aws.md index 31d6ec7983f..385847fa764 100644 --- a/tools/hangar/__snapshots__/test_corpus/valid/inflight_handler_singleton.test.w_compile_tf-aws.md +++ b/tools/hangar/__snapshots__/test_corpus/valid/inflight_handler_singleton.test.w_compile_tf-aws.md @@ -51,7 +51,7 @@ module.exports = function({ $foo }) { "use strict"; const $helpers = require("@winglang/sdk/lib/helpers"); const $macros = require("@winglang/sdk/lib/macros"); -module.exports = function({ $expect_Util, $fn, $fn2, $sim }) { +module.exports = function({ $expect_Util, $fn, $fn2 }) { class $Closure3 { constructor($args) { const { } = $args; @@ -64,7 +64,7 @@ module.exports = function({ $expect_Util, $fn, $fn2, $sim }) { const y = (await $fn.invoke("")); const z = (await $fn2.invoke("")); (await $expect_Util.equal(x, "100")); - if ($sim) { + if ($helpers.eq(process.env.WING_TARGET, "sim")) { (await $expect_Util.equal(y, "101")); console.log("client has been reused"); } @@ -546,7 +546,6 @@ class $Root extends $stdlib.std.Resource { $expect_Util: ${$stdlib.core.liftObject($stdlib.core.toLiftableModuleType(globalThis.$ClassFactory.resolveType("@winglang/sdk.expect.Util") ?? expect.Util, "@winglang/sdk/expect", "Util"))}, $fn: ${$stdlib.core.liftObject(fn)}, $fn2: ${$stdlib.core.liftObject(fn2)}, - $sim: ${$stdlib.core.liftObject(sim)}, }) `; } @@ -556,13 +555,11 @@ class $Root extends $stdlib.std.Resource { [$stdlib.core.toLiftableModuleType(globalThis.$ClassFactory.resolveType("@winglang/sdk.expect.Util") ?? expect.Util, "@winglang/sdk/expect", "Util"), ["equal"]], [fn, ["invoke"]], [fn2, ["invoke"]], - [sim, []], ], "$inflight_init": [ [$stdlib.core.toLiftableModuleType(globalThis.$ClassFactory.resolveType("@winglang/sdk.expect.Util") ?? expect.Util, "@winglang/sdk/expect", "Util"), []], [fn, []], [fn2, []], - [sim, []], ], }); } @@ -630,7 +627,6 @@ class $Root extends $stdlib.std.Resource { const foo = new Foo(this, "Foo"); const fn = globalThis.$ClassFactory.new("@winglang/sdk.cloud.Function", cloud.Function, this, "Function", new $Closure1(this, "$Closure1")); const fn2 = globalThis.$ClassFactory.new("@winglang/sdk.cloud.Function", cloud.Function, this, "fn2", new $Closure2(this, "$Closure2")); - const sim = $helpers.eq((util.Util.env("WING_TARGET")), "sim"); globalThis.$ClassFactory.new("@winglang/sdk.std.Test", std.Test, this, "test:single instance of Foo", new $Closure3(this, "$Closure3")); const fn3 = globalThis.$ClassFactory.new("@winglang/sdk.cloud.Function", cloud.Function, this, "fn3", new $Closure4(this, "$Closure4")); globalThis.$ClassFactory.new("@winglang/sdk.std.Test", std.Test, this, "test:Foo state is not shared between function invocations", new $Closure5(this, "$Closure5")); diff --git a/tools/hangar/__snapshots__/test_corpus/valid/intrinsics.test.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/valid/intrinsics.test.w_compile_tf-aws.md index 98e4e785968..8c28992ceed 100644 --- a/tools/hangar/__snapshots__/test_corpus/valid/intrinsics.test.w_compile_tf-aws.md +++ b/tools/hangar/__snapshots__/test_corpus/valid/intrinsics.test.w_compile_tf-aws.md @@ -134,6 +134,7 @@ class $Root extends $stdlib.std.Resource { (expect.Util.equal($helpers.resolve(__dirname, "../../../intrinsics.test.w"), currentFile)); (expect.Util.equal((fs.Util.dirname(currentFile)), $helpers.resolve(__dirname, "../../.."))); (expect.Util.equal((bar.Bar.getSubfile(this)), (fs.Util.join($helpers.resolve(__dirname, "../../.."), "subdir", "bar.w")))); + (expect.Util.ok($macros.__Array_contains(false, ["sim", "tf-aws", "tf-azure", "tf-gcp", "awscdk"], process.env.WING_TARGET))); } } const $APP = $PlatformManager.createApp({ outdir: $outdir, name: "intrinsics.test", rootConstruct: $Root, isTestEnvironment: $wing_is_test, entrypointDir: process.env['WING_SOURCE_DIR'], rootId: process.env['WING_ROOT_ID'] }); diff --git a/wing-console/console/ui/src/features/inspector-pane/resource-panes/custom-resource-table.tsx b/wing-console/console/ui/src/features/inspector-pane/resource-panes/custom-resource-table.tsx index ecc345d0a68..7abf054296a 100644 --- a/wing-console/console/ui/src/features/inspector-pane/resource-panes/custom-resource-table.tsx +++ b/wing-console/console/ui/src/features/inspector-pane/resource-panes/custom-resource-table.tsx @@ -1,3 +1,5 @@ +import { ArrowPathIcon } from "@heroicons/react/24/outline"; +import { Button } from "@wingconsole/design-system"; import { memo } from "react"; import { trpc } from "../../../trpc.js"; @@ -18,6 +20,15 @@ export const CustomResourceTable = memo(
+
+
{tableScan.data && (