From 07e2faf6330b582989ef9df76709104a866bafe6 Mon Sep 17 00:00:00 2001 From: Chris Rybicki Date: Fri, 6 Sep 2024 12:26:52 -0400 Subject: [PATCH] feat: `@app` and `@filename` intrinsics (#7078) Co-authored-by: wingbot <109207340+monadabot@users.noreply.github.com> Co-authored-by: monada-bot[bot] Co-authored-by: Elad Ben-Israel --- docs/api/04-standard-library/std/node.md | 8 +- docs/api/05-language-reference.md | 8 +- packages/@winglang/sdk/src/helpers.ts | 7 +- packages/@winglang/sdk/src/std/node.ts | 4 +- packages/@winglang/wingc/src/ast.rs | 14 ++ packages/@winglang/wingc/src/jsify.rs | 43 +++- ...ils_when_referencing_this_from_static.snap | 2 +- packages/@winglang/wingc/src/lib.rs | 2 +- .../completions/call_struct_expansion.snap | 2 +- .../call_struct_expansion_partial.snap | 2 +- .../src/lsp/snapshots/completions/empty.snap | 2 +- .../lsp/snapshots/completions/intrinsics.snap | 18 +- .../completions/intrinsics_partial.snap | 18 +- .../only_show_symbols_in_scope.snap | 2 +- .../struct_arg_expansion_partial.snap | 2 +- .../completions/struct_literal_value.snap | 2 +- .../completions/struct_show_values.snap | 2 +- .../src/lsp/snapshots/hovers/intrinsics.snap | 4 +- packages/@winglang/wingc/src/type_check.rs | 111 ++++++---- .../wingc/src/type_check/jsii_importer.rs | 19 +- packages/@winglibs/testfixture/API.md | 1 + .../@winglibs/testfixture/example-data.txt | 1 + packages/@winglibs/testfixture/store.w | 9 + tests/invalid/intrinsics.test.w | 2 + tests/invalid/parameters.test.w | 4 +- tests/invalid/struct_from_parameter.test.w | 7 +- tests/valid/app.test.w | 18 ++ tests/valid/bring_wing_library.test.w | 3 + tests/valid/external_ts.extern.d.ts | 137 ------------ tests/valid/factory.test.w | 25 +++ .../inflight_closure_as_super_param.test.w | 2 +- tests/valid/intrinsics.test.w | 6 + .../valid/parameters/nested/parameters.test.w | 6 +- .../valid/parameters/simple/parameters.test.w | 6 +- tests/valid/rootid.test.w | 4 +- tests/valid/subdir/bar.w | 5 +- tests/valid/this.test.w | 17 -- tools/hangar/__snapshots__/invalid.ts.snap | 41 ++-- .../valid/app.test.w_compile_tf-aws.md | 53 +++++ .../test_corpus/valid/app.test.w_test_sim.md | 14 ++ ...cal_normalization.test.w_compile_tf-aws.md | 5 +- ...ring_wing_library.test.w_compile_tf-aws.md | 8 + .../valid/factory.test.w_compile_tf-aws.md | 200 ++++++++++++++++++ .../valid/factory.test.w_test_sim.md | 14 ++ .../valid/intrinsics.test.w_compile_tf-aws.md | 14 +- .../parameters.test.w_compile_tf-aws.md | 3 +- .../parameters.test.w_compile_tf-aws.md | 3 +- .../valid/rootid.test.w_compile_tf-aws.md | 2 +- 48 files changed, 598 insertions(+), 284 deletions(-) create mode 100644 packages/@winglibs/testfixture/example-data.txt create mode 100644 tests/valid/app.test.w create mode 100644 tests/valid/factory.test.w delete mode 100644 tests/valid/this.test.w create mode 100644 tools/hangar/__snapshots__/test_corpus/valid/app.test.w_compile_tf-aws.md create mode 100644 tools/hangar/__snapshots__/test_corpus/valid/app.test.w_test_sim.md create mode 100644 tools/hangar/__snapshots__/test_corpus/valid/factory.test.w_compile_tf-aws.md create mode 100644 tools/hangar/__snapshots__/test_corpus/valid/factory.test.w_test_sim.md diff --git a/docs/api/04-standard-library/std/node.md b/docs/api/04-standard-library/std/node.md index f6c4f60df8a..ace22fde784 100644 --- a/docs/api/04-standard-library/std/node.md +++ b/docs/api/04-standard-library/std/node.md @@ -701,10 +701,10 @@ prepended to the unique identifier. | **Name** | **Type** | **Description** | | --- | --- | --- | | node | constructs.Node | The tree node. | -| entrypointDir | str | The directory of the entrypoint of the current program. | +| entrypointDir | str | The directory of the entrypoint of the current Wing application. | | isTestEnvironment | bool | `true` if this is a testing environment. | | parameters | ParameterRegistrar | The application's parameter registrar. | -| workdir | str | The `.wing` directory into which you can emit artifacts during preflight. | +| workdir | str | The `.wing` directory into which you can emit intermediate artifacts during preflight. | --- @@ -728,7 +728,7 @@ entrypointDir: str; - *Type:* str -The directory of the entrypoint of the current program. +The directory of the entrypoint of the current Wing application. --- @@ -764,7 +764,7 @@ workdir: str; - *Type:* str -The `.wing` directory into which you can emit artifacts during preflight. +The `.wing` directory into which you can emit intermediate artifacts during preflight. --- diff --git a/docs/api/05-language-reference.md b/docs/api/05-language-reference.md index a8173163ac4..188ec71181d 100644 --- a/docs/api/05-language-reference.md +++ b/docs/api/05-language-reference.md @@ -591,10 +591,12 @@ the following properties (given an example intrinsic `@x`): | --------------- | ------------------------------------------------------------------------------------------------------------------------- | | `@log()` | logs str | | `@assert()` | checks a condition and _throws_ if evaluated to false | -| `@dirname` | current source directory | +| `@filename` | absolute path of the source file | +| `@dirname` | absolute path of the source file's directory | +| `@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 | -| `@lift()` | explicitly qualify a [lift](/docs/concepts/inflights) of a preflight object | +| `@nodeof()` | obtain the [tree node](/docs/concepts/application-tree) of a preflight object | +| `@lift()` | explicitly qualify a [lift](/docs/concepts/inflights) of a preflight object | > ```TS > @log("Hello {name}"); diff --git a/packages/@winglang/sdk/src/helpers.ts b/packages/@winglang/sdk/src/helpers.ts index 58cb31b4662..12332d23f0d 100644 --- a/packages/@winglang/sdk/src/helpers.ts +++ b/packages/@winglang/sdk/src/helpers.ts @@ -164,11 +164,8 @@ export function createExternRequire(dirname: string) { }; } -export function resolveDirname( - outdir: string, - relativeSourceDir: string -): string { - return normalPath(path.resolve(outdir, relativeSourceDir)); +export function resolve(outdir: string, relativeSourcePath: string): string { + return normalPath(path.resolve(outdir, relativeSourcePath)); } /** diff --git a/packages/@winglang/sdk/src/std/node.ts b/packages/@winglang/sdk/src/std/node.ts index 8c3284d9ae1..d2f3687c43e 100644 --- a/packages/@winglang/sdk/src/std/node.ts +++ b/packages/@winglang/sdk/src/std/node.ts @@ -472,7 +472,7 @@ export interface IApp extends IConstruct { readonly [APP_SYMBOL]: true; /** - * The `.wing` directory into which you can emit artifacts during preflight. + * The `.wing` directory into which you can emit intermediate artifacts during preflight. */ readonly workdir: string; @@ -482,7 +482,7 @@ export interface IApp extends IConstruct { readonly isTestEnvironment: boolean; /** - * The directory of the entrypoint of the current program. + * The directory of the entrypoint of the current Wing application. */ readonly entrypointDir: string; diff --git a/packages/@winglang/wingc/src/ast.rs b/packages/@winglang/wingc/src/ast.rs index fbf876ac81e..305edb71a31 100644 --- a/packages/@winglang/wingc/src/ast.rs +++ b/packages/@winglang/wingc/src/ast.rs @@ -588,6 +588,8 @@ pub enum IntrinsicKind { /// Error state Unknown, Dirname, + Filename, + App, } impl Display for IntrinsicKind { @@ -595,6 +597,8 @@ impl Display for IntrinsicKind { match self { IntrinsicKind::Unknown => write!(f, "@"), IntrinsicKind::Dirname => write!(f, "@dirname"), + IntrinsicKind::Filename => write!(f, "@filename"), + IntrinsicKind::App => write!(f, "@app"), } } } @@ -603,6 +607,8 @@ impl IntrinsicKind { pub fn from_str(s: &str) -> Self { match s { "@dirname" => IntrinsicKind::Dirname, + "@filename" => IntrinsicKind::Filename, + "@app" => IntrinsicKind::App, _ => IntrinsicKind::Unknown, } } @@ -614,6 +620,14 @@ impl IntrinsicKind { Phase::Preflight => true, _ => false, }, + IntrinsicKind::Filename => match phase { + Phase::Preflight => true, + _ => false, + }, + IntrinsicKind::App => match phase { + Phase::Preflight => true, + _ => false, + }, } } } diff --git a/packages/@winglang/wingc/src/jsify.rs b/packages/@winglang/wingc/src/jsify.rs index 6357e33a2f9..7381b3df495 100644 --- a/packages/@winglang/wingc/src/jsify.rs +++ b/packages/@winglang/wingc/src/jsify.rs @@ -683,24 +683,49 @@ impl<'a> JSifier<'a> { // Only happens inflight, so we can assume an error was caught earlier return new_code!(expr_span, ""); }; - let relative_source_path = make_relative_path( - self.out_dir.as_str(), - source_path - .path - .parent() - .expect("source path is file in a directory") - .as_str(), - ); + let source_dir = source_path.path.parent().expect("source path is file in a directory"); + + // Calculate the path of "if I'm at , how do I get to " + // This relative path is what we will write inside the js file, with the motivation that + // the output is more stable across different users' machines than an absolute path. + let relative_source_path = make_relative_path(self.out_dir.as_str(), source_dir.as_str()); + + // At runtime, $helpers.resolve will normalize the path for Windows or Unix, and then convert it to an absolute path new_code!( expr_span, HELPERS_VAR, - ".resolveDirname(", + ".resolve(", __DIRNAME, ", \"", relative_source_path, "\")" ) } + IntrinsicKind::Filename => { + let Some(source_path) = ctx.source_file else { + // Only happens inflight, so we can assume an error was caught earlier + return new_code!(expr_span, ""); + }; + + // Calculate the path of "if I'm at , how do I get to " + // This relative path is what we will write inside the js file, with the motivation that + // the output is more stable across different users' machines than an absolute path. + let relative_source_path = make_relative_path(self.out_dir.as_str(), source_path.path.as_str()); + + // At runtime, $helpers.resolve will normalize the path for Windows or Unix, and then convert it to an absolute path + new_code!( + expr_span, + HELPERS_VAR, + ".resolve(", + __DIRNAME, + ", \"", + relative_source_path, + "\")" + ) + } + IntrinsicKind::App => { + new_code!(expr_span, HELPERS_VAR, ".nodeof(this).app") + } }, ExprKind::Call { callee, arg_list } => { let function_type = match callee { diff --git a/packages/@winglang/wingc/src/jsify/snapshots/fails_when_referencing_this_from_static.snap b/packages/@winglang/wingc/src/jsify/snapshots/fails_when_referencing_this_from_static.snap index f683e035597..1f4e3318417 100644 --- a/packages/@winglang/wingc/src/jsify/snapshots/fails_when_referencing_this_from_static.snap +++ b/packages/@winglang/wingc/src/jsify/snapshots/fails_when_referencing_this_from_static.snap @@ -1,5 +1,5 @@ --- -source: libs/wingc/src/jsify/tests.rs +source: packages/@winglang/wingc/src/jsify/tests.rs --- ## Errors Member "print" does not exist in "Construct" 3:13 diff --git a/packages/@winglang/wingc/src/lib.rs b/packages/@winglang/wingc/src/lib.rs index e653bdb12ad..0044a110178 100644 --- a/packages/@winglang/wingc/src/lib.rs +++ b/packages/@winglang/wingc/src/lib.rs @@ -123,6 +123,7 @@ const WINGSDK_AUTOID_RESOURCE: &'static str = "std.AutoIdResource"; const WINGSDK_STRUCT: &'static str = "std.Struct"; const WINGSDK_TEST_CLASS_NAME: &'static str = "Test"; const WINGSDK_NODE: &'static str = "std.Node"; +const WINGSDK_APP: &'static str = "std.IApp"; const WINGSDK_SIM_IRESOURCE: &'static str = "sim.IResource"; const WINGSDK_SIM_IRESOURCE_FQN: &'static str = formatcp!( @@ -289,7 +290,6 @@ pub fn type_check_file( None, ); tc.add_builtins(scope); - tc.patch_constructs(); // If the file is an entrypoint file, we add "this" to its symbol environment if is_entrypoint_file(&file.path) { diff --git a/packages/@winglang/wingc/src/lsp/snapshots/completions/call_struct_expansion.snap b/packages/@winglang/wingc/src/lsp/snapshots/completions/call_struct_expansion.snap index e3910ae14c6..4eeb4d6499e 100644 --- a/packages/@winglang/wingc/src/lsp/snapshots/completions/call_struct_expansion.snap +++ b/packages/@winglang/wingc/src/lsp/snapshots/completions/call_struct_expansion.snap @@ -1,5 +1,5 @@ --- -source: libs/wingc/src/lsp/completions.rs +source: packages/@winglang/wingc/src/lsp/completions.rs --- - label: "a:" kind: 5 diff --git a/packages/@winglang/wingc/src/lsp/snapshots/completions/call_struct_expansion_partial.snap b/packages/@winglang/wingc/src/lsp/snapshots/completions/call_struct_expansion_partial.snap index 71ba9424430..8b052f0e78e 100644 --- a/packages/@winglang/wingc/src/lsp/snapshots/completions/call_struct_expansion_partial.snap +++ b/packages/@winglang/wingc/src/lsp/snapshots/completions/call_struct_expansion_partial.snap @@ -1,5 +1,5 @@ --- -source: libs/wingc/src/lsp/completions.rs +source: packages/@winglang/wingc/src/lsp/completions.rs --- - label: "two:" kind: 5 diff --git a/packages/@winglang/wingc/src/lsp/snapshots/completions/empty.snap b/packages/@winglang/wingc/src/lsp/snapshots/completions/empty.snap index beef6a5ebb0..579eebdf85d 100644 --- a/packages/@winglang/wingc/src/lsp/snapshots/completions/empty.snap +++ b/packages/@winglang/wingc/src/lsp/snapshots/completions/empty.snap @@ -1,5 +1,5 @@ --- -source: libs/wingc/src/lsp/completions.rs +source: packages/@winglang/wingc/src/lsp/completions.rs --- - label: this kind: 6 diff --git a/packages/@winglang/wingc/src/lsp/snapshots/completions/intrinsics.snap b/packages/@winglang/wingc/src/lsp/snapshots/completions/intrinsics.snap index cd2d60e7030..df4afd74925 100644 --- a/packages/@winglang/wingc/src/lsp/snapshots/completions/intrinsics.snap +++ b/packages/@winglang/wingc/src/lsp/snapshots/completions/intrinsics.snap @@ -1,11 +1,25 @@ --- -source: libs/wingc/src/lsp/completions.rs +source: packages/@winglang/wingc/src/lsp/completions.rs --- +- label: "@app" + kind: 6 + detail: IApp + documentation: + kind: markdown + value: "Get the root application node.\n\nThe application node is the root of the construct tree and all other resources are children (or grandchildren) of this node.\nSee https://www.winglang.io/docs/concepts/application-tree for more information." + sortText: bb|@app - label: "@dirname" kind: 6 detail: str documentation: kind: markdown - value: "Get the normalized absolute path of the current source file's directory.\n\nThe resolved path represents a path during preflight only and is not guaranteed to be valid while inflight.\nIt should primarily be used in preflight or in inflights that are guaranteed to be executed in the same filesystem where preflight executed." + value: "Get the normalized absolute path of the current Wing source file's directory.\n\nThe resolved path represents a path during preflight only and is not guaranteed to be valid while inflight." sortText: bb|@dirname +- label: "@filename" + kind: 6 + detail: str + documentation: + 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 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 cd2d60e7030..df4afd74925 100644 --- a/packages/@winglang/wingc/src/lsp/snapshots/completions/intrinsics_partial.snap +++ b/packages/@winglang/wingc/src/lsp/snapshots/completions/intrinsics_partial.snap @@ -1,11 +1,25 @@ --- -source: libs/wingc/src/lsp/completions.rs +source: packages/@winglang/wingc/src/lsp/completions.rs --- +- label: "@app" + kind: 6 + detail: IApp + documentation: + kind: markdown + value: "Get the root application node.\n\nThe application node is the root of the construct tree and all other resources are children (or grandchildren) of this node.\nSee https://www.winglang.io/docs/concepts/application-tree for more information." + sortText: bb|@app - label: "@dirname" kind: 6 detail: str documentation: kind: markdown - value: "Get the normalized absolute path of the current source file's directory.\n\nThe resolved path represents a path during preflight only and is not guaranteed to be valid while inflight.\nIt should primarily be used in preflight or in inflights that are guaranteed to be executed in the same filesystem where preflight executed." + value: "Get the normalized absolute path of the current Wing source file's directory.\n\nThe resolved path represents a path during preflight only and is not guaranteed to be valid while inflight." sortText: bb|@dirname +- label: "@filename" + kind: 6 + detail: str + documentation: + 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 diff --git a/packages/@winglang/wingc/src/lsp/snapshots/completions/only_show_symbols_in_scope.snap b/packages/@winglang/wingc/src/lsp/snapshots/completions/only_show_symbols_in_scope.snap index 6d8e6e8943f..8664a76341c 100644 --- a/packages/@winglang/wingc/src/lsp/snapshots/completions/only_show_symbols_in_scope.snap +++ b/packages/@winglang/wingc/src/lsp/snapshots/completions/only_show_symbols_in_scope.snap @@ -1,5 +1,5 @@ --- -source: libs/wingc/src/lsp/completions.rs +source: packages/@winglang/wingc/src/lsp/completions.rs --- - label: a kind: 6 diff --git a/packages/@winglang/wingc/src/lsp/snapshots/completions/struct_arg_expansion_partial.snap b/packages/@winglang/wingc/src/lsp/snapshots/completions/struct_arg_expansion_partial.snap index 9390aaa24d5..271e4af50c5 100644 --- a/packages/@winglang/wingc/src/lsp/snapshots/completions/struct_arg_expansion_partial.snap +++ b/packages/@winglang/wingc/src/lsp/snapshots/completions/struct_arg_expansion_partial.snap @@ -1,5 +1,5 @@ --- -source: libs/wingc/src/lsp/completions.rs +source: packages/@winglang/wingc/src/lsp/completions.rs --- - label: "a1:" kind: 5 diff --git a/packages/@winglang/wingc/src/lsp/snapshots/completions/struct_literal_value.snap b/packages/@winglang/wingc/src/lsp/snapshots/completions/struct_literal_value.snap index 21a43adb971..106ee1c1519 100644 --- a/packages/@winglang/wingc/src/lsp/snapshots/completions/struct_literal_value.snap +++ b/packages/@winglang/wingc/src/lsp/snapshots/completions/struct_literal_value.snap @@ -1,5 +1,5 @@ --- -source: libs/wingc/src/lsp/completions.rs +source: packages/@winglang/wingc/src/lsp/completions.rs --- - label: this kind: 6 diff --git a/packages/@winglang/wingc/src/lsp/snapshots/completions/struct_show_values.snap b/packages/@winglang/wingc/src/lsp/snapshots/completions/struct_show_values.snap index e7fe01330cb..2870bfba730 100644 --- a/packages/@winglang/wingc/src/lsp/snapshots/completions/struct_show_values.snap +++ b/packages/@winglang/wingc/src/lsp/snapshots/completions/struct_show_values.snap @@ -1,5 +1,5 @@ --- -source: libs/wingc/src/lsp/completions.rs +source: packages/@winglang/wingc/src/lsp/completions.rs --- - label: this kind: 6 diff --git a/packages/@winglang/wingc/src/lsp/snapshots/hovers/intrinsics.snap b/packages/@winglang/wingc/src/lsp/snapshots/hovers/intrinsics.snap index 6a908874edd..33c201c947f 100644 --- a/packages/@winglang/wingc/src/lsp/snapshots/hovers/intrinsics.snap +++ b/packages/@winglang/wingc/src/lsp/snapshots/hovers/intrinsics.snap @@ -1,9 +1,9 @@ --- -source: libs/wingc/src/lsp/hover.rs +source: packages/@winglang/wingc/src/lsp/hover.rs --- contents: kind: markdown - value: "```wing\nstatic preflight @dirname: str\n```\n---\nGet the normalized absolute path of the current source file's directory.\n\nThe resolved path represents a path during preflight only and is not guaranteed to be valid while inflight.\nIt should primarily be used in preflight or in inflights that are guaranteed to be executed in the same filesystem where preflight executed." + value: "```wing\nstatic preflight @dirname: str\n```\n---\nGet the normalized absolute path of the current Wing source file's directory.\n\nThe resolved path represents a path during preflight only and is not guaranteed to be valid while inflight." range: start: line: 1 diff --git a/packages/@winglang/wingc/src/type_check.rs b/packages/@winglang/wingc/src/type_check.rs index 2b88f8ca7ed..62fe866f65f 100644 --- a/packages/@winglang/wingc/src/type_check.rs +++ b/packages/@winglang/wingc/src/type_check.rs @@ -29,10 +29,10 @@ use crate::visit_stmt_before_super::{CheckSuperCtorLocationVisitor, CheckValidBe use crate::visit_types::{VisitType, VisitTypeMut}; use crate::{ debug, CONSTRUCT_BASE_CLASS, CONSTRUCT_BASE_INTERFACE, CONSTRUCT_NODE_PROPERTY, DEFAULT_PACKAGE_NAME, - UTIL_CLASS_NAME, WINGSDK_ARRAY, WINGSDK_ASSEMBLY_NAME, WINGSDK_BRINGABLE_MODULES, 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_REGEX, WINGSDK_RESOURCE, WINGSDK_SET, WINGSDK_SIM_IRESOURCE_FQN, - WINGSDK_STD_MODULE, WINGSDK_STRING, WINGSDK_STRUCT, + UTIL_CLASS_NAME, WINGSDK_APP, WINGSDK_ARRAY, WINGSDK_ASSEMBLY_NAME, WINGSDK_BRINGABLE_MODULES, 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_REGEX, WINGSDK_RESOURCE, WINGSDK_SET, + WINGSDK_SIM_IRESOURCE_FQN, WINGSDK_STD_MODULE, WINGSDK_STRING, WINGSDK_STRUCT, }; use camino::{Utf8Path, Utf8PathBuf}; use derivative::Derivative; @@ -1909,7 +1909,7 @@ impl Types { } } -/// Enum of builtin functions, this are defined as hard coded AST nodes in `add_builtins` +/// Enum of builtin functions, this are defined as hard coded types in `add_builtins` #[derive(Debug)] pub enum UtilityFunctions { Log, @@ -1929,6 +1929,9 @@ impl Display for UtilityFunctions { } } +/// The type checker is responsible for type checking the AST of a Wing program. +/// Type checking includes building the symbol environment, checking and inferring types, and emitting relevant errors. +/// A new type checker is created for each file or directory. pub struct TypeChecker<'a> { types: &'a mut Types, @@ -2147,40 +2150,6 @@ impl<'a> TypeChecker<'a> { .expect("Failed to add this"); } - /// Patch some of the types from the "constructs" package to provide a better DX - pub fn patch_constructs(&mut self) { - // Hide the "node" field from constructs so that users go through - // the `nodeof` utility function to get the tree node of a construct. - // The `Node` instance provided by Wing has some extra methods not - // available in the constructs package, and also modifies how the - // root node is obtained. - let mut constructs_iface = self - .types - .libraries - .lookup_nested_str(&CONSTRUCT_BASE_INTERFACE, None) - .expect("constructs.IConstruct not found in type system") - .0 - .as_type() - .expect("constructs.IConstruct was found but it's not a type"); - let iface = constructs_iface - .as_interface_mut() - .expect("constructs.IConstruct was found but it's not a class"); - iface.env.symbol_map.remove(CONSTRUCT_NODE_PROPERTY); - - let mut constructs_class = self - .types - .libraries - .lookup_nested_str(&CONSTRUCT_BASE_CLASS, None) - .expect("constructs.Construct not found in type system") - .0 - .as_type() - .expect("constructs.Construct was found but it's not a type"); - let class = constructs_class - .as_class_mut() - .expect("constructs.Construct was found but it's not a class"); - class.env.symbol_map.remove(CONSTRUCT_NODE_PROPERTY); - } - pub fn add_builtins(&mut self, scope: &mut Scope) { let optional_string = self.types.make_option(self.types.string()); self.add_builtin( @@ -2279,15 +2248,39 @@ impl<'a> TypeChecker<'a> { ); // Intrinsics + // @dirname + + // TODO: we shouldn't be dropping the return value here let _ = self.types.intrinsics.define( &Symbol::global(IntrinsicKind::Dirname.to_string()), SymbolKind::Variable(VariableInfo { access: AccessModifier::Public, name: Symbol::global(IntrinsicKind::Dirname.to_string()), - docs: Some(Docs::with_summary(r#"Get the normalized absolute path of the current source file's directory. + docs: Some(Docs::with_summary( + r#"Get the normalized absolute path of the current Wing source file's directory. + +The resolved path represents a path during preflight only and is not guaranteed to be valid while inflight."#, + )), + kind: VariableKind::StaticMember, + phase: Phase::Preflight, + type_: self.types.string(), + reassignable: false, + }), + AccessModifier::Public, + StatementIdx::Top, + ); + + // @filename + let _ = self.types.intrinsics.define( + &Symbol::global(IntrinsicKind::Filename.to_string()), + SymbolKind::Variable(VariableInfo { + access: AccessModifier::Public, + name: Symbol::global(IntrinsicKind::Filename.to_string()), + docs: Some(Docs::with_summary( + r#"Get the normalized absolute path of the current Wing source file. -The resolved path represents a path during preflight only and is not guaranteed to be valid while inflight. -It should primarily be used in preflight or in inflights that are guaranteed to be executed in the same filesystem where preflight executed."#)), +The resolved path represents a path during preflight only and is not guaranteed to be valid while inflight."#, + )), kind: VariableKind::StaticMember, phase: Phase::Preflight, type_: self.types.string(), @@ -2296,6 +2289,38 @@ It should primarily be used in preflight or in inflights that are guaranteed to AccessModifier::Public, StatementIdx::Top, ); + + // @app + let std_app_fqn = format!("{}.{}", WINGSDK_ASSEMBLY_NAME, WINGSDK_APP); + let std_app = self + .types + .libraries + .lookup_nested_str(&std_app_fqn, None) + .expect("std.IApp not found in type system") + .0 + .as_type() + .expect("std.IApp was found but it's not a type"); + let _ = self.types + .intrinsics + .define( + &Symbol::global(IntrinsicKind::App.to_string()), + SymbolKind::Variable(VariableInfo { + access: AccessModifier::Public, + name: Symbol::global(IntrinsicKind::App.to_string()), + docs: Some(Docs::with_summary( + r#"Get the root application node. + +The application node is the root of the construct tree and all other resources are children (or grandchildren) of this node. +See https://www.winglang.io/docs/concepts/application-tree for more information."#, + )), + kind: VariableKind::StaticMember, + phase: Phase::Preflight, + type_: std_app, + reassignable: false, + }), + AccessModifier::Public, + StatementIdx::Top, + ); } fn add_builtin(&mut self, name: &str, typ: Type, scope: &mut Scope) { @@ -2944,7 +2969,7 @@ It should primarily be used in preflight or in inflights that are guaranteed to } match intrinsic.kind { - IntrinsicKind::Dirname | IntrinsicKind::Unknown => { + IntrinsicKind::Dirname | IntrinsicKind::Filename | IntrinsicKind::App | IntrinsicKind::Unknown => { return (sig.return_type, sig.phase); } } diff --git a/packages/@winglang/wingc/src/type_check/jsii_importer.rs b/packages/@winglang/wingc/src/type_check/jsii_importer.rs index f6b9e3a1c41..86ddd0fa3a9 100644 --- a/packages/@winglang/wingc/src/type_check/jsii_importer.rs +++ b/packages/@winglang/wingc/src/type_check/jsii_importer.rs @@ -10,8 +10,8 @@ use crate::{ Class, FunctionParameter, FunctionSignature, Interface, ResolveSource, Struct, SymbolKind, Type, TypeRef, Types, CLASS_INIT_NAME, }, - CONSTRUCT_BASE_CLASS, WINGSDK_ASSEMBLY_NAME, WINGSDK_DATETIME, WINGSDK_DURATION, WINGSDK_JSON, WINGSDK_MUT_JSON, - WINGSDK_REGEX, WINGSDK_RESOURCE, + CONSTRUCT_BASE_CLASS, CONSTRUCT_BASE_INTERFACE, WINGSDK_ASSEMBLY_NAME, WINGSDK_DATETIME, WINGSDK_DURATION, + WINGSDK_JSON, WINGSDK_MUT_JSON, WINGSDK_REGEX, WINGSDK_RESOURCE, }; use colored::Colorize; use indexmap::IndexMap; @@ -27,11 +27,15 @@ use super::{ }; trait JsiiInterface { + fn fqn(&self) -> &str; fn methods(&self) -> &Option>; fn properties(&self) -> &Option>; } impl JsiiInterface for jsii::ClassType { + fn fqn(&self) -> &str { + &self.fqn + } fn methods(&self) -> &Option> { &self.methods } @@ -41,6 +45,9 @@ impl JsiiInterface for jsii::ClassType { } impl JsiiInterface for jsii::InterfaceType { + fn fqn(&self) -> &str { + &self.fqn + } fn methods(&self) -> &Option> { &self.methods } @@ -626,6 +633,14 @@ impl<'a> JsiiImporter<'a> { if let Some(properties) = jsii_interface.properties() { for p in properties { debug!("Found property {} with type {:?}", p.name.green(), p.type_); + + if (jsii_interface.fqn() == CONSTRUCT_BASE_CLASS || jsii_interface.fqn() == CONSTRUCT_BASE_INTERFACE) + && p.name == "node" + { + debug!("Skipping node property on resource"); + continue; + } + let base_wing_type = self.type_ref_to_wing_type(&p.type_); let is_optional = if let Some(true) = p.optional { true } else { false }; let is_static = if let Some(true) = p.static_ { true } else { false }; diff --git a/packages/@winglibs/testfixture/API.md b/packages/@winglibs/testfixture/API.md index 388f1b7a129..67b21c4da49 100644 --- a/packages/@winglibs/testfixture/API.md +++ b/packages/@winglibs/testfixture/API.md @@ -54,6 +54,7 @@ new(options: StoreOptions?): Store | **Signature** | **Description** | | --- | --- | +| static loadStaticData(): str | *No description* | | static makeKey(name: str): str | *No description* | | static inflight makeKeyInflight(name: str): str | *No description* | | onSet(handler: inflight (str): void): void | *No description* | diff --git a/packages/@winglibs/testfixture/example-data.txt b/packages/@winglibs/testfixture/example-data.txt new file mode 100644 index 00000000000..a0423896973 --- /dev/null +++ b/packages/@winglibs/testfixture/example-data.txt @@ -0,0 +1 @@ +hello world! diff --git a/packages/@winglibs/testfixture/store.w b/packages/@winglibs/testfixture/store.w index 79cb6e37a05..457b9fb4aac 100644 --- a/packages/@winglibs/testfixture/store.w +++ b/packages/@winglibs/testfixture/store.w @@ -1,4 +1,5 @@ bring cloud; +bring fs; bring "./subdir/util.w" as myutil; pub struct StoreOptions { @@ -27,6 +28,14 @@ pub class Store { pub onSet(handler: inflight (str): void) { this.handlers.push(handler); } + + // Example of a method that reads a file from the winglib in preflight + // This is to validate that @dirname is calculated correctly + pub static loadStaticData(): str { + let path = fs.join(@dirname, "example-data.txt"); + let contents = fs.readFile(path); + return contents; + } } pub interface PublicInterface {} diff --git a/tests/invalid/intrinsics.test.w b/tests/invalid/intrinsics.test.w index 458ab47823a..bb226bcf08b 100644 --- a/tests/invalid/intrinsics.test.w +++ b/tests/invalid/intrinsics.test.w @@ -1,6 +1,8 @@ inflight () => { let x = @dirname; // ^^^^^^^^ @dirname cannot be used inflight + let y = @filename; +// ^^^^^^^^ @filename cannot be used inflight }; let path = @dirname(); diff --git a/tests/invalid/parameters.test.w b/tests/invalid/parameters.test.w index 71b00933910..492db10b753 100644 --- a/tests/invalid/parameters.test.w +++ b/tests/invalid/parameters.test.w @@ -1,10 +1,8 @@ -let app = nodeof(this).app; - struct MyParams { foo: str; } -app.parameters.addSchema(MyParams.schema()); +@app.parameters.addSchema(MyParams.schema()); // Error: Parameter validation errors: // - must have required property 'foo' diff --git a/tests/invalid/struct_from_parameter.test.w b/tests/invalid/struct_from_parameter.test.w index 908b478fcf4..41b9d071a6d 100644 --- a/tests/invalid/struct_from_parameter.test.w +++ b/tests/invalid/struct_from_parameter.test.w @@ -4,15 +4,12 @@ struct MyParams { baz: num; } - -let app = nodeof(this).app; - // Never added the schema to the parameters, so // technically we never enforced the parameters must have been // provided -MyParams.fromJson(app.parameters.read()); +MyParams.fromJson(@app.parameters.read()); //Error: unable to parse MyParams: // - instance requires property "bar" // - instance requires property "baz" -// - instance requires property "foo" \ No newline at end of file +// - instance requires property "foo" diff --git a/tests/valid/app.test.w b/tests/valid/app.test.w new file mode 100644 index 00000000000..d9bfbb336f1 --- /dev/null +++ b/tests/valid/app.test.w @@ -0,0 +1,18 @@ +/*\ +args: + - --rootId + - root +\*/ + +bring expect; + +expect.equal(@app.workdir.contains(".wing"), true); + +let path = nodeof(@app).path; + +for c in nodeof(@app).children { + log(nodeof(c).path); +} + +expect.notNil(nodeof(@app)); +expect.equal(nodeof(@app).path.split("/").at(0), "root"); diff --git a/tests/valid/bring_wing_library.test.w b/tests/valid/bring_wing_library.test.w index f66f669b82c..daa50fcaddd 100644 --- a/tests/valid/bring_wing_library.test.w +++ b/tests/valid/bring_wing_library.test.w @@ -1,3 +1,4 @@ +bring expect; bring "@winglibs/testfixture" as fixture; bring testfixture; bring testfixture as testfixture2; @@ -12,3 +13,5 @@ assert(fixture.Store.makeKey("hello") == "data/hello.json"); test "makeKeyInflight" { assert(fixture.Store.makeKeyInflight("hello") == "data/hello.json"); } + +expect.equal(fixture.Store.loadStaticData(), "hello world!\n"); diff --git a/tests/valid/external_ts.extern.d.ts b/tests/valid/external_ts.extern.d.ts index 0804255b164..08567bed862 100644 --- a/tests/valid/external_ts.extern.d.ts +++ b/tests/valid/external_ts.extern.d.ts @@ -47,145 +47,8 @@ export interface IHostedLiftable extends ILiftable { one or more of its methods are called. */ readonly onLift: (host: IInflightHost, ops: (readonly (string)[])) => void; } -/** Options for `construct.addMetadata()`. */ -export interface MetadataOptions { - /** Include stack trace with metadata entry. */ - readonly stackTrace?: (boolean) | undefined; - /** A JavaScript function to begin tracing from. - This option is ignored unless `stackTrace` is `true`. */ - readonly traceFromFunction?: (any) | undefined; -} -/** Implement this interface in order for the construct to be able to validate itself. */ -export interface IValidation { - /** Validate the current construct. - This method can be implemented by derived constructs in order to perform - validation logic. It is called on all constructs before synthesis. - @returns An array of validation error messages, or an empty array if there the construct is valid. */ - readonly validate: () => (readonly (string)[]); -} -/** In what order to return constructs. */ -export enum ConstructOrder { - PREORDER = 0, - POSTORDER = 1, -} -/** An entry in the construct metadata table. */ -export interface MetadataEntry { - /** The data. */ - readonly data?: any; - /** Stack trace at the point of adding the metadata. - Only available if `addMetadata()` is called with `stackTrace: true`. */ - readonly trace?: ((readonly (string)[])) | undefined; - /** The metadata entry type. */ - readonly type: string; -} -/** Represents the construct node in the scope tree. */ -export class Node { - /** Add an ordering dependency on another construct. - An `IDependable` */ - readonly addDependency: (deps: (readonly (IDependable)[])) => void; - /** Adds a metadata entry to this construct. - Entries are arbitrary values and will also include a stack trace to allow tracing back to - the code location for when the entry was added. It can be used, for example, to include source - mapping in CloudFormation templates to improve diagnostics. */ - readonly addMetadata: (type: string, data?: any, options?: (MetadataOptions) | undefined) => void; - /** Adds a validation to this construct. - When `node.validate()` is called, the `validate()` method will be called on - all validations and all errors will be returned. */ - readonly addValidation: (validation: IValidation) => void; - /** Returns an opaque tree-unique address for this construct. - Addresses are 42 characters hexadecimal strings. They begin with "c8" - followed by 40 lowercase hexadecimal characters (0-9a-f). - - Addresses are calculated using a SHA-1 of the components of the construct - path. - - To enable refactorings of construct trees, constructs with the ID `Default` - will be excluded from the calculation. In those cases constructs in the - same tree may have the same addreess. - c83a2846e506bcc5f10682b564084bca2d275709ee */ - readonly addr: string; - /** All direct children of this construct. */ - readonly children: (readonly (IConstruct)[]); - /** Returns the child construct that has the id `Default` or `Resource"`. - This is usually the construct that provides the bulk of the underlying functionality. - Useful for modifications of the underlying construct that are not available at the higher levels. - Override the defaultChild property. - - This should only be used in the cases where the correct - default child is not named 'Resource' or 'Default' as it - should be. - - If you set this to undefined, the default behavior of finding - the child named 'Resource' or 'Default' will be used. - @returns a construct or undefined if there is no default child */ - defaultChild?: (IConstruct) | undefined; - /** Return all dependencies registered on this node (non-recursive). */ - readonly dependencies: (readonly (IConstruct)[]); - /** Return this construct and all of its children in the given order. */ - readonly findAll: (order?: (ConstructOrder) | undefined) => (readonly (IConstruct)[]); - /** Return a direct child by id. - Throws an error if the child is not found. - @returns Child with the given id. */ - readonly findChild: (id: string) => IConstruct; - /** Retrieves the all context of a node from tree context. - Context is usually initialized at the root, but can be overridden at any point in the tree. - @returns The context object or an empty object if there is discovered context */ - readonly getAllContext: (defaults?: (Readonly) | undefined) => any; - /** Retrieves a value from tree context if present. Otherwise, would throw an error. - Context is usually initialized at the root, but can be overridden at any point in the tree. - @returns The context value or throws error if there is no context value for this key */ - readonly getContext: (key: string) => any; - /** The id of this construct within the current scope. - This is a scope-unique id. To obtain an app-unique id for this construct, use `addr`. */ - readonly id: string; - /** Locks this construct from allowing more children to be added. - After this - call, no more children can be added to this construct or to any children. */ - readonly lock: () => void; - /** Returns true if this construct or the scopes in which it is defined are locked. */ - readonly locked: boolean; - /** An immutable array of metadata objects associated with this construct. - This can be used, for example, to implement support for deprecation notices, source mapping, etc. */ - readonly metadata: (readonly (MetadataEntry)[]); - /** The full, absolute path of this construct in the tree. - Components are separated by '/'. */ - readonly path: string; - /** Returns the root of the construct tree. - @returns The root of the construct tree. */ - readonly root: IConstruct; - /** Returns the scope in which this construct is defined. - The value is `undefined` at the root of the construct scope tree. */ - readonly scope?: (IConstruct) | undefined; - /** All parent scopes of this construct. - @returns a list of parent scopes. The last element in the list will always - be the current construct and the first element will be the root of the - tree. */ - readonly scopes: (readonly (IConstruct)[]); - /** This can be used to set contextual values. - Context must be set before any children are added, since children may consult context info during construction. - If the key already exists, it will be overridden. */ - readonly setContext: (key: string, value?: any) => void; - /** Return a direct child by id, or undefined. - @returns the child if found, or undefined */ - readonly tryFindChild: (id: string) => IConstruct | void; - /** Retrieves a value from tree context. - Context is usually initialized at the root, but can be overridden at any point in the tree. - @returns The context value or `undefined` if there is no context value for this key. */ - readonly tryGetContext: (key: string) => any; - /** Remove the child with the given name, if present. - @returns Whether a child with the given name was deleted. */ - readonly tryRemoveChild: (childName: string) => boolean; - /** Validates this construct. - Invokes the `validate()` method on all validations added through - `addValidation()`. - @returns an array of validation error messages associated with this - construct. */ - readonly validate: () => (readonly (string)[]); -} /** Abstract interface for `Resource`. */ export interface IResource extends IConstruct, IHostedLiftable { - /** The tree node. */ - readonly node: Node; /** A hook called by the Wing compiler once for each inflight host that needs to use this object inflight. The list of requested inflight methods needed by the inflight host are given by `ops`. diff --git a/tests/valid/factory.test.w b/tests/valid/factory.test.w new file mode 100644 index 00000000000..b59987b72bd --- /dev/null +++ b/tests/valid/factory.test.w @@ -0,0 +1,25 @@ +bring cloud; +bring "constructs" as constructs; +bring expect; + +class BucketFactory { + pub static makeBucket(scope: constructs.IConstruct): cloud.Bucket { + let bucket = new cloud.Bucket() in scope; + // apply customizations to bucket... + return bucket; + } +} + +// Test that we can use the factory pattern by passing top-level "this" +let bucket = BucketFactory.makeBucket(this); +log(nodeof(bucket).path); + +test "can use bucket" { + bucket.put("hello", "world"); + expect.equal(bucket.list().length, 1); +} + +test "can use other bucket" { + bucket.put("yo", "sup"); + expect.equal(bucket.list().length, 1); +} diff --git a/tests/valid/inflight_closure_as_super_param.test.w b/tests/valid/inflight_closure_as_super_param.test.w index 8cf60c60a19..a1b40feeb5a 100644 --- a/tests/valid/inflight_closure_as_super_param.test.w +++ b/tests/valid/inflight_closure_as_super_param.test.w @@ -32,4 +32,4 @@ assert(nodeof(c.f_base).path == "{appPath}/in_root"); test "boom!" { assert(c.h() == "boom!"); -} \ No newline at end of file +} diff --git a/tests/valid/intrinsics.test.w b/tests/valid/intrinsics.test.w index 8a532e72109..ee23acf5f96 100644 --- a/tests/valid/intrinsics.test.w +++ b/tests/valid/intrinsics.test.w @@ -13,3 +13,9 @@ let currentFile = fs.join(@dirname, filename); expect.equal(filename, fs.basename(currentFile)); expect.equal(@dirname, fs.dirname(currentFile)); expect.equal(bar.Bar.getSubdir(), fs.join(@dirname, "subdir")); + +// @filename + +expect.equal(@filename, currentFile); +expect.equal(fs.dirname(currentFile), @dirname); +expect.equal(bar.Bar.getSubfile(), fs.join(@dirname, "subdir", "bar.w")); diff --git a/tests/valid/parameters/nested/parameters.test.w b/tests/valid/parameters/nested/parameters.test.w index 618b89979fc..975c09adcd8 100644 --- a/tests/valid/parameters/nested/parameters.test.w +++ b/tests/valid/parameters/nested/parameters.test.w @@ -12,10 +12,8 @@ struct MyParams { houses: Array; } -let app = nodeof(this).app; - -let myParams = MyParams.fromJson(app.parameters.read(schema: MyParams.schema())); +let myParams = MyParams.fromJson(@app.parameters.read(schema: MyParams.schema())); assert(myParams.houses.length == 2); assert(myParams.houses.at(0).address == "123 Main St"); -assert(myParams.houses.at(0).residents.length == 2); \ No newline at end of file +assert(myParams.houses.at(0).residents.length == 2); diff --git a/tests/valid/parameters/simple/parameters.test.w b/tests/valid/parameters/simple/parameters.test.w index 740e1b2ecea..27faa0b7e52 100644 --- a/tests/valid/parameters/simple/parameters.test.w +++ b/tests/valid/parameters/simple/parameters.test.w @@ -1,11 +1,9 @@ -let app = nodeof(this).app; - struct MyParams { foo: str?; meaningOfLife: num; } -let myParams = MyParams.fromJson(app.parameters.read(schema: MyParams.schema())); +let myParams = MyParams.fromJson(@app.parameters.read(schema: MyParams.schema())); if let foo = myParams.foo { assert(false); // shouldnt happen @@ -15,4 +13,4 @@ if let foo = myParams.foo { let meaningOfLife = myParams.meaningOfLife; -assert(meaningOfLife == 42); \ No newline at end of file +assert(meaningOfLife == 42); diff --git a/tests/valid/rootid.test.w b/tests/valid/rootid.test.w index 65d89b90ebf..b872fe100df 100644 --- a/tests/valid/rootid.test.w +++ b/tests/valid/rootid.test.w @@ -7,7 +7,7 @@ args: bring util; bring expect; -let rootId = nodeof(this).app.node.id; +let rootId = nodeof(@app).id; // this env var does not exist within the console and within inflight scopes let envRootId = util.tryEnv("WING_ROOT_ID") ?? "root"; @@ -18,4 +18,4 @@ expect.equal(rootId, envRootId); test "root id" { // an inflight test is added since it's looked for by path and we need to verify its working expect.equal(rootId, envRootId); -} \ No newline at end of file +} diff --git a/tests/valid/subdir/bar.w b/tests/valid/subdir/bar.w index ff24b6028a7..d82fe798fcd 100644 --- a/tests/valid/subdir/bar.w +++ b/tests/valid/subdir/bar.w @@ -7,6 +7,9 @@ pub class Bar { pub static getSubdir(): str { return @dirname; } + pub static getSubfile(): str { + return @filename; + } } -pub inflight class InflightBar {} \ No newline at end of file +pub inflight class InflightBar {} diff --git a/tests/valid/this.test.w b/tests/valid/this.test.w deleted file mode 100644 index 00fa592dd6a..00000000000 --- a/tests/valid/this.test.w +++ /dev/null @@ -1,17 +0,0 @@ -/*\ -args: - - --rootId - - root -\*/ - -bring expect; - -// Play around with "this" -let path = nodeof(this).path; - -for c in nodeof(this).children { - log(nodeof(c).path); -} - -expect.notNil(nodeof(this)); -expect.equal(nodeof(this).path.split("/").at(0), "root"); diff --git a/tools/hangar/__snapshots__/invalid.ts.snap b/tools/hangar/__snapshots__/invalid.ts.snap index c86bf1c3da7..ce0c40a4885 100644 --- a/tools/hangar/__snapshots__/invalid.ts.snap +++ b/tools/hangar/__snapshots__/invalid.ts.snap @@ -2875,9 +2875,9 @@ error: Interface "fixture.InternalInterface" is internal 6 | class FakeClass impl fixture.InternalInterface {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - --> ../../../tests/invalid/node_modules/@winglibs/testfixture/store.w:34:20 + --> ../../../tests/invalid/node_modules/@winglibs/testfixture/store.w:43:20 | -34 | internal interface InternalInterface {} +43 | internal interface InternalInterface {} | ----------------- defined here | = hint: the definition of "fixture.InternalInterface" needs a broader access modifier like "pub" to be used outside of "@winglibs/testfixture" @@ -2896,9 +2896,9 @@ error: Class "fixture.InternalClass" is internal 9 | let i = new fixture.InternalClass(); | ^^^^^^^^^^^^^^^^^^^^^ | - --> ../../../tests/invalid/node_modules/@winglibs/testfixture/store.w:36:16 + --> ../../../tests/invalid/node_modules/@winglibs/testfixture/store.w:45:16 | -36 | internal class InternalClass { +45 | internal class InternalClass { | ------------- defined here | = hint: the definition of "fixture.InternalClass" needs a broader access modifier like "pub" to be used outside of "@winglibs/testfixture" @@ -2910,9 +2910,9 @@ error: Cannot access internal member "internalStaticMethod" of "PublicClass" 12 | fixture.PublicClass.internalStaticMethod(); | ^^^^^^^^^^^^^^^^^^^^ | - --> ../../../tests/invalid/node_modules/@winglibs/testfixture/store.w:41:19 + --> ../../../tests/invalid/node_modules/@winglibs/testfixture/store.w:50:19 | -41 | static internal internalStaticMethod() {} +50 | static internal internalStaticMethod() {} | -------------------- defined here | = hint: the definition of "internalStaticMethod" needs a broader access modifier like "pub" to be used outside of "@winglibs/testfixture" @@ -2924,9 +2924,9 @@ error: Cannot access internal member "internalField" of "PublicClass" 16 | p.internalField; | ^^^^^^^^^^^^^ | - --> ../../../tests/invalid/node_modules/@winglibs/testfixture/store.w:43:12 + --> ../../../tests/invalid/node_modules/@winglibs/testfixture/store.w:52:12 | -43 | internal internalField: num; +52 | internal internalField: num; | ------------- defined here | = hint: the definition of "internalField" needs a broader access modifier like "pub" to be used outside of "@winglibs/testfixture" @@ -2938,9 +2938,9 @@ error: Cannot access internal member "internalMethod" of "PublicClass" 19 | p.internalMethod(); | ^^^^^^^^^^^^^^ | - --> ../../../tests/invalid/node_modules/@winglibs/testfixture/store.w:51:12 + --> ../../../tests/invalid/node_modules/@winglibs/testfixture/store.w:60:12 | -51 | internal internalMethod() {} +60 | internal internalMethod() {} | -------------- defined here | = hint: the definition of "internalMethod" needs a broader access modifier like "pub" to be used outside of "@winglibs/testfixture" @@ -2952,9 +2952,9 @@ error: Struct "fixture.InternalStruct" is internal 22 | let s = fixture.InternalStruct {}; | ^^^^^^^^^^^^^^^^^^^^^^ | - --> ../../../tests/invalid/node_modules/@winglibs/testfixture/store.w:55:17 + --> ../../../tests/invalid/node_modules/@winglibs/testfixture/store.w:64:17 | -55 | internal struct InternalStruct {} +64 | internal struct InternalStruct {} | -------------- defined here | = hint: the definition of "fixture.InternalStruct" needs a broader access modifier like "pub" to be used outside of "@winglibs/testfixture" @@ -2967,9 +2967,9 @@ Duration " exports[`intrinsics.test.w 1`] = ` "error: @dirname does not expect arguments - --> ../../../tests/invalid/intrinsics.test.w:6:20 + --> ../../../tests/invalid/intrinsics.test.w:8:20 | -6 | let path = @dirname(); +8 | let path = @dirname(); | ^^ @@ -2979,6 +2979,13 @@ error: @dirname cannot be used in inflight 2 | let x = @dirname; | ^^^^^^^^ + +error: @filename cannot be used in inflight + --> ../../../tests/invalid/intrinsics.test.w:4:11 + | +4 | let y = @filename; + | ^^^^^^^^^ + Tests 1 failed (1) Snapshots 1 skipped Test Files 1 failed (1) @@ -4756,13 +4763,13 @@ exports[`struct_from_parameter.test.w 1`] = ` - MyParams must have required property 'bar' - MyParams must have required property 'baz' - MyParams must have required property 'foo' - --> ../../../tests/invalid/struct_from_parameter.test.w:14:1 + --> ../../../tests/invalid/struct_from_parameter.test.w:11:1 | // technically we never enforced the parameters must have been | // provided | -14 | MyParams.fromJson(app.parameters.read()); +11 | MyParams.fromJson(@app.parameters.read()); | ^ -at /struct_from_parameter.test.w:14:1 +at /struct_from_parameter.test.w:11:1 Tests 1 failed (1) Snapshots 1 skipped diff --git a/tools/hangar/__snapshots__/test_corpus/valid/app.test.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/valid/app.test.w_compile_tf-aws.md new file mode 100644 index 00000000000..fe612ba54de --- /dev/null +++ b/tools/hangar/__snapshots__/test_corpus/valid/app.test.w_compile_tf-aws.md @@ -0,0 +1,53 @@ +# [app.test.w](../../../../../tests/valid/app.test.w) | compile | tf-aws + +## main.tf.json +```json +{ + "//": { + "metadata": { + "backend": "local", + "stackName": "root" + }, + "outputs": {} + }, + "provider": { + "aws": [ + {} + ] + } +} +``` + +## preflight.cjs +```cjs +"use strict"; +const $stdlib = require('@winglang/sdk'); +const $macros = require("@winglang/sdk/lib/macros"); +const $platforms = ((s) => !s ? [] : s.split(';'))(process.env.WING_PLATFORMS); +const $outdir = process.env.WING_SYNTH_DIR ?? "."; +const $wing_is_test = process.env.WING_IS_TEST === "true"; +const std = $stdlib.std; +const $helpers = $stdlib.helpers; +const $extern = $helpers.createExternRequire(__dirname); +const $PlatformManager = new $stdlib.platform.PlatformManager({platformPaths: $platforms}); +class $Root extends $stdlib.std.Resource { + constructor($scope, $id) { + super($scope, $id); + $helpers.nodeof(this).root.$preflightTypesMap = { }; + let $preflightTypesMap = {}; + const expect = $stdlib.expect; + $helpers.nodeof(this).root.$preflightTypesMap = $preflightTypesMap; + (expect.Util.equal($macros.__String_contains(false, $helpers.nodeof(this).app.workdir, ".wing"), true)); + const path = $helpers.nodeof($helpers.nodeof(this).app).path; + for (const c of $helpers.nodeof($helpers.nodeof(this).app).children) { + console.log($helpers.nodeof(c).path); + } + (expect.Util.notNil($helpers.nodeof($helpers.nodeof(this).app))); + (expect.Util.equal($macros.__Array_at(false, ($helpers.nodeof($helpers.nodeof(this).app).path.split("/")), 0), "root")); + } +} +const $APP = $PlatformManager.createApp({ outdir: $outdir, name: "app.test", rootConstruct: $Root, isTestEnvironment: $wing_is_test, entrypointDir: process.env['WING_SOURCE_DIR'], rootId: process.env['WING_ROOT_ID'] }); +$APP.synth(); +//# sourceMappingURL=preflight.cjs.map +``` + diff --git a/tools/hangar/__snapshots__/test_corpus/valid/app.test.w_test_sim.md b/tools/hangar/__snapshots__/test_corpus/valid/app.test.w_test_sim.md new file mode 100644 index 00000000000..93780afbe3b --- /dev/null +++ b/tools/hangar/__snapshots__/test_corpus/valid/app.test.w_test_sim.md @@ -0,0 +1,14 @@ +# [app.test.w](../../../../../tests/valid/app.test.w) | test | sim + +## stdout.log +```log +root/cloud.TestRunner +root/Default +pass ─ app.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/bring_local_normalization.test.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/valid/bring_local_normalization.test.w_compile_tf-aws.md index 4d59907343b..c71a5d063c0 100644 --- a/tools/hangar/__snapshots__/test_corpus/valid/bring_local_normalization.test.w_compile_tf-aws.md +++ b/tools/hangar/__snapshots__/test_corpus/valid/bring_local_normalization.test.w_compile_tf-aws.md @@ -87,7 +87,10 @@ class Bar extends $stdlib.std.Resource { return "bar"; } static getSubdir($scope) { - return $helpers.resolveDirname(__dirname, "../../../subdir"); + return $helpers.resolve(__dirname, "../../../subdir"); + } + static getSubfile($scope) { + return $helpers.resolve(__dirname, "../../../subdir/bar.w"); } static _toInflightType() { return ` diff --git a/tools/hangar/__snapshots__/test_corpus/valid/bring_wing_library.test.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/valid/bring_wing_library.test.w_compile_tf-aws.md index 63a969c3619..4acb72c5430 100644 --- a/tools/hangar/__snapshots__/test_corpus/valid/bring_wing_library.test.w_compile_tf-aws.md +++ b/tools/hangar/__snapshots__/test_corpus/valid/bring_wing_library.test.w_compile_tf-aws.md @@ -143,6 +143,7 @@ class $Root extends $stdlib.std.Resource { super($scope, $id); $helpers.nodeof(this).root.$preflightTypesMap = { }; let $preflightTypesMap = {}; + const expect = $stdlib.expect; const fixture = $helpers.bringJs(`${__dirname}/preflight.testfixture-5.cjs`, $preflightTypesMap); const testfixture = $helpers.bringJs(`${__dirname}/preflight.testfixture-5.cjs`, $preflightTypesMap); const testfixture2 = $helpers.bringJs(`${__dirname}/preflight.testfixture-5.cjs`, $preflightTypesMap); @@ -177,6 +178,7 @@ class $Root extends $stdlib.std.Resource { const fave_num3 = testfixture2.FavoriteNumbers.SEVEN; $helpers.assert($helpers.eq((fixture.Store.makeKey("hello")), "data/hello.json"), "fixture.Store.makeKey(\"hello\") == \"data/hello.json\""); globalThis.$ClassFactory.new("@winglang/sdk.std.Test", std.Test, this, "test:makeKeyInflight", new $Closure1(this, "$Closure1")); + (expect.Util.equal((fixture.Store.loadStaticData(this)), "hello world!\n")); } } const $APP = $PlatformManager.createApp({ outdir: $outdir, name: "bring_wing_library.test", rootConstruct: $Root, isTestEnvironment: $wing_is_test, entrypointDir: process.env['WING_SOURCE_DIR'], rootId: process.env['WING_ROOT_ID'] }); @@ -221,6 +223,7 @@ const $helpers = $stdlib.helpers; const $extern = $helpers.createExternRequire(__dirname); let $preflightTypesMap = {}; const cloud = $stdlib.cloud; +const fs = $stdlib.fs; const myutil = $helpers.bringJs(`${__dirname}/preflight.util-2.cjs`, $preflightTypesMap); class Store extends $stdlib.std.Resource { constructor($scope, $id, options) { @@ -234,6 +237,11 @@ class Store extends $stdlib.std.Resource { onSet(handler) { $macros.__MutArray_push(false, this.handlers, handler); } + static loadStaticData($scope) { + const path = (fs.Util.join($helpers.resolve(__dirname, "../../../node_modules/@winglibs/testfixture"), "example-data.txt")); + const contents = (fs.Util.readFile(path)); + return contents; + } static _toInflightType() { return ` require("${$helpers.normalPath(__dirname)}/inflight.Store-2.cjs")({ diff --git a/tools/hangar/__snapshots__/test_corpus/valid/factory.test.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/valid/factory.test.w_compile_tf-aws.md new file mode 100644 index 00000000000..fa1a4a6b587 --- /dev/null +++ b/tools/hangar/__snapshots__/test_corpus/valid/factory.test.w_compile_tf-aws.md @@ -0,0 +1,200 @@ +# [factory.test.w](../../../../../tests/valid/factory.test.w) | compile | tf-aws + +## inflight.$Closure1-1.cjs +```cjs +"use strict"; +const $helpers = require("@winglang/sdk/lib/helpers"); +const $macros = require("@winglang/sdk/lib/macros"); +module.exports = function({ $bucket, $expect_Util }) { + class $Closure1 { + constructor($args) { + const { } = $args; + const $obj = (...args) => this.handle(...args); + Object.setPrototypeOf($obj, this); + return $obj; + } + async handle() { + (await $bucket.put("hello", "world")); + (await $expect_Util.equal((await $bucket.list()).length, 1)); + } + } + return $Closure1; +} +//# sourceMappingURL=inflight.$Closure1-1.cjs.map +``` + +## inflight.$Closure2-1.cjs +```cjs +"use strict"; +const $helpers = require("@winglang/sdk/lib/helpers"); +const $macros = require("@winglang/sdk/lib/macros"); +module.exports = function({ $bucket, $expect_Util }) { + class $Closure2 { + constructor($args) { + const { } = $args; + const $obj = (...args) => this.handle(...args); + Object.setPrototypeOf($obj, this); + return $obj; + } + async handle() { + (await $bucket.put("yo", "sup")); + (await $expect_Util.equal((await $bucket.list()).length, 1)); + } + } + return $Closure2; +} +//# sourceMappingURL=inflight.$Closure2-1.cjs.map +``` + +## inflight.BucketFactory-1.cjs +```cjs +"use strict"; +const $helpers = require("@winglang/sdk/lib/helpers"); +const $macros = require("@winglang/sdk/lib/macros"); +module.exports = function({ }) { + class BucketFactory { + } + return BucketFactory; +} +//# sourceMappingURL=inflight.BucketFactory-1.cjs.map +``` + +## main.tf.json +```json +{ + "//": { + "metadata": { + "backend": "local", + "stackName": "root" + }, + "outputs": {} + }, + "provider": { + "aws": [ + {} + ] + }, + "resource": { + "aws_s3_bucket": { + "Bucket": { + "//": { + "metadata": { + "path": "root/Default/Default/Bucket/Default", + "uniqueId": "Bucket" + } + }, + "bucket_prefix": "bucket-c88fdc5f-", + "force_destroy": false + } + } + } +} +``` + +## preflight.cjs +```cjs +"use strict"; +const $stdlib = require('@winglang/sdk'); +const $macros = require("@winglang/sdk/lib/macros"); +const $platforms = ((s) => !s ? [] : s.split(';'))(process.env.WING_PLATFORMS); +const $outdir = process.env.WING_SYNTH_DIR ?? "."; +const $wing_is_test = process.env.WING_IS_TEST === "true"; +const std = $stdlib.std; +const $helpers = $stdlib.helpers; +const $extern = $helpers.createExternRequire(__dirname); +const $PlatformManager = new $stdlib.platform.PlatformManager({platformPaths: $platforms}); +class $Root extends $stdlib.std.Resource { + constructor($scope, $id) { + super($scope, $id); + $helpers.nodeof(this).root.$preflightTypesMap = { }; + let $preflightTypesMap = {}; + const cloud = $stdlib.cloud; + const constructs = require("constructs"); + const expect = $stdlib.expect; + $helpers.nodeof(this).root.$preflightTypesMap = $preflightTypesMap; + class BucketFactory extends $stdlib.std.Resource { + constructor($scope, $id, ) { + super($scope, $id); + } + static makeBucket($scope, scope) { + const bucket = globalThis.$ClassFactory.new("@winglang/sdk.cloud.Bucket", cloud.Bucket, scope, "Bucket"); + return bucket; + } + static _toInflightType() { + return ` + require("${$helpers.normalPath(__dirname)}/inflight.BucketFactory-1.cjs")({ + }) + `; + } + get _liftMap() { + return ({ + "$inflight_init": [ + ], + }); + } + } + class $Closure1 extends $stdlib.std.AutoIdResource { + _id = $stdlib.core.closureId(); + constructor($scope, $id, ) { + super($scope, $id); + $helpers.nodeof(this).hidden = true; + } + static _toInflightType() { + return ` + require("${$helpers.normalPath(__dirname)}/inflight.$Closure1-1.cjs")({ + $bucket: ${$stdlib.core.liftObject(bucket)}, + $expect_Util: ${$stdlib.core.liftObject($stdlib.core.toLiftableModuleType(globalThis.$ClassFactory.resolveType("@winglang/sdk.expect.Util") ?? expect.Util, "@winglang/sdk/expect", "Util"))}, + }) + `; + } + get _liftMap() { + return ({ + "handle": [ + [$stdlib.core.toLiftableModuleType(globalThis.$ClassFactory.resolveType("@winglang/sdk.expect.Util") ?? expect.Util, "@winglang/sdk/expect", "Util"), ["equal"]], + [bucket, [].concat(["put"], ["list"])], + ], + "$inflight_init": [ + [$stdlib.core.toLiftableModuleType(globalThis.$ClassFactory.resolveType("@winglang/sdk.expect.Util") ?? expect.Util, "@winglang/sdk/expect", "Util"), []], + [bucket, []], + ], + }); + } + } + class $Closure2 extends $stdlib.std.AutoIdResource { + _id = $stdlib.core.closureId(); + constructor($scope, $id, ) { + super($scope, $id); + $helpers.nodeof(this).hidden = true; + } + static _toInflightType() { + return ` + require("${$helpers.normalPath(__dirname)}/inflight.$Closure2-1.cjs")({ + $bucket: ${$stdlib.core.liftObject(bucket)}, + $expect_Util: ${$stdlib.core.liftObject($stdlib.core.toLiftableModuleType(globalThis.$ClassFactory.resolveType("@winglang/sdk.expect.Util") ?? expect.Util, "@winglang/sdk/expect", "Util"))}, + }) + `; + } + get _liftMap() { + return ({ + "handle": [ + [$stdlib.core.toLiftableModuleType(globalThis.$ClassFactory.resolveType("@winglang/sdk.expect.Util") ?? expect.Util, "@winglang/sdk/expect", "Util"), ["equal"]], + [bucket, [].concat(["put"], ["list"])], + ], + "$inflight_init": [ + [$stdlib.core.toLiftableModuleType(globalThis.$ClassFactory.resolveType("@winglang/sdk.expect.Util") ?? expect.Util, "@winglang/sdk/expect", "Util"), []], + [bucket, []], + ], + }); + } + } + const bucket = (BucketFactory.makeBucket(this, this)); + console.log($helpers.nodeof(bucket).path); + globalThis.$ClassFactory.new("@winglang/sdk.std.Test", std.Test, this, "test:can use bucket", new $Closure1(this, "$Closure1")); + globalThis.$ClassFactory.new("@winglang/sdk.std.Test", std.Test, this, "test:can use other bucket", new $Closure2(this, "$Closure2")); + } +} +const $APP = $PlatformManager.createApp({ outdir: $outdir, name: "factory.test", rootConstruct: $Root, isTestEnvironment: $wing_is_test, entrypointDir: process.env['WING_SOURCE_DIR'], rootId: process.env['WING_ROOT_ID'] }); +$APP.synth(); +//# sourceMappingURL=preflight.cjs.map +``` + diff --git a/tools/hangar/__snapshots__/test_corpus/valid/factory.test.w_test_sim.md b/tools/hangar/__snapshots__/test_corpus/valid/factory.test.w_test_sim.md new file mode 100644 index 00000000000..0f4cca3a147 --- /dev/null +++ b/tools/hangar/__snapshots__/test_corpus/valid/factory.test.w_test_sim.md @@ -0,0 +1,14 @@ +# [factory.test.w](../../../../../tests/valid/factory.test.w) | test | sim + +## stdout.log +```log +root/Default/Bucket +pass ─ factory.test.wsim » root/Default/test:can use bucket +pass ─ factory.test.wsim » root/Default/test:can use other bucket + +Tests 2 passed (2) +Snapshots 1 skipped +Test Files 1 passed (1) +Duration +``` + 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 9cc4696d8f3..98e4e785968 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 @@ -61,7 +61,10 @@ class Bar extends $stdlib.std.Resource { return "bar"; } static getSubdir($scope) { - return $helpers.resolveDirname(__dirname, "../../../subdir"); + return $helpers.resolve(__dirname, "../../../subdir"); + } + static getSubfile($scope) { + return $helpers.resolve(__dirname, "../../../subdir/bar.w"); } static _toInflightType() { return ` @@ -124,10 +127,13 @@ class $Root extends $stdlib.std.Resource { $helpers.nodeof(this).root.$preflightTypesMap = $preflightTypesMap; const path = "SHOULD_IGNORE"; const filename = "intrinsics.test.w"; - const currentFile = (fs.Util.join($helpers.resolveDirname(__dirname, "../../.."), filename)); + const currentFile = (fs.Util.join($helpers.resolve(__dirname, "../../.."), filename)); (expect.Util.equal(filename, (fs.Util.basename(currentFile)))); - (expect.Util.equal($helpers.resolveDirname(__dirname, "../../.."), (fs.Util.dirname(currentFile)))); - (expect.Util.equal((bar.Bar.getSubdir(this)), (fs.Util.join($helpers.resolveDirname(__dirname, "../../.."), "subdir")))); + (expect.Util.equal($helpers.resolve(__dirname, "../../.."), (fs.Util.dirname(currentFile)))); + (expect.Util.equal((bar.Bar.getSubdir(this)), (fs.Util.join($helpers.resolve(__dirname, "../../.."), "subdir")))); + (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")))); } } 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/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 e5b6418b572..0807cb9385e 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 @@ -37,8 +37,7 @@ class $Root extends $stdlib.std.Resource { 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",]}); $helpers.nodeof(this).root.$preflightTypesMap = $preflightTypesMap; - const app = $helpers.nodeof(this).app; - const myParams = $macros.__Struct_fromJson(false, MyParams, (app.parameters.read({ schema: $macros.__Struct_schema(false, MyParams, ) }))); + 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"); $helpers.assert($helpers.eq($macros.__Array_at(false, myParams.houses, 0).address, "123 Main St"), "myParams.houses.at(0).address == \"123 Main St\""); $helpers.assert($helpers.eq($macros.__Array_at(false, myParams.houses, 0).residents.length, 2), "myParams.houses.at(0).residents.length == 2"); 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 5ae6eaca6da..59ff984abb8 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 @@ -37,8 +37,7 @@ class $Root extends $stdlib.std.Resource { let $preflightTypesMap = {}; const MyParams = $stdlib.std.Struct._createJsonSchema({$id:"/MyParams",type:"object",properties:{foo:{type:"string"},meaningOfLife:{type:"number"},},required:["meaningOfLife",]}); $helpers.nodeof(this).root.$preflightTypesMap = $preflightTypesMap; - const app = $helpers.nodeof(this).app; - const myParams = $macros.__Struct_fromJson(false, MyParams, (app.parameters.read({ schema: $macros.__Struct_schema(false, MyParams, ) }))); + const myParams = $macros.__Struct_fromJson(false, MyParams, ($helpers.nodeof(this).app.parameters.read({ schema: $macros.__Struct_schema(false, MyParams, ) }))); { const $if_let_value = myParams.foo; if ($if_let_value != undefined) { diff --git a/tools/hangar/__snapshots__/test_corpus/valid/rootid.test.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/valid/rootid.test.w_compile_tf-aws.md index b41c890ce8b..e573da00c0e 100644 --- a/tools/hangar/__snapshots__/test_corpus/valid/rootid.test.w_compile_tf-aws.md +++ b/tools/hangar/__snapshots__/test_corpus/valid/rootid.test.w_compile_tf-aws.md @@ -90,7 +90,7 @@ class $Root extends $stdlib.std.Resource { }); } } - const rootId = $helpers.nodeof(this).app.node.id; + const rootId = $helpers.nodeof($helpers.nodeof(this).app).id; const envRootId = ((util.Util.tryEnv("WING_ROOT_ID")) ?? "root"); (expect.Util.equal(rootId, envRootId)); globalThis.$ClassFactory.new("@winglang/sdk.std.Test", std.Test, this, "test:root id", new $Closure1(this, "$Closure1"));