From bc99274bb862be99c4bd8a075d410edccb4e84e3 Mon Sep 17 00:00:00 2001 From: Chris Rybicki Date: Tue, 1 Oct 2024 12:34:39 -0400 Subject: [PATCH 1/8] feat(compiler): descriptions in generated JSON schemas --- packages/@winglang/wingc/src/jsify.rs | 2 +- .../wingc/src/json_schema_generator.rs | 126 ++++++++++++------ tests/valid/struct_from_json.test.w | 30 ++++- tests/valid/subdir/structs.w | 2 + 4 files changed, 117 insertions(+), 43 deletions(-) diff --git a/packages/@winglang/wingc/src/jsify.rs b/packages/@winglang/wingc/src/jsify.rs index 5b5160be71c..dc2959baf19 100644 --- a/packages/@winglang/wingc/src/jsify.rs +++ b/packages/@winglang/wingc/src/jsify.rs @@ -380,7 +380,7 @@ impl<'a> JSifier<'a> { code.line(format!( "const {flat_name} = $stdlib.std.Struct._createJsonSchema({});", - schema_code.to_string().replace("\n", "").replace(" ", "") + schema_code.to_string() )); } code diff --git a/packages/@winglang/wingc/src/json_schema_generator.rs b/packages/@winglang/wingc/src/json_schema_generator.rs index 0aa2335587d..ae1c590d0ca 100644 --- a/packages/@winglang/wingc/src/json_schema_generator.rs +++ b/packages/@winglang/wingc/src/json_schema_generator.rs @@ -1,4 +1,5 @@ use crate::{ + docs::Docs, jsify::{codemaker::CodeMaker, JSifier}, type_check::{symbol_env::SymbolEnv, Struct, Type, UnsafeRef}, }; @@ -13,10 +14,12 @@ impl JsonSchemaGenerator { fn get_struct_env_properties(&self, env: &SymbolEnv) -> CodeMaker { let mut code = CodeMaker::default(); for (field_name, entry) in env.symbol_map.iter() { - code.line(format!( - "{}: {},", + let var_info = entry.kind.as_variable().unwrap(); + let docs = var_info.docs.clone(); + code.append(format!( + "{}:{},", field_name, - self.get_struct_schema_field(&entry.kind.as_variable().unwrap().type_) + self.get_struct_schema_field(&entry.kind.as_variable().unwrap().type_, docs) )); } code @@ -24,62 +27,87 @@ impl JsonSchemaGenerator { fn get_struct_schema_required_fields(&self, env: &SymbolEnv) -> CodeMaker { let mut code = CodeMaker::default(); - code.open("required: ["); + code.append("required:["); for (field_name, entry) in env.symbol_map.iter() { if !matches!(*entry.kind.as_variable().unwrap().type_, Type::Optional(_)) { - code.line(format!("\"{}\",", field_name)); + code.append(format!("\"{}\",", field_name)); } } - code.close("]"); + code.append("]"); code } - fn get_struct_schema_field(&self, typ: &UnsafeRef) -> String { + fn get_struct_schema_field(&self, typ: &UnsafeRef, docs: Option) -> String { match **typ { Type::String | Type::Number | Type::Boolean => { - format!("{{ type: \"{}\" }}", JSifier::jsify_type(typ).unwrap()) + let jsified_type = JSifier::jsify_type(typ).unwrap(); + match docs { + Some(docs) => format!( + "{{type:\"{}\",description:\"{}\"}}", + jsified_type, + docs.summary.unwrap_or_default() + ), + None => format!("{{type:\"{}\"}}", jsified_type), + } } Type::Struct(ref s) => { let mut code = CodeMaker::default(); - code.open("{"); - code.line("type: \"object\","); - code.open("properties: {"); - code.add_code(self.get_struct_env_properties(&s.env)); - code.close("},"); - code.add_code(self.get_struct_schema_required_fields(&s.env)); - code.close("}"); + code.append("{"); + code.append("type:\"object\","); + code.append("properties:{"); + code.append(self.get_struct_env_properties(&s.env)); + code.append("},"); + code.append(self.get_struct_schema_required_fields(&s.env)); + if let Some(docs) = docs { + code.append(format!(",description:\"{}\"", docs.summary.unwrap_or_default())); + } + code.append("}"); code.to_string() } Type::Array(ref t) | Type::Set(ref t) => { let mut code = CodeMaker::default(); - code.open("{"); + code.append("{"); - code.line("type: \"array\","); + code.append("type:\"array\""); if matches!(**typ, Type::Set(_)) { - code.line("uniqueItems: true,"); + code.append(",uniqueItems:true"); } - code.line(format!("items: {}", self.get_struct_schema_field(t))); + code.append(format!(",items:{}", self.get_struct_schema_field(t, None))); - code.close("}"); + if let Some(docs) = docs { + code.append(format!(",description:\"{}\"", docs.summary.unwrap_or_default())); + } + + code.append("}"); code.to_string() } Type::Map(ref t) => { let mut code = CodeMaker::default(); - code.open("{"); + code.append("{"); - code.line("type: \"object\","); - code.line(format!( - "patternProperties: {{ \".*\": {} }}", - self.get_struct_schema_field(t) + code.append("type:\"object\","); + code.append(format!( + "patternProperties: {{\".*\":{}}}", + self.get_struct_schema_field(t, None) )); - code.close("}"); + if let Some(docs) = docs { + code.append(format!("description:\"{}\",", docs.summary.unwrap_or_default())); + } + + code.append("}"); code.to_string() } - Type::Optional(t) => self.get_struct_schema_field(&t), - Type::Json(_) => "{ type: [\"object\", \"string\", \"boolean\", \"number\", \"array\"] }".to_string(), + Type::Optional(ref t) => self.get_struct_schema_field(t, docs), + Type::Json(_) => match docs { + Some(docs) => format!( + "{{type:[\"object\",\"string\",\"boolean\",\"number\",\"array\"],description:\"{}\"}}", + docs.summary.unwrap_or_default() + ), + None => "{type:[\"object\",\"string\",\"boolean\",\"number\",\"array\"]}".to_string(), + }, Type::Enum(ref enu) => { let choices = enu .values @@ -87,33 +115,49 @@ impl JsonSchemaGenerator { .map(|(s, _)| format!("\"{}\"", s)) .collect::>() .join(", "); - format!("{{ type: \"string\", enum: [{}] }}", choices) + match docs { + Some(docs) => format!( + "{{type:\"string\",enum:[{}],description:\"{}\"}}", + choices, + docs.summary.unwrap_or_default() + ), + None => format!("{{type:\"string\",enum:[{}]}}", choices), + } } - _ => "{ type: \"null\" }".to_string(), + _ => match docs { + Some(docs) => format!( + "{{type:\"null\",description:\"{}\" }}", + docs.summary.unwrap_or_default() + ), + None => "{type:\"null\"}".to_string(), + }, } } pub fn create_from_struct(&self, struct_: &Struct) -> CodeMaker { let mut code = CodeMaker::default(); - code.open("{"); - code.line(format!("$id: \"/{}\",", struct_.name)); - code.line("type: \"object\",".to_string()); + code.append("{"); + code.append(format!("$id:\"/{}\",", struct_.name)); + code.append("type:\"object\",".to_string()); - code.open("properties: {"); + code.append("properties:{"); - code.add_code(self.get_struct_env_properties(&struct_.env)); + code.append(self.get_struct_env_properties(&struct_.env)); //close properties - code.close("},"); + code.append("},"); - code.add_code(self.get_struct_schema_required_fields(&struct_.env)); + code.append(self.get_struct_schema_required_fields(&struct_.env)); - // close schema - code.close("}"); + code.append(format!( + ",description:\"{}\"", + struct_.docs.summary.as_ref().unwrap_or(&String::new()) + )); - let cleaned = code.to_string().replace("\n", "").replace(" ", ""); + // close schema + code.append("}"); - CodeMaker::one_line(cleaned) + code } } diff --git a/tests/valid/struct_from_json.test.w b/tests/valid/struct_from_json.test.w index d342e1e015e..ce6a77eebfe 100644 --- a/tests/valid/struct_from_json.test.w +++ b/tests/valid/struct_from_json.test.w @@ -263,9 +263,13 @@ bring "./subdir/structs_2.w" as otherExternalStructs; enum Color { red, green, blue } +/// MyStruct docs struct MyStruct { + /// m1 docs m1: externalStructs.MyStruct; + /// m2 docs m2: otherExternalStructs.MyStruct; + /// color docs color: Color; } @@ -288,7 +292,31 @@ expect.equal(myStruct.color, Color.red); let schema = MyStruct.schema(); schema.validate(jMyStruct); // Should not throw exception -let expectedSchema = {"$id":"/MyStruct","type":"object","properties":{"color":{"type":"string","enum":["red","green","blue"]},"m1":{"type":"object","properties":{"val":{"type":"number"}},"required":["val"]},"m2":{"type":"object","properties":{"val":{"type":"string"}},"required":["val"]}},"required":["color","m1","m2"]}; +let expectedSchema = { + "$id": "/MyStruct", + "type": "object", + "properties": { + "color": { + "type": "string", + "enum": ["red", "green", "blue"], + "description": "color docs", + }, + "m1": { + "type": "object", + "properties": { "val": { "type": "number", "description": "val docs" } }, + "required": ["val"], + "description": "m1 docs", + }, + "m2": { + "type": "object", + "properties": { "val": { "type": "string" } }, + "required": ["val"], + "description": "m2 docs", + }, + }, + "required": ["color", "m1", "m2"], + "description": "MyStruct docs", +}; expect.equal(schema.asStr(), Json.stringify(expectedSchema)); diff --git a/tests/valid/subdir/structs.w b/tests/valid/subdir/structs.w index 0a7905e8116..e9fd033cc20 100644 --- a/tests/valid/subdir/structs.w +++ b/tests/valid/subdir/structs.w @@ -1,4 +1,6 @@ +/// MyStruct docs in subdir pub struct MyStruct { + /// val docs val: num; } From 281de2cab1cd7b2c80c06b9fb3b3903a6d4428c4 Mon Sep 17 00:00:00 2001 From: Chris Rybicki Date: Tue, 1 Oct 2024 12:41:28 -0400 Subject: [PATCH 2/8] fallback if no description to the type's description --- .../wingc/src/json_schema_generator.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/packages/@winglang/wingc/src/json_schema_generator.rs b/packages/@winglang/wingc/src/json_schema_generator.rs index ae1c590d0ca..8267644b355 100644 --- a/packages/@winglang/wingc/src/json_schema_generator.rs +++ b/packages/@winglang/wingc/src/json_schema_generator.rs @@ -58,9 +58,8 @@ impl JsonSchemaGenerator { code.append(self.get_struct_env_properties(&s.env)); code.append("},"); code.append(self.get_struct_schema_required_fields(&s.env)); - if let Some(docs) = docs { - code.append(format!(",description:\"{}\"", docs.summary.unwrap_or_default())); - } + let docs = docs.unwrap_or(s.docs.clone()); + code.append(format!(",description:\"{}\"", docs.summary.unwrap_or_default())); code.append("}"); code.to_string() } @@ -115,14 +114,12 @@ impl JsonSchemaGenerator { .map(|(s, _)| format!("\"{}\"", s)) .collect::>() .join(", "); - match docs { - Some(docs) => format!( - "{{type:\"string\",enum:[{}],description:\"{}\"}}", - choices, - docs.summary.unwrap_or_default() - ), - None => format!("{{type:\"string\",enum:[{}]}}", choices), - } + let docs = docs.unwrap_or(enu.docs.clone()); + format!( + "{{type:\"string\",enum:[{}],description:\"{}\"}}", + choices, + docs.summary.unwrap_or_default() + ) } _ => match docs { Some(docs) => format!( From 6d87c163a3317e78048f87519bfbba1e4d8dd6fa Mon Sep 17 00:00:00 2001 From: "monada-bot[bot]" Date: Tue, 1 Oct 2024 16:55:06 +0000 Subject: [PATCH 3/8] chore: self mutation (e2e-1of2.diff) Signed-off-by: monada-bot[bot] --- .../valid/optionals.test.w_compile_tf-aws.md | 2 +- .../simple/parameters.test.w_compile_tf-aws.md | 2 +- .../struct_from_json.test.w_compile_tf-aws.md | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tools/hangar/__snapshots__/test_corpus/valid/optionals.test.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/valid/optionals.test.w_compile_tf-aws.md index dfe57adfa05..80b3d9a2636 100644 --- a/tools/hangar/__snapshots__/test_corpus/valid/optionals.test.w_compile_tf-aws.md +++ b/tools/hangar/__snapshots__/test_corpus/valid/optionals.test.w_compile_tf-aws.md @@ -158,7 +158,7 @@ class $Root extends $stdlib.std.Resource { $helpers.nodeof(this).root.$preflightTypesMap = { }; let $preflightTypesMap = {}; const cloud = $stdlib.cloud; - const Person = $stdlib.std.Struct._createJsonSchema({$id:"/Person",type:"object",properties:{age:{type:"number"},name:{type:"string"},},required:["age","name",]}); + const Person = $stdlib.std.Struct._createJsonSchema({$id:"/Person",type:"object",properties:{age:{type:"number"},name:{type:"string"},},required:["age","name",],description:""}); $helpers.nodeof(this).root.$preflightTypesMap = $preflightTypesMap; class Super extends $stdlib.std.Resource { constructor($scope, $id, ) { diff --git a/tools/hangar/__snapshots__/test_corpus/valid/parameters/simple/parameters.test.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/valid/parameters/simple/parameters.test.w_compile_tf-aws.md index d330bbac75b..b952266e5fc 100644 --- a/tools/hangar/__snapshots__/test_corpus/valid/parameters/simple/parameters.test.w_compile_tf-aws.md +++ b/tools/hangar/__snapshots__/test_corpus/valid/parameters/simple/parameters.test.w_compile_tf-aws.md @@ -36,7 +36,7 @@ class $Root extends $stdlib.std.Resource { super($scope, $id); $helpers.nodeof(this).root.$preflightTypesMap = { }; let $preflightTypesMap = {}; - const MyParams = $stdlib.std.Struct._createJsonSchema({$id:"/MyParams",type:"object",properties:{foo:{type:"string"},meaningOfLife:{type:"number"},},required:["meaningOfLife",]}); + const MyParams = $stdlib.std.Struct._createJsonSchema({$id:"/MyParams",type:"object",properties:{foo:{type:"string"},meaningOfLife:{type:"number"},},required:["meaningOfLife",],description:""}); $helpers.nodeof(this).root.$preflightTypesMap = $preflightTypesMap; const myParams = $macros.__Struct_fromJson(false, MyParams, ($helpers.nodeof(this).app.parameters.read({ schema: $macros.__Struct_schema(false, MyParams, ) }))); { diff --git a/tools/hangar/__snapshots__/test_corpus/valid/struct_from_json.test.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/valid/struct_from_json.test.w_compile_tf-aws.md index 393b3d52ad0..8ade7d124c3 100644 --- a/tools/hangar/__snapshots__/test_corpus/valid/struct_from_json.test.w_compile_tf-aws.md +++ b/tools/hangar/__snapshots__/test_corpus/valid/struct_from_json.test.w_compile_tf-aws.md @@ -197,13 +197,13 @@ class $Root extends $stdlib.std.Resource { const expect = $stdlib.expect; const externalStructs = $helpers.bringJs(`${__dirname}/preflight.structs-1.cjs`, $preflightTypesMap); const otherExternalStructs = $helpers.bringJs(`${__dirname}/preflight.structs2-2.cjs`, $preflightTypesMap); - const Bar = $stdlib.std.Struct._createJsonSchema({$id:"/Bar",type:"object",properties:{b:{type:"number"},f:{type:"string"},},required:["b","f",]}); - const Foo = $stdlib.std.Struct._createJsonSchema({$id:"/Foo",type:"object",properties:{f:{type:"string"},},required:["f",]}); - const Foosible = $stdlib.std.Struct._createJsonSchema({$id:"/Foosible",type:"object",properties:{f:{type:"string"},},required:[]}); - const MyStruct = $stdlib.std.Struct._createJsonSchema({$id:"/MyStruct",type:"object",properties:{color:{type:"string",enum:["red","green","blue"]},m1:{type:"object",properties:{val:{type:"number"},},required:["val",]},m2:{type:"object",properties:{val:{type:"string"},},required:["val",]},},required:["color","m1","m2",]}); - const Student = $stdlib.std.Struct._createJsonSchema({$id:"/Student",type:"object",properties:{additionalData:{type:["object","string","boolean","number","array"]},advisor:{type:"object",properties:{dob:{type:"object",properties:{day:{type:"number"},month:{type:"number"},year:{type:"number"},},required:["day","month","year",]},employeeID:{type:"string"},firstName:{type:"string"},lastName:{type:"string"},},required:["dob","employeeID","firstName","lastName",]},coursesTaken:{type:"array",items:{type:"object",properties:{course:{type:"object",properties:{credits:{type:"number"},name:{type:"string"},},required:["credits","name",]},dateTaken:{type:"object",properties:{day:{type:"number"},month:{type:"number"},year:{type:"number"},},required:["day","month","year",]},grade:{type:"string"},},required:["course","dateTaken","grade",]}},dob:{type:"object",properties:{day:{type:"number"},month:{type:"number"},year:{type:"number"},},required:["day","month","year",]},enrolled:{type:"boolean"},enrolledCourses:{type:"array",uniqueItems:true,items:{type:"object",properties:{credits:{type:"number"},name:{type:"string"},},required:["credits","name",]}},firstName:{type:"string"},lastName:{type:"string"},schoolId:{type:"string"},},required:["dob","enrolled","firstName","lastName","schoolId",]}); - const cloud_CounterProps = $stdlib.std.Struct._createJsonSchema({$id:"/CounterProps",type:"object",properties:{initial:{type:"number"},},required:[]}); - const externalStructs_MyOtherStruct = $stdlib.std.Struct._createJsonSchema({$id:"/MyOtherStruct",type:"object",properties:{data:{type:"object",properties:{val:{type:"number"},},required:["val",]},},required:["data",]}); + const Bar = $stdlib.std.Struct._createJsonSchema({$id:"/Bar",type:"object",properties:{b:{type:"number"},f:{type:"string"},},required:["b","f",],description:""}); + const Foo = $stdlib.std.Struct._createJsonSchema({$id:"/Foo",type:"object",properties:{f:{type:"string"},},required:["f",],description:""}); + const Foosible = $stdlib.std.Struct._createJsonSchema({$id:"/Foosible",type:"object",properties:{f:{type:"string"},},required:[],description:""}); + const MyStruct = $stdlib.std.Struct._createJsonSchema({$id:"/MyStruct",type:"object",properties:{color:{type:"string",enum:["red", "green", "blue"],description:"color docs"},m1:{type:"object",properties:{val:{type:"number",description:"val docs"},},required:["val",],description:"m1 docs"},m2:{type:"object",properties:{val:{type:"string"},},required:["val",],description:"m2 docs"},},required:["color","m1","m2",],description:"MyStruct docs"}); + const Student = $stdlib.std.Struct._createJsonSchema({$id:"/Student",type:"object",properties:{additionalData:{type:["object","string","boolean","number","array"]},advisor:{type:"object",properties:{dob:{type:"object",properties:{day:{type:"number"},month:{type:"number"},year:{type:"number"},},required:["day","month","year",],description:""},employeeID:{type:"string"},firstName:{type:"string"},lastName:{type:"string"},},required:["dob","employeeID","firstName","lastName",],description:""},coursesTaken:{type:"array",items:{type:"object",properties:{course:{type:"object",properties:{credits:{type:"number"},name:{type:"string"},},required:["credits","name",],description:""},dateTaken:{type:"object",properties:{day:{type:"number"},month:{type:"number"},year:{type:"number"},},required:["day","month","year",],description:""},grade:{type:"string"},},required:["course","dateTaken","grade",],description:""}},dob:{type:"object",properties:{day:{type:"number"},month:{type:"number"},year:{type:"number"},},required:["day","month","year",],description:""},enrolled:{type:"boolean"},enrolledCourses:{type:"array",uniqueItems:true,items:{type:"object",properties:{credits:{type:"number"},name:{type:"string"},},required:["credits","name",],description:""}},firstName:{type:"string"},lastName:{type:"string"},schoolId:{type:"string"},},required:["dob","enrolled","firstName","lastName","schoolId",],description:""}); + const cloud_CounterProps = $stdlib.std.Struct._createJsonSchema({$id:"/CounterProps",type:"object",properties:{initial:{type:"number",description:"The initial value of the counter."},},required:[],description:"Options for `Counter`."}); + const externalStructs_MyOtherStruct = $stdlib.std.Struct._createJsonSchema({$id:"/MyOtherStruct",type:"object",properties:{data:{type:"object",properties:{val:{type:"number",description:"val docs"},},required:["val",],description:"MyStruct docs in subdir"},},required:["data",],description:""}); $helpers.nodeof(this).root.$preflightTypesMap = $preflightTypesMap; const Color = (function (tmp) { @@ -478,7 +478,7 @@ class $Root extends $stdlib.std.Resource { (expect.Util.equal(myStruct.color, Color.red)); const schema = $macros.__Struct_schema(false, MyStruct, ); (schema.validate(jMyStruct)); - const expectedSchema = ({"$id": "/MyStruct", "type": "object", "properties": ({"color": ({"type": "string", "enum": ["red", "green", "blue"]}), "m1": ({"type": "object", "properties": ({"val": ({"type": "number"})}), "required": ["val"]}), "m2": ({"type": "object", "properties": ({"val": ({"type": "string"})}), "required": ["val"]})}), "required": ["color", "m1", "m2"]}); + const expectedSchema = ({"$id": "/MyStruct", "type": "object", "properties": ({"color": ({"type": "string", "enum": ["red", "green", "blue"], "description": "color docs"}), "m1": ({"type": "object", "properties": ({"val": ({"type": "number", "description": "val docs"})}), "required": ["val"], "description": "m1 docs"}), "m2": ({"type": "object", "properties": ({"val": ({"type": "string"})}), "required": ["val"], "description": "m2 docs"})}), "required": ["color", "m1", "m2"], "description": "MyStruct docs"}); (expect.Util.equal((schema.asStr()), $macros.__Json_stringify(false, std.Json, expectedSchema))); globalThis.$ClassFactory.new("@winglang/sdk.std.Test", std.Test, this, "test:inflight schema usage", new $Closure4(this, "$Closure4")); (std.String.fromJson(10, { unsafe: true })); @@ -518,7 +518,7 @@ const $helpers = $stdlib.helpers; const $extern = $helpers.createExternRequire(__dirname); const $types = require("./types.cjs"); let $preflightTypesMap = {}; -const SomeStruct = $stdlib.std.Struct._createJsonSchema({$id:"/SomeStruct",type:"object",properties:{foo:{type:"string"},},required:["foo",]}); +const SomeStruct = $stdlib.std.Struct._createJsonSchema({$id:"/SomeStruct",type:"object",properties:{foo:{type:"string"},},required:["foo",],description:""}); class UsesStructInImportedFile extends $stdlib.std.Resource { constructor($scope, $id, ) { super($scope, $id); From fd34d03be87ee559bdec237874c1015387e62a73 Mon Sep 17 00:00:00 2001 From: "monada-bot[bot]" Date: Tue, 1 Oct 2024 16:55:06 +0000 Subject: [PATCH 4/8] chore: self mutation (e2e-2of2.diff) Signed-off-by: monada-bot[bot] --- .../valid/parameters/nested/parameters.test.w_compile_tf-aws.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/hangar/__snapshots__/test_corpus/valid/parameters/nested/parameters.test.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/valid/parameters/nested/parameters.test.w_compile_tf-aws.md index 78c03e65fa5..c21bc6dd0f8 100644 --- a/tools/hangar/__snapshots__/test_corpus/valid/parameters/nested/parameters.test.w_compile_tf-aws.md +++ b/tools/hangar/__snapshots__/test_corpus/valid/parameters/nested/parameters.test.w_compile_tf-aws.md @@ -36,7 +36,7 @@ class $Root extends $stdlib.std.Resource { super($scope, $id); $helpers.nodeof(this).root.$preflightTypesMap = { }; let $preflightTypesMap = {}; - const MyParams = $stdlib.std.Struct._createJsonSchema({$id:"/MyParams",type:"object",properties:{houses:{type:"array",items:{type:"object",properties:{address:{type:"string"},residents:{type:"array",items:{type:"object",properties:{age:{type:"number"},name:{type:"string"},},required:["age","name",]}},},required:["address","residents",]}},},required:["houses",]}); + const MyParams = $stdlib.std.Struct._createJsonSchema({$id:"/MyParams",type:"object",properties:{houses:{type:"array",items:{type:"object",properties:{address:{type:"string"},residents:{type:"array",items:{type:"object",properties:{age:{type:"number"},name:{type:"string"},},required:["age","name",],description:""}},},required:["address","residents",],description:""}},},required:["houses",],description:""}); $helpers.nodeof(this).root.$preflightTypesMap = $preflightTypesMap; const myParams = $macros.__Struct_fromJson(false, MyParams, ($helpers.nodeof(this).app.parameters.read({ schema: $macros.__Struct_schema(false, MyParams, ) }))); $helpers.assert($helpers.eq(myParams.houses.length, 2), "myParams.houses.length == 2"); From 83be5fc384f22255387d9b60e7a5845f939ca2f2 Mon Sep 17 00:00:00 2001 From: Chris Rybicki Date: Wed, 2 Oct 2024 12:42:56 -0400 Subject: [PATCH 5/8] handle docstrings --- packages/@winglang/wingc/src/docs.rs | 46 ++++++++++++++++++- packages/@winglang/wingc/src/jsify.rs | 2 +- .../wingc/src/json_schema_generator.rs | 22 ++++----- tests/valid/struct_from_json.test.w | 6 ++- 4 files changed, 58 insertions(+), 18 deletions(-) diff --git a/packages/@winglang/wingc/src/docs.rs b/packages/@winglang/wingc/src/docs.rs index 960b0c34187..946d35e2e90 100644 --- a/packages/@winglang/wingc/src/docs.rs +++ b/packages/@winglang/wingc/src/docs.rs @@ -6,7 +6,7 @@ use regex::Regex; use crate::{ ast::{AccessModifier, Phase}, closure_transform::CLOSURE_CLASS_PREFIX, - jsify::codemaker::CodeMaker, + jsify::{codemaker::CodeMaker, escape_javascript_string}, type_check::{ jsii_importer::is_construct_base, symbol_env::SymbolEnvKind, Class, ClassLike, Enum, FunctionSignature, Interface, Namespace, Struct, SymbolKind, Type, TypeRef, VariableInfo, VariableKind, CLASS_INFLIGHT_INIT_NAME, @@ -47,6 +47,50 @@ impl Docs { markdown.to_string().trim().to_string() } + pub fn to_escaped_string(&self) -> String { + let mut contents = String::new(); + if let Some(summary) = &self.summary { + contents.push_str(summary); + } + if let Some(remarks) = &self.remarks { + contents.push_str("\n\n"); + contents.push_str(remarks); + } + if let Some(example) = &self.example { + contents.push_str("\n@example "); + contents.push_str(example); + } + if let Some(returns) = &self.returns { + contents.push_str("\n@returns "); + contents.push_str(returns); + } + if let Some(deprecated) = &self.deprecated { + contents.push_str("\n@deprecated "); + contents.push_str(deprecated); + } + if let Some(see) = &self.see { + contents.push_str("\n@see "); + contents.push_str(see); + } + if let Some(default) = &self.default { + contents.push_str("\n@default "); + contents.push_str(default); + } + if let Some(stability) = &self.stability { + contents.push_str("\n@stability "); + contents.push_str(stability); + } + if let Some(_) = &self.subclassable { + contents.push_str("\n@subclassable"); + } + for (k, v) in self.custom.iter() { + contents.push_str(&format!("\n@{} ", k)); + contents.push_str(v); + } + + escape_javascript_string(&contents) + } + pub(crate) fn with_summary(summary: &str) -> Docs { Docs { summary: Some(summary.to_string()), diff --git a/packages/@winglang/wingc/src/jsify.rs b/packages/@winglang/wingc/src/jsify.rs index dc2959baf19..53a924bbf2a 100644 --- a/packages/@winglang/wingc/src/jsify.rs +++ b/packages/@winglang/wingc/src/jsify.rs @@ -2704,7 +2704,7 @@ fn lookup_span(span: &WingSpan, files: &Files) -> String { result } -fn escape_javascript_string(s: &str) -> String { +pub fn escape_javascript_string(s: &str) -> String { let mut result = String::new(); // escape all escapable characters -- see the section "Escape sequences" in diff --git a/packages/@winglang/wingc/src/json_schema_generator.rs b/packages/@winglang/wingc/src/json_schema_generator.rs index 8267644b355..1efcf86cf89 100644 --- a/packages/@winglang/wingc/src/json_schema_generator.rs +++ b/packages/@winglang/wingc/src/json_schema_generator.rs @@ -45,7 +45,7 @@ impl JsonSchemaGenerator { Some(docs) => format!( "{{type:\"{}\",description:\"{}\"}}", jsified_type, - docs.summary.unwrap_or_default() + docs.to_escaped_string() ), None => format!("{{type:\"{}\"}}", jsified_type), } @@ -59,7 +59,7 @@ impl JsonSchemaGenerator { code.append("},"); code.append(self.get_struct_schema_required_fields(&s.env)); let docs = docs.unwrap_or(s.docs.clone()); - code.append(format!(",description:\"{}\"", docs.summary.unwrap_or_default())); + code.append(format!(",description:\"{}\"", docs.to_escaped_string())); code.append("}"); code.to_string() } @@ -76,7 +76,7 @@ impl JsonSchemaGenerator { code.append(format!(",items:{}", self.get_struct_schema_field(t, None))); if let Some(docs) = docs { - code.append(format!(",description:\"{}\"", docs.summary.unwrap_or_default())); + code.append(format!(",description:\"{}\"", docs.to_escaped_string())); } code.append("}"); @@ -93,7 +93,7 @@ impl JsonSchemaGenerator { )); if let Some(docs) = docs { - code.append(format!("description:\"{}\",", docs.summary.unwrap_or_default())); + code.append(format!("description:\"{}\",", docs.to_escaped_string())); } code.append("}"); @@ -103,7 +103,7 @@ impl JsonSchemaGenerator { Type::Json(_) => match docs { Some(docs) => format!( "{{type:[\"object\",\"string\",\"boolean\",\"number\",\"array\"],description:\"{}\"}}", - docs.summary.unwrap_or_default() + docs.to_escaped_string() ), None => "{type:[\"object\",\"string\",\"boolean\",\"number\",\"array\"]}".to_string(), }, @@ -118,14 +118,11 @@ impl JsonSchemaGenerator { format!( "{{type:\"string\",enum:[{}],description:\"{}\"}}", choices, - docs.summary.unwrap_or_default() + docs.to_escaped_string() ) } _ => match docs { - Some(docs) => format!( - "{{type:\"null\",description:\"{}\" }}", - docs.summary.unwrap_or_default() - ), + Some(docs) => format!("{{type:\"null\",description:\"{}\" }}", docs.to_escaped_string()), None => "{type:\"null\"}".to_string(), }, } @@ -147,10 +144,7 @@ impl JsonSchemaGenerator { code.append(self.get_struct_schema_required_fields(&struct_.env)); - code.append(format!( - ",description:\"{}\"", - struct_.docs.summary.as_ref().unwrap_or(&String::new()) - )); + code.append(format!(",description:\"{}\"", struct_.docs.to_escaped_string())); // close schema code.append("}"); diff --git a/tests/valid/struct_from_json.test.w b/tests/valid/struct_from_json.test.w index ce6a77eebfe..e87fff49f16 100644 --- a/tests/valid/struct_from_json.test.w +++ b/tests/valid/struct_from_json.test.w @@ -264,12 +264,14 @@ bring "./subdir/structs_2.w" as otherExternalStructs; enum Color { red, green, blue } /// MyStruct docs +/// @foo bar struct MyStruct { /// m1 docs m1: externalStructs.MyStruct; /// m2 docs m2: otherExternalStructs.MyStruct; /// color docs + /// @example Color.red color: Color; } @@ -299,7 +301,7 @@ let expectedSchema = { "color": { "type": "string", "enum": ["red", "green", "blue"], - "description": "color docs", + "description": "color docs\n@example Color.red", }, "m1": { "type": "object", @@ -315,7 +317,7 @@ let expectedSchema = { }, }, "required": ["color", "m1", "m2"], - "description": "MyStruct docs", + "description": "MyStruct docs\n@foo bar", }; expect.equal(schema.asStr(), Json.stringify(expectedSchema)); From 2c67ab8e345addd986ab87bdd602f0c27f30ad42 Mon Sep 17 00:00:00 2001 From: Chris Rybicki Date: Mon, 7 Oct 2024 19:56:21 -0400 Subject: [PATCH 6/8] add changed files --- docs/api/04-standard-library/std/reflect.md | 11 ++++ docs/by-example/32-testing.md | 4 +- docs/docs/02-concepts/04-tests.md | 2 +- packages/@winglang/sdk/src/std/index.ts | 4 +- .../__snapshots__/bucket.test.ts.snap | 2 +- .../invalid/04-tests.md_example_5/main.w | 2 +- .../invalid/32-testing.md_example_1/main.w | 24 ++++++++ .../valid/09-arrays.md_example_1/main.w | 19 +++++++ .../valid/10-maps.md_example_1/main.w | 23 ++++++++ .../valid/11-sets.md_example_1/main.w | 15 +++++ .../valid/12-structs.md_example_1/main.w | 28 +++++++++ .../valid/13-bytes.md_example_1/main.w | 18 ++++++ .../main.w | 25 ++++++++ .../14-async-functions.md_example_1/main.w | 28 +++++++++ .../valid/14-functions.md_example_1/main.w | 18 ++++++ .../15-variadic-functions.md_example_1/main.w | 17 ++++++ .../valid/16-closures.md_example_1/main.w | 16 ++++++ .../valid/17-recursion.md_example_1/main.w | 11 ++++ .../valid/18-methods.md_example_1/main.w | 50 ++++++++++++++++ .../valid/19-interfaces.md_example_1/main.w | 51 +++++++++++++++++ .../valid/20-sleep.md_example_1/main.w | 27 +++++++++ .../21-string-functions.md_example_1/main.w | 16 ++++++ .../valid/22-regex.md_example_1/main.w | 28 +++++++++ .../valid/23-Json.md_example_1/main.w | 54 ++++++++++++++++++ .../valid/24-time.md_example_1/main.w | 21 +++++++ .../valid/25-random.md_example_1/main.w | 10 ++++ .../26-number-parsing.md_example_1/main.w | 9 +++ .../valid/27-url-parsing.md_example_1/main.w | 20 +++++++ .../valid/28-sha256.md_example_1/main.w | 7 +++ .../29-base64-encoding.md_example_1/main.w | 12 ++++ .../main.w | 22 +++++++ .../valid/31-directories.md_example_1/main.w | 22 +++++++ .../valid/33-http-client.md_example_1/main.w | 25 ++++++++ .../valid/34-http-server.md_example_1/main.w | 57 +++++++++++++++++++ .../35-exec-processes.md_example_1/main.w | 19 +++++++ .../valid/36-reflection.md_example_1/main.w | 45 +++++++++++++++ .../struct_from_json.test.w_compile_tf-aws.md | 6 +- 37 files changed, 758 insertions(+), 10 deletions(-) create mode 100644 docs/api/04-standard-library/std/reflect.md create mode 100644 tests/doc_examples/invalid/32-testing.md_example_1/main.w create mode 100644 tests/doc_examples/valid/09-arrays.md_example_1/main.w create mode 100644 tests/doc_examples/valid/10-maps.md_example_1/main.w create mode 100644 tests/doc_examples/valid/11-sets.md_example_1/main.w create mode 100644 tests/doc_examples/valid/12-structs.md_example_1/main.w create mode 100644 tests/doc_examples/valid/13-bytes.md_example_1/main.w create mode 100644 tests/doc_examples/valid/13-trailing-struct-parameters.md_example_1/main.w create mode 100644 tests/doc_examples/valid/14-async-functions.md_example_1/main.w create mode 100644 tests/doc_examples/valid/14-functions.md_example_1/main.w create mode 100644 tests/doc_examples/valid/15-variadic-functions.md_example_1/main.w create mode 100644 tests/doc_examples/valid/16-closures.md_example_1/main.w create mode 100644 tests/doc_examples/valid/17-recursion.md_example_1/main.w create mode 100644 tests/doc_examples/valid/18-methods.md_example_1/main.w create mode 100644 tests/doc_examples/valid/19-interfaces.md_example_1/main.w create mode 100644 tests/doc_examples/valid/20-sleep.md_example_1/main.w create mode 100644 tests/doc_examples/valid/21-string-functions.md_example_1/main.w create mode 100644 tests/doc_examples/valid/22-regex.md_example_1/main.w create mode 100644 tests/doc_examples/valid/23-Json.md_example_1/main.w create mode 100644 tests/doc_examples/valid/24-time.md_example_1/main.w create mode 100644 tests/doc_examples/valid/25-random.md_example_1/main.w create mode 100644 tests/doc_examples/valid/26-number-parsing.md_example_1/main.w create mode 100644 tests/doc_examples/valid/27-url-parsing.md_example_1/main.w create mode 100644 tests/doc_examples/valid/28-sha256.md_example_1/main.w create mode 100644 tests/doc_examples/valid/29-base64-encoding.md_example_1/main.w create mode 100644 tests/doc_examples/valid/30-reading-writing-files.md_example_1/main.w create mode 100644 tests/doc_examples/valid/31-directories.md_example_1/main.w create mode 100644 tests/doc_examples/valid/33-http-client.md_example_1/main.w create mode 100644 tests/doc_examples/valid/34-http-server.md_example_1/main.w create mode 100644 tests/doc_examples/valid/35-exec-processes.md_example_1/main.w create mode 100644 tests/doc_examples/valid/36-reflection.md_example_1/main.w diff --git a/docs/api/04-standard-library/std/reflect.md b/docs/api/04-standard-library/std/reflect.md new file mode 100644 index 00000000000..c7d3ce7c5eb --- /dev/null +++ b/docs/api/04-standard-library/std/reflect.md @@ -0,0 +1,11 @@ +--- +title: reflect +id: reflect +--- + +# API Reference + + + + + diff --git a/docs/by-example/32-testing.md b/docs/by-example/32-testing.md index 7274e2f1397..cc49afd08f2 100644 --- a/docs/by-example/32-testing.md +++ b/docs/by-example/32-testing.md @@ -10,7 +10,7 @@ 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" +```js playground example{valid: false} title="main.w" bring math; bring cloud; let b = new cloud.Bucket(); @@ -31,7 +31,7 @@ test "bucket starts empty" { } test "this test fails" { - throw("test throws an exception fails"); + throw "test throws an exception fails"; } ``` diff --git a/docs/docs/02-concepts/04-tests.md b/docs/docs/02-concepts/04-tests.md index 7fb091a6be0..cc901ffcb6e 100644 --- a/docs/docs/02-concepts/04-tests.md +++ b/docs/docs/02-concepts/04-tests.md @@ -158,7 +158,7 @@ test "bucket starts empty" { } test "this test should fail" { - throw("test throws an exception fails"); + throw "test throws an exception fails"; } ``` diff --git a/packages/@winglang/sdk/src/std/index.ts b/packages/@winglang/sdk/src/std/index.ts index 07e641004f2..aab781d6b57 100644 --- a/packages/@winglang/sdk/src/std/index.ts +++ b/packages/@winglang/sdk/src/std/index.ts @@ -9,12 +9,12 @@ export * from "./json_schema"; export * from "./map"; export * from "./node"; export * from "./number"; +export * as reflect from "./reflect"; export * from "./regex"; export * from "./resource"; export * from "./set"; export * from "./string"; export * from "./struct"; export * from "./test"; -export * from "./test-runner"; -export * as reflect from "./reflect"; +export * from "./test-runner"; diff --git a/packages/@winglang/sdk/test/target-sim/__snapshots__/bucket.test.ts.snap b/packages/@winglang/sdk/test/target-sim/__snapshots__/bucket.test.ts.snap index cf6f4dbd626..78d62a97938 100644 --- a/packages/@winglang/sdk/test/target-sim/__snapshots__/bucket.test.ts.snap +++ b/packages/@winglang/sdk/test/target-sim/__snapshots__/bucket.test.ts.snap @@ -863,8 +863,8 @@ exports[`update an object in bucket 1`] = ` "InvokeAsync (payload="1.txt").", "Publish (messages=1.txt).", "Put (key=1.txt).", - "Put (key=1.txt).", "I am done", + "Put (key=1.txt).", "root/my_bucket/Policy stopped", "Closing server on http://127.0.0.1:", "root/my_bucket stopped", diff --git a/tests/doc_examples/invalid/04-tests.md_example_5/main.w b/tests/doc_examples/invalid/04-tests.md_example_5/main.w index b0da4713678..a14a4e4601a 100644 --- a/tests/doc_examples/invalid/04-tests.md_example_5/main.w +++ b/tests/doc_examples/invalid/04-tests.md_example_5/main.w @@ -17,5 +17,5 @@ test "bucket starts empty" { } test "this test should fail" { - throw("test throws an exception fails"); + throw "test throws an exception fails"; } diff --git a/tests/doc_examples/invalid/32-testing.md_example_1/main.w b/tests/doc_examples/invalid/32-testing.md_example_1/main.w new file mode 100644 index 00000000000..bb69d5beba2 --- /dev/null +++ b/tests/doc_examples/invalid/32-testing.md_example_1/main.w @@ -0,0 +1,24 @@ +// This file was auto generated from an example found in: 32-testing.md_example_1 +// Example metadata: {"valid":false} +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"; +} diff --git a/tests/doc_examples/valid/09-arrays.md_example_1/main.w b/tests/doc_examples/valid/09-arrays.md_example_1/main.w new file mode 100644 index 00000000000..7229234308d --- /dev/null +++ b/tests/doc_examples/valid/09-arrays.md_example_1/main.w @@ -0,0 +1,19 @@ +// This file was auto generated from an example found in: 09-arrays.md_example_1 +// Example metadata: {"valid":true} +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); + } +} diff --git a/tests/doc_examples/valid/10-maps.md_example_1/main.w b/tests/doc_examples/valid/10-maps.md_example_1/main.w new file mode 100644 index 00000000000..f5b2f768b51 --- /dev/null +++ b/tests/doc_examples/valid/10-maps.md_example_1/main.w @@ -0,0 +1,23 @@ +// This file was auto generated from an example found in: 10-maps.md_example_1 +// Example metadata: {"valid":true} +// 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"))); diff --git a/tests/doc_examples/valid/11-sets.md_example_1/main.w b/tests/doc_examples/valid/11-sets.md_example_1/main.w new file mode 100644 index 00000000000..53dd4d9876e --- /dev/null +++ b/tests/doc_examples/valid/11-sets.md_example_1/main.w @@ -0,0 +1,15 @@ +// This file was auto generated from an example found in: 11-sets.md_example_1 +// Example metadata: {"valid":true} +// 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())); diff --git a/tests/doc_examples/valid/12-structs.md_example_1/main.w b/tests/doc_examples/valid/12-structs.md_example_1/main.w new file mode 100644 index 00000000000..b158780d0de --- /dev/null +++ b/tests/doc_examples/valid/12-structs.md_example_1/main.w @@ -0,0 +1,28 @@ +// This file was auto generated from an example found in: 12-structs.md_example_1 +// Example metadata: {"valid":true} +// 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); diff --git a/tests/doc_examples/valid/13-bytes.md_example_1/main.w b/tests/doc_examples/valid/13-bytes.md_example_1/main.w new file mode 100644 index 00000000000..491f5a89690 --- /dev/null +++ b/tests/doc_examples/valid/13-bytes.md_example_1/main.w @@ -0,0 +1,18 @@ +// This file was auto generated from an example found in: 13-bytes.md_example_1 +// Example metadata: {"valid":true} +// 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)); diff --git a/tests/doc_examples/valid/13-trailing-struct-parameters.md_example_1/main.w b/tests/doc_examples/valid/13-trailing-struct-parameters.md_example_1/main.w new file mode 100644 index 00000000000..59dcc112481 --- /dev/null +++ b/tests/doc_examples/valid/13-trailing-struct-parameters.md_example_1/main.w @@ -0,0 +1,25 @@ +// This file was auto generated from an example found in: 13-trailing-struct-parameters.md_example_1 +// Example metadata: {"valid":true} +// 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); + diff --git a/tests/doc_examples/valid/14-async-functions.md_example_1/main.w b/tests/doc_examples/valid/14-async-functions.md_example_1/main.w new file mode 100644 index 00000000000..ad566f484dd --- /dev/null +++ b/tests/doc_examples/valid/14-async-functions.md_example_1/main.w @@ -0,0 +1,28 @@ +// This file was auto generated from an example found in: 14-async-functions.md_example_1 +// Example metadata: {"valid":true} +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"; diff --git a/tests/doc_examples/valid/14-functions.md_example_1/main.w b/tests/doc_examples/valid/14-functions.md_example_1/main.w new file mode 100644 index 00000000000..eef40b0312d --- /dev/null +++ b/tests/doc_examples/valid/14-functions.md_example_1/main.w @@ -0,0 +1,18 @@ +// This file was auto generated from an example found in: 14-functions.md_example_1 +// Example metadata: {"valid":true} +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); diff --git a/tests/doc_examples/valid/15-variadic-functions.md_example_1/main.w b/tests/doc_examples/valid/15-variadic-functions.md_example_1/main.w new file mode 100644 index 00000000000..494d86a6635 --- /dev/null +++ b/tests/doc_examples/valid/15-variadic-functions.md_example_1/main.w @@ -0,0 +1,17 @@ +// This file was auto generated from an example found in: 15-variadic-functions.md_example_1 +// Example metadata: {"valid":true} +// 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)); diff --git a/tests/doc_examples/valid/16-closures.md_example_1/main.w b/tests/doc_examples/valid/16-closures.md_example_1/main.w new file mode 100644 index 00000000000..22e74f05893 --- /dev/null +++ b/tests/doc_examples/valid/16-closures.md_example_1/main.w @@ -0,0 +1,16 @@ +// This file was auto generated from an example found in: 16-closures.md_example_1 +// Example metadata: {"valid":true} +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()); diff --git a/tests/doc_examples/valid/17-recursion.md_example_1/main.w b/tests/doc_examples/valid/17-recursion.md_example_1/main.w new file mode 100644 index 00000000000..540f9cf5f77 --- /dev/null +++ b/tests/doc_examples/valid/17-recursion.md_example_1/main.w @@ -0,0 +1,11 @@ +// This file was auto generated from an example found in: 17-recursion.md_example_1 +// Example metadata: {"valid":true} +let fact = (n: num): num => { + if n == 0 { + return 1; + } + return n * fact(n - 1); +}; + + +log(fact(7)); diff --git a/tests/doc_examples/valid/18-methods.md_example_1/main.w b/tests/doc_examples/valid/18-methods.md_example_1/main.w new file mode 100644 index 00000000000..da766937b48 --- /dev/null +++ b/tests/doc_examples/valid/18-methods.md_example_1/main.w @@ -0,0 +1,50 @@ +// This file was auto generated from an example found in: 18-methods.md_example_1 +// Example metadata: {"valid":true} +// 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()); + diff --git a/tests/doc_examples/valid/19-interfaces.md_example_1/main.w b/tests/doc_examples/valid/19-interfaces.md_example_1/main.w new file mode 100644 index 00000000000..e93d9dcd79f --- /dev/null +++ b/tests/doc_examples/valid/19-interfaces.md_example_1/main.w @@ -0,0 +1,51 @@ +// This file was auto generated from an example found in: 19-interfaces.md_example_1 +// Example metadata: {"valid":true} +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()); diff --git a/tests/doc_examples/valid/20-sleep.md_example_1/main.w b/tests/doc_examples/valid/20-sleep.md_example_1/main.w new file mode 100644 index 00000000000..17072426e04 --- /dev/null +++ b/tests/doc_examples/valid/20-sleep.md_example_1/main.w @@ -0,0 +1,27 @@ +// This file was auto generated from an example found in: 20-sleep.md_example_1 +// Example metadata: {"valid":true} +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(); +}); + diff --git a/tests/doc_examples/valid/21-string-functions.md_example_1/main.w b/tests/doc_examples/valid/21-string-functions.md_example_1/main.w new file mode 100644 index 00000000000..3b7f205d7f1 --- /dev/null +++ b/tests/doc_examples/valid/21-string-functions.md_example_1/main.w @@ -0,0 +1,16 @@ +// This file was auto generated from an example found in: 21-string-functions.md_example_1 +// Example metadata: {"valid":true} +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()); diff --git a/tests/doc_examples/valid/22-regex.md_example_1/main.w b/tests/doc_examples/valid/22-regex.md_example_1/main.w new file mode 100644 index 00000000000..6dc17c82c32 --- /dev/null +++ b/tests/doc_examples/valid/22-regex.md_example_1/main.w @@ -0,0 +1,28 @@ +// This file was auto generated from an example found in: 22-regex.md_example_1 +// Example metadata: {"valid":true} + +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", "")); diff --git a/tests/doc_examples/valid/23-Json.md_example_1/main.w b/tests/doc_examples/valid/23-Json.md_example_1/main.w new file mode 100644 index 00000000000..3bc8941ed85 --- /dev/null +++ b/tests/doc_examples/valid/23-Json.md_example_1/main.w @@ -0,0 +1,54 @@ +// This file was auto generated from an example found in: 23-Json.md_example_1 +// Example metadata: {"valid":true} +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)); diff --git a/tests/doc_examples/valid/24-time.md_example_1/main.w b/tests/doc_examples/valid/24-time.md_example_1/main.w new file mode 100644 index 00000000000..dd83d67cc44 --- /dev/null +++ b/tests/doc_examples/valid/24-time.md_example_1/main.w @@ -0,0 +1,21 @@ +// This file was auto generated from an example found in: 24-time.md_example_1 +// Example metadata: {"valid":true} +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); diff --git a/tests/doc_examples/valid/25-random.md_example_1/main.w b/tests/doc_examples/valid/25-random.md_example_1/main.w new file mode 100644 index 00000000000..c9fd8b23691 --- /dev/null +++ b/tests/doc_examples/valid/25-random.md_example_1/main.w @@ -0,0 +1,10 @@ +// This file was auto generated from an example found in: 25-random.md_example_1 +// Example metadata: {"valid":true} +bring math; + +log(math.random(100)); + +log(math.ceil(math.random(100))); + +log((math.random()*5)+5); + diff --git a/tests/doc_examples/valid/26-number-parsing.md_example_1/main.w b/tests/doc_examples/valid/26-number-parsing.md_example_1/main.w new file mode 100644 index 00000000000..e49f0f1a9be --- /dev/null +++ b/tests/doc_examples/valid/26-number-parsing.md_example_1/main.w @@ -0,0 +1,9 @@ +// This file was auto generated from an example found in: 26-number-parsing.md_example_1 +// Example metadata: {"valid":true} +let j = Json { a: 100 }; + +let x: num = num.fromStr("1"); +let y: num = num.fromJson(j.get("a")); + +log(x); +log(y); diff --git a/tests/doc_examples/valid/27-url-parsing.md_example_1/main.w b/tests/doc_examples/valid/27-url-parsing.md_example_1/main.w new file mode 100644 index 00000000000..20e69928c86 --- /dev/null +++ b/tests/doc_examples/valid/27-url-parsing.md_example_1/main.w @@ -0,0 +1,20 @@ +// This file was auto generated from an example found in: 27-url-parsing.md_example_1 +// Example metadata: {"valid":true} +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); + +}); diff --git a/tests/doc_examples/valid/28-sha256.md_example_1/main.w b/tests/doc_examples/valid/28-sha256.md_example_1/main.w new file mode 100644 index 00000000000..394a5440e45 --- /dev/null +++ b/tests/doc_examples/valid/28-sha256.md_example_1/main.w @@ -0,0 +1,7 @@ +// This file was auto generated from an example found in: 28-sha256.md_example_1 +// Example metadata: {"valid":true} +bring util; + +let value = util.sha256("sha256 this string"); + +log(value); diff --git a/tests/doc_examples/valid/29-base64-encoding.md_example_1/main.w b/tests/doc_examples/valid/29-base64-encoding.md_example_1/main.w new file mode 100644 index 00000000000..92c15bfebc2 --- /dev/null +++ b/tests/doc_examples/valid/29-base64-encoding.md_example_1/main.w @@ -0,0 +1,12 @@ +// This file was auto generated from an example found in: 29-base64-encoding.md_example_1 +// Example metadata: {"valid":true} +bring util; + +let data = "abc123!?$*&()'-=@~"; + +let encoded = util.base64Encode(data); +log(encoded); + + +let decoded = util.base64Decode(encoded); +log(decoded); diff --git a/tests/doc_examples/valid/30-reading-writing-files.md_example_1/main.w b/tests/doc_examples/valid/30-reading-writing-files.md_example_1/main.w new file mode 100644 index 00000000000..050698ec6c1 --- /dev/null +++ b/tests/doc_examples/valid/30-reading-writing-files.md_example_1/main.w @@ -0,0 +1,22 @@ +// This file was auto generated from an example found in: 30-reading-writing-files.md_example_1 +// Example metadata: {"valid":true} +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); diff --git a/tests/doc_examples/valid/31-directories.md_example_1/main.w b/tests/doc_examples/valid/31-directories.md_example_1/main.w new file mode 100644 index 00000000000..d797907d117 --- /dev/null +++ b/tests/doc_examples/valid/31-directories.md_example_1/main.w @@ -0,0 +1,22 @@ +// This file was auto generated from an example found in: 31-directories.md_example_1 +// Example metadata: {"valid":true} +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"); diff --git a/tests/doc_examples/valid/33-http-client.md_example_1/main.w b/tests/doc_examples/valid/33-http-client.md_example_1/main.w new file mode 100644 index 00000000000..ed231e511a1 --- /dev/null +++ b/tests/doc_examples/valid/33-http-client.md_example_1/main.w @@ -0,0 +1,25 @@ +// This file was auto generated from an example found in: 33-http-client.md_example_1 +// Example metadata: {"valid":true} +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); +}); diff --git a/tests/doc_examples/valid/34-http-server.md_example_1/main.w b/tests/doc_examples/valid/34-http-server.md_example_1/main.w new file mode 100644 index 00000000000..cbcba21b02d --- /dev/null +++ b/tests/doc_examples/valid/34-http-server.md_example_1/main.w @@ -0,0 +1,57 @@ +// This file was auto generated from an example found in: 34-http-server.md_example_1 +// Example metadata: {"valid":true} +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/tests/doc_examples/valid/35-exec-processes.md_example_1/main.w b/tests/doc_examples/valid/35-exec-processes.md_example_1/main.w new file mode 100644 index 00000000000..9325079e83d --- /dev/null +++ b/tests/doc_examples/valid/35-exec-processes.md_example_1/main.w @@ -0,0 +1,19 @@ +// This file was auto generated from an example found in: 35-exec-processes.md_example_1 +// Example metadata: {"valid":true} +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); diff --git a/tests/doc_examples/valid/36-reflection.md_example_1/main.w b/tests/doc_examples/valid/36-reflection.md_example_1/main.w new file mode 100644 index 00000000000..3e6ba73ec9e --- /dev/null +++ b/tests/doc_examples/valid/36-reflection.md_example_1/main.w @@ -0,0 +1,45 @@ +// This file was auto generated from an example found in: 36-reflection.md_example_1 +// Example metadata: {"valid":true} +let generateJsonSchema = (structType: std.reflect.Type): str => { + if let st = structType.asStruct() { + let schema = MutJson { + type: "object", + properties: {}, + required: [] + }; + + for name in st.fields.keys() { + let fieldSchema = MutJson {}; + let var field = st.fields[name].child; + let var required = true; + if let opt = field.asOptional() { + required = false; + field = opt.child; + } + + if field.kind == "str" { + fieldSchema["type"] = "string"; + } else if field.kind == "num" { + fieldSchema["type"] = "number"; + } // ...handle other types + + schema["properties"][name] = fieldSchema; + if required { + // TODO: https://github.com/winglang/wing/issues/6929 + unsafeCast(schema["required"])?.push(name); + } + } + + return Json.stringify(schema); + } + + throw "input must be a struct type"; +}; + +struct User { + name: str; + age: num; + email: str?; +} + +log(generateJsonSchema(@type(User))); diff --git a/tools/hangar/__snapshots__/test_corpus/valid/struct_from_json.test.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/valid/struct_from_json.test.w_compile_tf-aws.md index 8ade7d124c3..cb28daf530a 100644 --- a/tools/hangar/__snapshots__/test_corpus/valid/struct_from_json.test.w_compile_tf-aws.md +++ b/tools/hangar/__snapshots__/test_corpus/valid/struct_from_json.test.w_compile_tf-aws.md @@ -200,9 +200,9 @@ class $Root extends $stdlib.std.Resource { const Bar = $stdlib.std.Struct._createJsonSchema({$id:"/Bar",type:"object",properties:{b:{type:"number"},f:{type:"string"},},required:["b","f",],description:""}); const Foo = $stdlib.std.Struct._createJsonSchema({$id:"/Foo",type:"object",properties:{f:{type:"string"},},required:["f",],description:""}); const Foosible = $stdlib.std.Struct._createJsonSchema({$id:"/Foosible",type:"object",properties:{f:{type:"string"},},required:[],description:""}); - const MyStruct = $stdlib.std.Struct._createJsonSchema({$id:"/MyStruct",type:"object",properties:{color:{type:"string",enum:["red", "green", "blue"],description:"color docs"},m1:{type:"object",properties:{val:{type:"number",description:"val docs"},},required:["val",],description:"m1 docs"},m2:{type:"object",properties:{val:{type:"string"},},required:["val",],description:"m2 docs"},},required:["color","m1","m2",],description:"MyStruct docs"}); + const MyStruct = $stdlib.std.Struct._createJsonSchema({$id:"/MyStruct",type:"object",properties:{color:{type:"string",enum:["red", "green", "blue"],description:"color docs\n@example Color.red"},m1:{type:"object",properties:{val:{type:"number",description:"val docs"},},required:["val",],description:"m1 docs"},m2:{type:"object",properties:{val:{type:"string"},},required:["val",],description:"m2 docs"},},required:["color","m1","m2",],description:"MyStruct docs\n@foo bar"}); const Student = $stdlib.std.Struct._createJsonSchema({$id:"/Student",type:"object",properties:{additionalData:{type:["object","string","boolean","number","array"]},advisor:{type:"object",properties:{dob:{type:"object",properties:{day:{type:"number"},month:{type:"number"},year:{type:"number"},},required:["day","month","year",],description:""},employeeID:{type:"string"},firstName:{type:"string"},lastName:{type:"string"},},required:["dob","employeeID","firstName","lastName",],description:""},coursesTaken:{type:"array",items:{type:"object",properties:{course:{type:"object",properties:{credits:{type:"number"},name:{type:"string"},},required:["credits","name",],description:""},dateTaken:{type:"object",properties:{day:{type:"number"},month:{type:"number"},year:{type:"number"},},required:["day","month","year",],description:""},grade:{type:"string"},},required:["course","dateTaken","grade",],description:""}},dob:{type:"object",properties:{day:{type:"number"},month:{type:"number"},year:{type:"number"},},required:["day","month","year",],description:""},enrolled:{type:"boolean"},enrolledCourses:{type:"array",uniqueItems:true,items:{type:"object",properties:{credits:{type:"number"},name:{type:"string"},},required:["credits","name",],description:""}},firstName:{type:"string"},lastName:{type:"string"},schoolId:{type:"string"},},required:["dob","enrolled","firstName","lastName","schoolId",],description:""}); - const cloud_CounterProps = $stdlib.std.Struct._createJsonSchema({$id:"/CounterProps",type:"object",properties:{initial:{type:"number",description:"The initial value of the counter."},},required:[],description:"Options for `Counter`."}); + const cloud_CounterProps = $stdlib.std.Struct._createJsonSchema({$id:"/CounterProps",type:"object",properties:{initial:{type:"number",description:"The initial value of the counter.\n@default 0\n@stability experimental"},},required:[],description:"Options for `Counter`.\n@stability experimental"}); const externalStructs_MyOtherStruct = $stdlib.std.Struct._createJsonSchema({$id:"/MyOtherStruct",type:"object",properties:{data:{type:"object",properties:{val:{type:"number",description:"val docs"},},required:["val",],description:"MyStruct docs in subdir"},},required:["data",],description:""}); $helpers.nodeof(this).root.$preflightTypesMap = $preflightTypesMap; const Color = @@ -478,7 +478,7 @@ class $Root extends $stdlib.std.Resource { (expect.Util.equal(myStruct.color, Color.red)); const schema = $macros.__Struct_schema(false, MyStruct, ); (schema.validate(jMyStruct)); - const expectedSchema = ({"$id": "/MyStruct", "type": "object", "properties": ({"color": ({"type": "string", "enum": ["red", "green", "blue"], "description": "color docs"}), "m1": ({"type": "object", "properties": ({"val": ({"type": "number", "description": "val docs"})}), "required": ["val"], "description": "m1 docs"}), "m2": ({"type": "object", "properties": ({"val": ({"type": "string"})}), "required": ["val"], "description": "m2 docs"})}), "required": ["color", "m1", "m2"], "description": "MyStruct docs"}); + const expectedSchema = ({"$id": "/MyStruct", "type": "object", "properties": ({"color": ({"type": "string", "enum": ["red", "green", "blue"], "description": "color docs\n@example Color.red"}), "m1": ({"type": "object", "properties": ({"val": ({"type": "number", "description": "val docs"})}), "required": ["val"], "description": "m1 docs"}), "m2": ({"type": "object", "properties": ({"val": ({"type": "string"})}), "required": ["val"], "description": "m2 docs"})}), "required": ["color", "m1", "m2"], "description": "MyStruct docs\n@foo bar"}); (expect.Util.equal((schema.asStr()), $macros.__Json_stringify(false, std.Json, expectedSchema))); globalThis.$ClassFactory.new("@winglang/sdk.std.Test", std.Test, this, "test:inflight schema usage", new $Closure4(this, "$Closure4")); (std.String.fromJson(10, { unsafe: true })); From e318e1a971e0505689df36659c6730e9888d7549 Mon Sep 17 00:00:00 2001 From: Chris Rybicki Date: Mon, 7 Oct 2024 19:58:41 -0400 Subject: [PATCH 7/8] remove flakey test snapshot --- .../__snapshots__/bucket.test.ts.snap | 25 ------------------- .../sdk/test/target-sim/bucket.test.ts | 1 - 2 files changed, 26 deletions(-) diff --git a/packages/@winglang/sdk/test/target-sim/__snapshots__/bucket.test.ts.snap b/packages/@winglang/sdk/test/target-sim/__snapshots__/bucket.test.ts.snap index 78d62a97938..8a05d5d51cb 100644 --- a/packages/@winglang/sdk/test/target-sim/__snapshots__/bucket.test.ts.snap +++ b/packages/@winglang/sdk/test/target-sim/__snapshots__/bucket.test.ts.snap @@ -849,28 +849,3 @@ exports[`removing a key will call onDelete method 1`] = ` "root/my_bucket/OnDelete/OnMessage0 stopped", ] `; - -exports[`update an object in bucket 1`] = ` -[ - "root/my_bucket/OnCreate started", - "Server listening on http://127.0.0.1:", - "root/my_bucket started", - "root/my_bucket/Policy started", - "root/my_bucket/OnCreate/OnMessage0 started", - "root/my_bucket/OnCreate/Policy started", - "root/my_bucket/OnCreate/TopicEventMapping0 started", - "Sending message (message=1.txt, subscriber=sim-3).", - "InvokeAsync (payload="1.txt").", - "Publish (messages=1.txt).", - "Put (key=1.txt).", - "I am done", - "Put (key=1.txt).", - "root/my_bucket/Policy stopped", - "Closing server on http://127.0.0.1:", - "root/my_bucket stopped", - "root/my_bucket/OnCreate/Policy stopped", - "root/my_bucket/OnCreate/TopicEventMapping0 stopped", - "root/my_bucket/OnCreate stopped", - "root/my_bucket/OnCreate/OnMessage0 stopped", -] -`; diff --git a/packages/@winglang/sdk/test/target-sim/bucket.test.ts b/packages/@winglang/sdk/test/target-sim/bucket.test.ts index eadde50a276..da26a80c682 100644 --- a/packages/@winglang/sdk/test/target-sim/bucket.test.ts +++ b/packages/@winglang/sdk/test/target-sim/bucket.test.ts @@ -57,7 +57,6 @@ test("update an object in bucket", async () => { // THEN await s.stop(); - expect(listMessages(s)).toMatchSnapshot(); // The bucket notification topic should only publish one message, since the // second put() call counts as an update, not a create. expect(listMessages(s).filter((m) => m.includes(`Publish`))).toHaveLength(1); From d8c6b3c5a18b2008655e302f1b511729ba80d56d Mon Sep 17 00:00:00 2001 From: Chris Rybicki Date: Mon, 7 Oct 2024 20:04:42 -0400 Subject: [PATCH 8/8] patch docgen script temporarily --- docs/api/04-standard-library/std/reflect.md | 11 ----------- packages/@winglang/sdk/scripts/docgen.mts | 5 ++++- 2 files changed, 4 insertions(+), 12 deletions(-) delete mode 100644 docs/api/04-standard-library/std/reflect.md diff --git a/docs/api/04-standard-library/std/reflect.md b/docs/api/04-standard-library/std/reflect.md deleted file mode 100644 index c7d3ce7c5eb..00000000000 --- a/docs/api/04-standard-library/std/reflect.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: reflect -id: reflect ---- - -# API Reference - - - - - diff --git a/packages/@winglang/sdk/scripts/docgen.mts b/packages/@winglang/sdk/scripts/docgen.mts index f84f3ef278a..9b4a461f72d 100644 --- a/packages/@winglang/sdk/scripts/docgen.mts +++ b/packages/@winglang/sdk/scripts/docgen.mts @@ -1,4 +1,4 @@ -import { readdir, writeFile, readFile } from "node:fs/promises"; +import { readdir, writeFile, readFile, rm } from "node:fs/promises"; import { join } from "node:path"; import { fileURLToPath } from "node:url"; import { Language, Documentation } from "@winglang/jsii-docgen"; @@ -184,6 +184,9 @@ await generateResourceApiDocs("target-sim", { jsiiModule: "sim", }); +// TODO: this file isn't generated correctly +await rm(getStdlibDocsDir("std/reflect") + ".md"); + console.log( `${ANSI_LINE_CLEAR}${ANSI_LINE_CLEAR}${docCounter} Docs Generated!` );