Skip to content

Commit

Permalink
pull jsify methods into their own file
Browse files Browse the repository at this point in the history
  • Loading branch information
hasanaburayyan committed Sep 2, 2023
1 parent e09740a commit 8b5291f
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 138 deletions.
4 changes: 2 additions & 2 deletions examples/tests/valid/struct_from_json.w
Original file line number Diff line number Diff line change
Expand Up @@ -265,10 +265,10 @@ let jMyStruct = {
val: 10
},
m2: {
data: "10"
val: "10"
}
};

let myStruct = MyStruct.fromJson(jMyStruct);
assert(myStruct.m1.val == 10);
assert(myStruct.m2.data == "10");
assert(myStruct.m2.val == "10");
2 changes: 1 addition & 1 deletion examples/tests/valid/subdir/structs_2.w
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
struct MyStruct {
data: str;
val: str;
}
129 changes: 4 additions & 125 deletions libs/wingc/src/jsify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::{
lifts::{Liftable, Lifts},
resolve_super_method, resolve_user_defined_type,
symbol_env::SymbolEnv,
ClassLike, Struct, Type, TypeRef, Types, UnsafeRef, VariableKind, CLASS_INFLIGHT_INIT_NAME,
ClassLike, Type, TypeRef, Types, VariableKind, CLASS_INFLIGHT_INIT_NAME,
},
visit_context::VisitContext,
MACRO_REPLACE_ARGS, MACRO_REPLACE_ARGS_TEXT, MACRO_REPLACE_SELF, WINGSDK_ASSEMBLY_NAME, WINGSDK_RESOURCE,
Expand Down Expand Up @@ -307,21 +307,21 @@ impl<'a> JSifier<'a> {
}
}

fn jsify_type(&self, typ: &Type, ctx: &mut JSifyContext) -> Option<String> {
pub fn jsify_type(&self, typ: &Type) -> Option<String> {
match typ {
Type::Struct(t) => Some(t.name.name.clone()),
Type::String => Some("string".to_string()),
Type::Number => Some("number".to_string()),
Type::Boolean => Some("boolean".to_string()),
Type::Array(t) => {
if let Some(inner) = self.jsify_type(&t, ctx) {
if let Some(inner) = self.jsify_type(&t) {
Some(format!("{}[]", inner))
} else {
None
}
}
Type::Optional(t) => {
if let Some(inner) = self.jsify_type(&t, ctx) {
if let Some(inner) = self.jsify_type(&t) {
Some(format!("{}?", inner))
} else {
None
Expand Down Expand Up @@ -653,127 +653,6 @@ impl<'a> JSifier<'a> {
}
}

pub fn jsify_struct_env_properties(&self, env: &SymbolEnv, ctx: &mut JSifyContext) -> CodeMaker {
let mut code = CodeMaker::default();
for (field_name, (.., kind)) in env.symbol_map.iter() {
code.line(format!(
"{}: {},",
field_name,
self.jsify_struct_schema_field(&kind.as_variable().unwrap().type_, ctx)
));
}
code
}

pub fn jsify_struct_schema_required_fields(&self, env: &SymbolEnv) -> CodeMaker {
let mut code = CodeMaker::default();
code.open("required: [");
for (field_name, (_stmt_idx, kind)) in env.symbol_map.iter() {
if !matches!(*kind.as_variable().unwrap().type_, Type::Optional(_)) {
code.line(format!("\"{}\",", field_name));
}
}
code.close("]");
code
}

pub fn jsify_struct_schema_field(&self, typ: &UnsafeRef<Type>, ctx: &mut JSifyContext) -> String {
match **typ {
Type::String | Type::Number | Type::Boolean => {
format!("{{ type: \"{}\" }}", self.jsify_type(typ, ctx).unwrap())
}
Type::Struct(ref s) => {
let mut code = CodeMaker::default();
code.open("{");
code.line("type: \"object\",");
code.open("properties: {");
code.add_code(self.jsify_struct_env_properties(&s.env, ctx));
code.close("},");
code.add_code(self.jsify_struct_schema_required_fields(&s.env));
code.close("}");
code.to_string().strip_suffix("\n").unwrap().to_string()
}
Type::Array(ref t) | Type::Set(ref t) => {
let mut code = CodeMaker::default();
code.open("{");

code.line("type: \"array\",");

if matches!(**typ, Type::Set(_)) {
code.line("uniqueItems: true,");
}

code.line(format!("items: {}", self.jsify_struct_schema_field(t, ctx)));

code.close("}");
code.to_string().strip_suffix("\n").unwrap().to_string()
}
Type::Map(ref t) => {
let mut code = CodeMaker::default();
code.open("{");

code.line("type: \"object\",");
code.line(format!(
"patternProperties: {{ \".*\": {} }}",
self.jsify_struct_schema_field(t, ctx)
));

code.close("}");
code.to_string().strip_suffix("\n").unwrap().to_string()
}
Type::Optional(t) => self.jsify_struct_schema_field(&t, ctx),
Type::Json(_) => "{ type: \"object\" }".to_string(),
_ => "{ type: \"null\" }".to_string(),
}
}

pub fn jsify_struct(&self, struct_: &Struct, ctx: &mut JSifyContext) -> CodeMaker {
let mut code = CodeMaker::default();

code.open("module.exports = function(stdStruct) {".to_string());
code.open(format!("class {} {{", struct_.name));

code.open("static jsonSchema() {".to_string());
code.open("return {");

code.line(format!("id: \"/{}\",", struct_.name));
code.line("type: \"object\",".to_string());

code.open("properties: {");

code.add_code(self.jsify_struct_env_properties(&struct_.env, ctx));

//close properties
code.close("},");

code.add_code(self.jsify_struct_schema_required_fields(&struct_.env));

// close return
code.close("}");

// close schema
code.close("}");

// create _validate() function
code.open("static fromJson(obj) {");
code.line("return stdStruct._validate(obj, this.jsonSchema())");
code.close("}");

// create _toInflightType function that just requires the generated struct file
code.open("static _toInflightType(context) {".to_string());
code.line("return `require(\"./${require('path').basename(__filename)}\")(${ context._lift(stdStruct) })`;".to_string());
code.close("}");

// close class
code.close("}");
// close module.exports

code.line(format!("return {};", struct_.name.name));
code.close("};");

code
}

// To avoid a performance penalty when evaluating assignments made in the elif statement,
// it was necessary to nest the if statements.
//
Expand Down
139 changes: 129 additions & 10 deletions libs/wingc/src/struct_schema.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
ast::{Reference, Scope},
jsify::{codemaker::CodeMaker, JSifier, JSifyContext},
type_check::{is_udt_struct_type, resolve_user_defined_type, Struct},
type_check::{is_udt_struct_type, resolve_user_defined_type, Struct, symbol_env::SymbolEnv, Type, UnsafeRef},
visit::{self, Visit},
visit_context::VisitContext,
};
Expand All @@ -20,14 +20,131 @@ impl<'a> StructSchemaVisitor<'a> {
}

fn jsify_struct(&self, struct_: &Struct) -> CodeMaker {
self.jsify.jsify_struct(
struct_,
&mut JSifyContext {
lifts: None,
visit_ctx: &mut VisitContext::new(),
},
)
self.jsify_struct_schema(struct_, self.ctx.current_env().unwrap())
}

fn jsify_struct_schema_required_fields(&self, env: &SymbolEnv) -> CodeMaker {
let mut code = CodeMaker::default();
code.open("required: [");
for (field_name, (_stmt_idx, kind)) in env.symbol_map.iter() {
if !matches!(*kind.as_variable().unwrap().type_, Type::Optional(_)) {
code.line(format!("\"{}\",", field_name));
}
}
code.close("]");
code
}

fn jsify_struct_schema_field(&self, typ: &UnsafeRef<Type>, env: &SymbolEnv) -> String {
match **typ {
Type::String | Type::Number | Type::Boolean => {
format!("{{ type: \"{}\" }}", self.jsify.jsify_type(typ).unwrap())
}
Type::Struct(ref s) => {
let mut code = CodeMaker::default();
code.open("{");
code.line("type: \"object\",");
code.open("properties: {");
code.add_code(self.jsify_struct_env_properties(&s.env));
code.close("},");
code.add_code(self.jsify_struct_schema_required_fields(&s.env));
code.close("}");
code.to_string().strip_suffix("\n").unwrap().to_string()
}
Type::Array(ref t) | Type::Set(ref t) => {
let mut code = CodeMaker::default();
code.open("{");

code.line("type: \"array\",");

if matches!(**typ, Type::Set(_)) {
code.line("uniqueItems: true,");
}

code.line(format!("items: {}", self.jsify_struct_schema_field(t, env)));

code.close("}");
code.to_string().strip_suffix("\n").unwrap().to_string()
}
Type::Map(ref t) => {
let mut code = CodeMaker::default();
code.open("{");

code.line("type: \"object\",");
code.line(format!(
"patternProperties: {{ \".*\": {} }}",
self.jsify_struct_schema_field(t, env)
));

code.close("}");
code.to_string().strip_suffix("\n").unwrap().to_string()
}
Type::Optional(t) => self.jsify_struct_schema_field(&t, env),
Type::Json(_) => "{ type: \"object\" }".to_string(),
_ => "{ type: \"null\" }".to_string(),
}
}

fn jsify_struct_env_properties(&self, env: &SymbolEnv) -> CodeMaker {
let mut code = CodeMaker::default();
for (field_name, (.., kind)) in env.symbol_map.iter() {
code.line(format!(
"{}: {},",
field_name,
self.jsify_struct_schema_field(&kind.as_variable().unwrap().type_, env)
));
}
code
}

fn jsify_struct_schema(&self, struct_: &Struct, env: &SymbolEnv) -> CodeMaker {
let mut code = CodeMaker::default();

code.open("module.exports = function(stdStruct) {".to_string());
code.open(format!("class {} {{", struct_.name));

code.open("static jsonSchema() {".to_string());
code.open("return {");

code.line(format!("id: \"/{}\",", struct_.name));
code.line("type: \"object\",".to_string());

code.open("properties: {");

code.add_code(self.jsify_struct_env_properties(&struct_.env));

//close properties
code.close("},");

code.add_code(self.jsify_struct_schema_required_fields(&struct_.env));

// close return
code.close("}");

// close schema
code.close("}");

// create _validate() function
code.open("static fromJson(obj) {");
code.line("return stdStruct._validate(obj, this.jsonSchema())");
code.close("}");

// create _toInflightType function that just requires the generated struct file
code.open("static _toInflightType(context) {".to_string());
code.line(format!(
"return `require(\"./${{require('path').basename(__filename)}}\")(${{ context._lift(stdStruct) }})`;",
));
code.close("}");

// close class
code.close("}");
// close module.exports

code.line(format!("return {};", struct_.name.name));
code.close("};");

code
}
}

// Looks for any references to a struct type, and emits a struct schema file for it.
Expand All @@ -40,7 +157,9 @@ impl<'a> Visit<'a> for StructSchemaVisitor<'a> {
Reference::TypeMember { type_name, .. } => {
if is_udt_struct_type(type_name, self.ctx.current_env().unwrap()) {
let type_ = resolve_user_defined_type(type_name, self.ctx.current_env().unwrap(), 0);
let struct_code = self.jsify_struct(type_.unwrap().as_struct().unwrap());
let struct_code = self.jsify_struct(
type_.unwrap().as_struct().unwrap()
);
self.jsify.emit_struct_file(
&self.jsify.jsify_user_defined_type(
type_name,
Expand All @@ -66,4 +185,4 @@ impl<'a> Visit<'a> for StructSchemaVisitor<'a> {
visit::visit_scope(self, node);
self.ctx.pop_env();
}
}
}

0 comments on commit 8b5291f

Please sign in to comment.