diff --git a/docs/docs/04-standard-library/std/node.md b/docs/docs/04-standard-library/std/node.md
index 86b8067d357..1b4021f6df3 100644
--- a/docs/docs/04-standard-library/std/node.md
+++ b/docs/docs/04-standard-library/std/node.md
@@ -640,6 +640,7 @@ prepended to the unique identifier.
| node
| constructs.Node
| The tree node. |
| entrypointDir
| str
| The directory of the entrypoint of the current program. |
| 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. |
---
@@ -680,6 +681,18 @@ isTestEnvironment: bool;
---
+##### `parameters`Required
+
+```wing
+parameters: ParameterRegistrar;
+```
+
+- *Type:* ParameterRegistrar
+
+The application's parameter registrar.
+
+---
+
##### `workdir`Required
```wing
diff --git a/examples/tests/invalid/parameters.test.w b/examples/tests/invalid/parameters.test.w
new file mode 100644
index 00000000000..71b00933910
--- /dev/null
+++ b/examples/tests/invalid/parameters.test.w
@@ -0,0 +1,12 @@
+let app = nodeof(this).app;
+
+struct MyParams {
+ foo: str;
+}
+
+app.parameters.addSchema(MyParams.schema());
+
+// Error: Parameter validation errors:
+// - must have required property 'foo'
+
+// (hint: make sure to use --values to provide the required parameters file)
diff --git a/examples/tests/invalid/struct_from_parameter.test.w b/examples/tests/invalid/struct_from_parameter.test.w
new file mode 100644
index 00000000000..908b478fcf4
--- /dev/null
+++ b/examples/tests/invalid/struct_from_parameter.test.w
@@ -0,0 +1,18 @@
+struct MyParams {
+ foo: str;
+ bar: bool;
+ 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());
+//Error: unable to parse MyParams:
+// - instance requires property "bar"
+// - instance requires property "baz"
+// - instance requires property "foo"
\ No newline at end of file
diff --git a/examples/tests/valid/parameters/nested/parameters.test.w b/examples/tests/valid/parameters/nested/parameters.test.w
new file mode 100644
index 00000000000..618b89979fc
--- /dev/null
+++ b/examples/tests/valid/parameters/nested/parameters.test.w
@@ -0,0 +1,21 @@
+struct Person {
+ name: str;
+ age: num;
+}
+
+struct House {
+ address: str;
+ residents: Array;
+}
+
+struct MyParams {
+ houses: Array;
+}
+
+let app = nodeof(this).app;
+
+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
diff --git a/examples/tests/valid/parameters/nested/wing.toml b/examples/tests/valid/parameters/nested/wing.toml
new file mode 100644
index 00000000000..155886a5249
--- /dev/null
+++ b/examples/tests/valid/parameters/nested/wing.toml
@@ -0,0 +1,13 @@
+[[houses]]
+address = "123 Main St"
+residents = [
+ {name = "John Doe", age = 30},
+ {name = "Jane Doe", age = 24}
+]
+
+[[houses]]
+address = "456 Elm St"
+residents = [
+ {name = "Tom Smith", age = 45},
+ {name = "Sue Smith", age = 40}
+]
\ No newline at end of file
diff --git a/examples/tests/valid/parameters/simple/parameters.test.w b/examples/tests/valid/parameters/simple/parameters.test.w
new file mode 100644
index 00000000000..740e1b2ecea
--- /dev/null
+++ b/examples/tests/valid/parameters/simple/parameters.test.w
@@ -0,0 +1,18 @@
+let app = nodeof(this).app;
+
+struct MyParams {
+ foo: str?;
+ meaningOfLife: num;
+}
+
+let myParams = MyParams.fromJson(app.parameters.read(schema: MyParams.schema()));
+
+if let foo = myParams.foo {
+ assert(false); // shouldnt happen
+} else {
+ assert(true);
+}
+
+let meaningOfLife = myParams.meaningOfLife;
+
+assert(meaningOfLife == 42);
\ No newline at end of file
diff --git a/examples/tests/valid/parameters/simple/wing.toml b/examples/tests/valid/parameters/simple/wing.toml
new file mode 100644
index 00000000000..54e0f73088f
--- /dev/null
+++ b/examples/tests/valid/parameters/simple/wing.toml
@@ -0,0 +1 @@
+meaningOfLife = 42
\ No newline at end of file
diff --git a/examples/tests/valid/struct_from_json.test.w b/examples/tests/valid/struct_from_json.test.w
index cd878088614..0bc62575891 100644
--- a/examples/tests/valid/struct_from_json.test.w
+++ b/examples/tests/valid/struct_from_json.test.w
@@ -282,7 +282,7 @@ assert(myStruct.m2.val == "10");
let schema = MyStruct.schema();
schema.validate(jMyStruct); // Should not throw exception
-let expectedSchema = {"id":"/MyStruct","type":"object","properties":{"m1":{"type":"object","properties":{"val":{"type":"number"}},"required":["val"]},"m2":{"type":"object","properties":{"val":{"type":"string"}},"required":["val"]}},"required":["m1","m2"]};
+let expectedSchema = {"$id":"/MyStruct","type":"object","properties":{"m1":{"type":"object","properties":{"val":{"type":"number"}},"required":["val"]},"m2":{"type":"object","properties":{"val":{"type":"string"}},"required":["val"]}},"required":["m1","m2"]};
assert(schema.asStr() == Json.stringify(expectedSchema));
diff --git a/libs/wingc/src/json_schema_generator.rs b/libs/wingc/src/json_schema_generator.rs
index e585879cdbe..ac4560cf7b9 100644
--- a/libs/wingc/src/json_schema_generator.rs
+++ b/libs/wingc/src/json_schema_generator.rs
@@ -88,7 +88,7 @@ impl JsonSchemaGenerator {
let mut code = CodeMaker::default();
code.open("{");
- code.line(format!("id: \"/{}\",", struct_.name));
+ code.line(format!("$id: \"/{}\",", struct_.name));
code.line("type: \"object\",".to_string());
code.open("properties: {");
diff --git a/libs/wingsdk/src/core/app.ts b/libs/wingsdk/src/core/app.ts
index 38c5e7ff3af..ec9a6f14eca 100644
--- a/libs/wingsdk/src/core/app.ts
+++ b/libs/wingsdk/src/core/app.ts
@@ -155,7 +155,7 @@ export abstract class App extends Construct implements IApp {
* Parameter registrar of composed platforms
* @internal
*/
- protected _platformParameters?: ParameterRegistrar;
+ protected _parameters?: ParameterRegistrar;
constructor(scope: Construct, id: string, props: AppProps) {
super(scope, id);
@@ -187,14 +187,11 @@ export abstract class App extends Construct implements IApp {
* The parameter registrar for the app, can be used to find and register
* parameter values that were provided to the wing application.
*/
- public get platformParameters() {
- if (!this._platformParameters) {
- this._platformParameters = new ParameterRegistrar(
- this,
- "ParameterRegistrar"
- );
+ public get parameters() {
+ if (!this._parameters) {
+ this._parameters = new ParameterRegistrar(this, "ParameterRegistrar");
}
- return this._platformParameters!;
+ return this._parameters!;
}
/**
diff --git a/libs/wingsdk/src/platform/parameter-registrar.ts b/libs/wingsdk/src/platform/parameter-registrar.ts
index fb979a77574..967687f061f 100644
--- a/libs/wingsdk/src/platform/parameter-registrar.ts
+++ b/libs/wingsdk/src/platform/parameter-registrar.ts
@@ -1,7 +1,19 @@
import Ajv from "ajv";
import { Construct } from "constructs";
-import { loadPlatformSpecificValues } from "./util";
-import { Node } from "../std";
+import {
+ loadPlatformSpecificValues,
+ extractFieldsFromSchema,
+ filterParametersBySchema,
+} from "./util";
+import { Json, Node } from "../std";
+
+/**
+ * Options for reading parameters
+ */
+export interface ReadParameterOptions {
+ /** Schema to limit the read to */
+ readonly schema?: any;
+}
/**
* Parameter Registrar
@@ -29,7 +41,7 @@ export class ParameterRegistrar extends Construct {
* @param path the path of the parameter
* @returns the value of the parameter
*/
- public getParameterValue(path: string): any {
+ public value(path: string): any {
if (this.parameterValueByPath[path] === undefined) {
// attempt to read the value from the raw parameters, then cache it
this.parameterValueByPath[path] = resolveValueFromPath(
@@ -41,13 +53,36 @@ export class ParameterRegistrar extends Construct {
return this.parameterValueByPath[path];
}
+ /**
+ * Read parameters
+ *
+ * @param options options for reading parameters
+ * @returns the schema as a string
+ */
+ public read(options?: ReadParameterOptions): Json {
+ if (options?.schema) {
+ this.addSchema(options.schema);
+ const fields = extractFieldsFromSchema(
+ options.schema._rawSchema // If a JsonSchema object is passed in, extract raw schema from it
+ ? options.schema._rawSchema
+ : options.schema
+ );
+ return filterParametersBySchema(fields, this._rawParameters);
+ }
+ return this._rawParameters as Json;
+ }
+
/**
* Add parameter schema to registrar
*
* @param schema schema to add to the registrar
*/
- public addParameterSchema(schema: any) {
- this.parameterSchemas.push(schema);
+ public addSchema(schema: any) {
+ // If a JsonSchema object is passed in, extract the raw schema from it
+ const schemaToAdd = schema._rawSchema ? schema._rawSchema : schema;
+ if (!this.parameterSchemas.includes(schemaToAdd)) {
+ this.parameterSchemas.push(schemaToAdd);
+ }
}
/**
@@ -58,14 +93,8 @@ export class ParameterRegistrar extends Construct {
* @param path the path to nest the schema under
* @param recursiveRequire whether or not to require all the nested properties
*/
- public addParameterSchemaAtPath(
- schema: any,
- path: string,
- recursiveRequire = false
- ) {
- this.addParameterSchema(
- this._nestSchemaUnderPath(schema, path, recursiveRequire)
- );
+ public addSchemaAtPath(schema: any, path: string, recursiveRequire = false) {
+ this.addSchema(this._nestSchemaUnderPath(schema, path, recursiveRequire));
}
/**
diff --git a/libs/wingsdk/src/platform/platform-manager.ts b/libs/wingsdk/src/platform/platform-manager.ts
index 321385ed188..53d5bc3ba88 100644
--- a/libs/wingsdk/src/platform/platform-manager.ts
+++ b/libs/wingsdk/src/platform/platform-manager.ts
@@ -148,10 +148,10 @@ export class PlatformManager {
newInstanceOverrides,
}) as App;
- let registrar = app.platformParameters;
+ let registrar = app.parameters;
parameterSchemas.forEach((schema) => {
- registrar.addParameterSchema(schema);
+ registrar.addSchema(schema);
});
return app;
diff --git a/libs/wingsdk/src/platform/util.ts b/libs/wingsdk/src/platform/util.ts
index 7b92a6c5c66..a76c969f2f7 100644
--- a/libs/wingsdk/src/platform/util.ts
+++ b/libs/wingsdk/src/platform/util.ts
@@ -42,6 +42,39 @@ export function parseValuesObjectFromString(values: string) {
return result;
}
+/**
+ * Extracts all fields from a JSON schema.
+ *
+ * @param schema the schema to extract fields from
+ * @returns a set of all fields in the schema
+ */
+export function extractFieldsFromSchema(schema: any): Set {
+ const fields = new Set();
+
+ if (schema.properties) {
+ for (const key of Object.keys(schema.properties)) {
+ fields.add(key);
+ }
+ }
+
+ return fields;
+}
+
+export function filterParametersBySchema(
+ fields: Set,
+ parameters: any
+): any {
+ const filtered: any = {};
+
+ for (const field of fields) {
+ if (parameters.hasOwnProperty(field)) {
+ filtered[field] = parameters[field];
+ }
+ }
+
+ return filtered;
+}
+
/**
* Loads platform-specific values that were passed in via CLI arguments and
* from a values file. CLI arguments take precedence over values file.
diff --git a/libs/wingsdk/src/shared-aws/domain.ts b/libs/wingsdk/src/shared-aws/domain.ts
index 432e04859fd..8b06e99092f 100644
--- a/libs/wingsdk/src/shared-aws/domain.ts
+++ b/libs/wingsdk/src/shared-aws/domain.ts
@@ -17,7 +17,7 @@ export class Domain extends cloud.Domain {
constructor(scope: Construct, id: string, props: cloud.DomainProps) {
super(scope, id, props);
- const parameters = App.of(scope).platformParameters;
+ const parameters = App.of(scope).parameters;
// Domain requires parameters from the user, so we need to add the parameter schemas to the registrar
let schema = {
@@ -44,17 +44,13 @@ export class Domain extends cloud.Domain {
},
};
- parameters.addParameterSchemaAtPath(schema, this.node.path, true);
+ parameters.addSchemaAtPath(schema, this.node.path, true);
- const iamCertificate = parameters.getParameterValue(
- `${this.node.path}/iamCertificate`
- );
- const acmCertificateArn = parameters.getParameterValue(
+ const iamCertificate = parameters.value(`${this.node.path}/iamCertificate`);
+ const acmCertificateArn = parameters.value(
`${this.node.path}/acmCertificateArn`
);
- const hostedZoneId = parameters.getParameterValue(
- `${this.node.path}/hostedZoneId`
- );
+ const hostedZoneId = parameters.value(`${this.node.path}/hostedZoneId`);
this._iamCertificate = iamCertificate;
this._hostedZoneId = hostedZoneId;
diff --git a/libs/wingsdk/src/std/bool.ts b/libs/wingsdk/src/std/bool.ts
index d5af712c398..74b9468c872 100644
--- a/libs/wingsdk/src/std/bool.ts
+++ b/libs/wingsdk/src/std/bool.ts
@@ -15,7 +15,7 @@ export class Boolean {
*/
public static fromJson(json: Json, options?: JsonValidationOptions): boolean {
const schema = JsonSchema._createJsonSchema({
- id: "bool",
+ $id: "bool",
type: "boolean",
} as any);
schema.validate(json, options);
diff --git a/libs/wingsdk/src/std/json_schema.ts b/libs/wingsdk/src/std/json_schema.ts
index cbcbd4b4db5..27c32678957 100644
--- a/libs/wingsdk/src/std/json_schema.ts
+++ b/libs/wingsdk/src/std/json_schema.ts
@@ -1,6 +1,10 @@
import { Validator } from "jsonschema";
import { Json, JsonValidationOptions } from "./json";
import { InflightClient } from "../core";
+import {
+ extractFieldsFromSchema,
+ filterParametersBySchema,
+} from "../platform/util";
/**
* Struct Schema
@@ -25,11 +29,12 @@ export class JsonSchema {
return new JsonSchema(schema);
}
- private jsonSchema: any;
+ /** @internal */
+ public _rawSchema: any;
private validator: Validator;
constructor(schema: Json) {
- this.jsonSchema = schema;
+ this._rawSchema = schema;
this.validator = new Validator();
}
@@ -44,10 +49,10 @@ export class JsonSchema {
return; // skip validation
}
- const result = this.validator.validate(obj, this.jsonSchema);
+ const result = this.validator.validate(obj, this._rawSchema);
if (result.errors.length > 0) {
throw new Error(
- `unable to parse ${this.jsonSchema.id.replace(
+ `unable to parse ${this._rawSchema.$id.replace(
"/",
""
)}:\n- ${result.errors.join("\n- ")}`
@@ -61,13 +66,16 @@ export class JsonSchema {
* @returns the schema as a string
*/
public asStr(): String {
- return JSON.stringify(this.jsonSchema);
+ return JSON.stringify(this._rawSchema);
}
/** @internal */
public _fromJson(obj: Json, validateOptions?: JsonValidationOptions) {
this.validate(obj, validateOptions);
- return obj;
+ const fields = extractFieldsFromSchema(this._rawSchema);
+ // Filter rawParameters based on the schema
+ const filteredParameters = filterParametersBySchema(fields, obj);
+ return filteredParameters;
}
/** @internal */
@@ -90,6 +98,6 @@ export class JsonSchema {
/** @internal */
public _toInflightType() {
- return JsonSchema._toInflightType(this.jsonSchema);
+ return JsonSchema._toInflightType(this._rawSchema);
}
}
diff --git a/libs/wingsdk/src/std/node.ts b/libs/wingsdk/src/std/node.ts
index f3154e2a27f..02498e8833a 100644
--- a/libs/wingsdk/src/std/node.ts
+++ b/libs/wingsdk/src/std/node.ts
@@ -7,6 +7,7 @@ import {
IValidation,
} from "constructs";
import { Connections } from "../core/connections";
+import { ParameterRegistrar } from "../platform";
const NODE_SYMBOL = Symbol.for("@winglang/sdk.std.Node");
export const APP_SYMBOL = Symbol.for("@winglang/sdk.std.Node/app");
@@ -452,6 +453,11 @@ export interface IApp extends IConstruct {
*/
readonly entrypointDir: string;
+ /**
+ * The application's parameter registrar
+ */
+ readonly parameters: ParameterRegistrar;
+
/**
* Generate a unique ID for the given scope and prefix. The newly generated ID is
* guaranteed to be unique within the given scope.
diff --git a/libs/wingsdk/src/std/number.ts b/libs/wingsdk/src/std/number.ts
index dd02ebc6bfc..f30a0b235f3 100644
--- a/libs/wingsdk/src/std/number.ts
+++ b/libs/wingsdk/src/std/number.ts
@@ -15,7 +15,7 @@ export class Number {
*/
public static fromJson(json: Json, options?: JsonValidationOptions): number {
const schema = JsonSchema._createJsonSchema({
- id: "num",
+ $id: "num",
type: "number",
} as any);
schema.validate(json, options);
diff --git a/libs/wingsdk/src/std/string.ts b/libs/wingsdk/src/std/string.ts
index f0d77b13ee4..82cff5cfe1e 100644
--- a/libs/wingsdk/src/std/string.ts
+++ b/libs/wingsdk/src/std/string.ts
@@ -26,7 +26,7 @@ export class String {
*/
public static fromJson(json: Json, options?: JsonValidationOptions): string {
const schema = JsonSchema._createJsonSchema({
- id: "string",
+ $id: "string",
type: "string",
} as any);
schema.validate(json, options);
diff --git a/libs/wingsdk/src/target-tf-aws/api.ts b/libs/wingsdk/src/target-tf-aws/api.ts
index 7877c6590cc..daa80e0534d 100644
--- a/libs/wingsdk/src/target-tf-aws/api.ts
+++ b/libs/wingsdk/src/target-tf-aws/api.ts
@@ -333,9 +333,7 @@ class WingRestApi extends Construct {
this.accountId = app.accountId;
// Check for PRIVATE API Gateway configuration
- let privateApiGateway = app.platformParameters.getParameterValue(
- "tf-aws/vpc_api_gateway"
- );
+ let privateApiGateway = app.parameters.value("tf-aws/vpc_api_gateway");
if (privateApiGateway === true) {
this.privateVpc = true;
const vpcResources = this._initVpcResources(app);
diff --git a/libs/wingsdk/src/target-tf-aws/app.ts b/libs/wingsdk/src/target-tf-aws/app.ts
index c45890d55f8..95af8724ca7 100644
--- a/libs/wingsdk/src/target-tf-aws/app.ts
+++ b/libs/wingsdk/src/target-tf-aws/app.ts
@@ -170,20 +170,17 @@ export class App extends CdktfApp {
return this._vpc;
}
- return this.platformParameters.getParameterValue(`${this._target}/vpc`) ===
- "existing"
+ return this.parameters.value(`${this._target}/vpc`) === "existing"
? this.importExistingVpc()
: this.createDefaultVpc();
}
private importExistingVpc(): DataAwsVpc {
- const vpcId = this.platformParameters.getParameterValue(
- `${this._target}/vpc_id`
- );
- const privateSubnetIds = this.platformParameters.getParameterValue(
+ const vpcId = this.parameters.value(`${this._target}/vpc_id`);
+ const privateSubnetIds = this.parameters.value(
`${this._target}/private_subnet_ids`
);
- const publicSubnetIds = this.platformParameters.getParameterValue(
+ const publicSubnetIds = this.parameters.value(
`${this._target}/public_subnet_ids`
);
diff --git a/libs/wingsdk/src/target-tf-aws/function.ts b/libs/wingsdk/src/target-tf-aws/function.ts
index fa2c17be175..6cfb6088d87 100644
--- a/libs/wingsdk/src/target-tf-aws/function.ts
+++ b/libs/wingsdk/src/target-tf-aws/function.ts
@@ -236,9 +236,7 @@ export class Function extends cloud.Function implements IAwsFunction {
architectures: ["arm64"],
});
- if (
- app.platformParameters.getParameterValue("tf-aws/vpc_lambda") === true
- ) {
+ if (app.parameters.value("tf-aws/vpc_lambda") === true) {
const sg = new SecurityGroup(this, `${id}SecurityGroup`, {
vpcId: app.vpc.id,
egress: [
diff --git a/libs/wingsdk/test/target-tf-aws/api.test.ts b/libs/wingsdk/test/target-tf-aws/api.test.ts
index 9bff61f1d24..d83966d4bbf 100644
--- a/libs/wingsdk/test/target-tf-aws/api.test.ts
+++ b/libs/wingsdk/test/target-tf-aws/api.test.ts
@@ -36,7 +36,7 @@ test("api with GET route at root", () => {
test("api will be private when vpc_api_gateway is true", () => {
// GIVEN
const app = new tfaws.App({ outdir: mkdtemp(), entrypointDir: __dirname });
- const parameters = app.platformParameters;
+ const parameters = app.parameters;
parameters._rawParameters["tf-aws"] = {
vpc: "new",
vpc_api_gateway: true,
diff --git a/libs/wingsdk/test/target-tf-aws/function.test.ts b/libs/wingsdk/test/target-tf-aws/function.test.ts
index ce7c99a4401..21158b84ad8 100644
--- a/libs/wingsdk/test/target-tf-aws/function.test.ts
+++ b/libs/wingsdk/test/target-tf-aws/function.test.ts
@@ -45,7 +45,7 @@ test("basic function", () => {
test("function will be behind a vpc when vpc_lambda is set to true", () => {
// GIVEN
const app = new tfaws.App({ outdir: mkdtemp(), entrypointDir: __dirname });
- const parameters = app.platformParameters;
+ const parameters = app.parameters;
parameters._rawParameters["tf-aws"] = {
vpc: "new",
vpc_lambda: true,
diff --git a/tools/hangar/__snapshots__/invalid.ts.snap b/tools/hangar/__snapshots__/invalid.ts.snap
index da92ba95642..e894fd962d1 100644
--- a/tools/hangar/__snapshots__/invalid.ts.snap
+++ b/tools/hangar/__snapshots__/invalid.ts.snap
@@ -3061,6 +3061,19 @@ Duration "
exports[`panic.test.w 2`] = `"Panicked, backtrace not captured: Unsupported"`;
+exports[`parameters.test.w 1`] = `
+"Error: Parameter validation errors:
+- must have required property 'foo'
+
+(hint: make sure to use --values to provide the required parameters file)
+
+
+
+Tests 1 failed (1)
+Test Files 1 failed (1)
+Duration "
+`;
+
exports[`phase_mismatch.test.w 1`] = `
"error: Expected type to be \\"inflight (num): num\\", but got \\"preflight (n: num): num\\" instead
--> ../../../examples/tests/invalid/phase_mismatch.test.w:2:10
@@ -3750,6 +3763,25 @@ error: Expected between 2 and 3 positional arguments or named arguments for the
+Tests 1 failed (1)
+Test Files 1 failed (1)
+Duration "
+`;
+
+exports[`struct_from_parameter.test.w 1`] = `
+"Error: unable to parse MyParams:
+- instance requires property \\"bar\\"
+- instance requires property \\"baz\\"
+- instance requires property \\"foo\\"
+ --> ../../../examples/tests/invalid/struct_from_parameter.test.w:14:1
+ | // technically we never enforced the parameters must have been
+ | // provided
+ |
+14 | MyParams.fromJson(app.parameters.read());
+ | ^
+at /struct_from_parameter.test.w:14:1
+
+
Tests 1 failed (1)
Test Files 1 failed (1)
Duration "
diff --git a/tools/hangar/__snapshots__/test_corpus/valid/apps_with_params/nested_params/parameters.test.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/valid/apps_with_params/nested_params/parameters.test.w_compile_tf-aws.md
new file mode 100644
index 00000000000..b39b3583e47
--- /dev/null
+++ b/tools/hangar/__snapshots__/test_corpus/valid/apps_with_params/nested_params/parameters.test.w_compile_tf-aws.md
@@ -0,0 +1,48 @@
+# [parameters.test.w](../../../../../../../examples/tests/valid/apps_with_params/nested_params/parameters.test.w) | compile | tf-aws
+
+## main.tf.json
+```json
+{
+ "//": {
+ "metadata": {
+ "backend": "local",
+ "stackName": "root",
+ "version": "0.20.3"
+ },
+ "outputs": {}
+ },
+ "provider": {
+ "aws": [
+ {}
+ ]
+ }
+}
+```
+
+## preflight.js
+```js
+"use strict";
+const $stdlib = require('@winglang/sdk');
+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;
+class $Root extends $stdlib.std.Resource {
+ constructor($scope, $id) {
+ super($scope, $id);
+ 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 app = $helpers.nodeof(this).app;
+ (app.parameters.addSchema(MyParams));
+ const myParams = MyParams._fromJson((app.parameters.json()));
+ $helpers.assert($helpers.eq(myParams.houses.length, 2), "myParams.houses.length == 2");
+ $helpers.assert($helpers.eq(((arr, index) => { if (index < 0 || index >= arr.length) throw new Error("Index out of bounds"); return arr[index]; })(myParams.houses, 0).address, "123 Main St"), "myParams.houses.at(0).address == \"123 Main St\"");
+ $helpers.assert($helpers.eq(((arr, index) => { if (index < 0 || index >= arr.length) throw new Error("Index out of bounds"); return arr[index]; })(myParams.houses, 0).residents.length, 2), "myParams.houses.at(0).residents.length == 2");
+ }
+}
+const $PlatformManager = new $stdlib.platform.PlatformManager({platformPaths: $platforms});
+const $APP = $PlatformManager.createApp({ outdir: $outdir, name: "parameters.test", rootConstruct: $Root, isTestEnvironment: $wing_is_test, entrypointDir: process.env['WING_SOURCE_DIR'], rootId: process.env['WING_ROOT_ID'] });
+$APP.synth();
+//# sourceMappingURL=preflight.js.map
+```
+
diff --git a/tools/hangar/__snapshots__/test_corpus/valid/apps_with_params/nested_params/parameters.test.w_test_sim.md b/tools/hangar/__snapshots__/test_corpus/valid/apps_with_params/nested_params/parameters.test.w_test_sim.md
new file mode 100644
index 00000000000..9af2392c17f
--- /dev/null
+++ b/tools/hangar/__snapshots__/test_corpus/valid/apps_with_params/nested_params/parameters.test.w_test_sim.md
@@ -0,0 +1,12 @@
+# [parameters.test.w](../../../../../../../examples/tests/valid/apps_with_params/nested_params/parameters.test.w) | test | sim
+
+## stdout.log
+```log
+pass ─ parameters.test.wsim (no tests)
+
+
+Tests 1 passed (1)
+Test Files 1 passed (1)
+Duration
+```
+
diff --git a/tools/hangar/__snapshots__/test_corpus/valid/apps_with_params/simple_test/parameters.test.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/valid/apps_with_params/simple_test/parameters.test.w_compile_tf-aws.md
new file mode 100644
index 00000000000..618e28b7345
--- /dev/null
+++ b/tools/hangar/__snapshots__/test_corpus/valid/apps_with_params/simple_test/parameters.test.w_compile_tf-aws.md
@@ -0,0 +1,57 @@
+# [parameters.test.w](../../../../../../../examples/tests/valid/apps_with_params/simple_test/parameters.test.w) | compile | tf-aws
+
+## main.tf.json
+```json
+{
+ "//": {
+ "metadata": {
+ "backend": "local",
+ "stackName": "root",
+ "version": "0.20.3"
+ },
+ "outputs": {}
+ },
+ "provider": {
+ "aws": [
+ {}
+ ]
+ }
+}
+```
+
+## preflight.js
+```js
+"use strict";
+const $stdlib = require('@winglang/sdk');
+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;
+class $Root extends $stdlib.std.Resource {
+ constructor($scope, $id) {
+ super($scope, $id);
+ const MyParams = $stdlib.std.Struct._createJsonSchema({$id:"/MyParams",type:"object",properties:{foo:{type:"string"},meaningOfLife:{type:"number"},},required:["meaningOfLife",]});
+ const app = $helpers.nodeof(this).app;
+ (app.parameters.addSchema(MyParams));
+ const myParams = MyParams._fromJson((app.parameters.json()));
+ {
+ const $if_let_value = myParams.foo;
+ if ($if_let_value != undefined) {
+ const foo = $if_let_value;
+ $helpers.assert(false, "false");
+ }
+ else {
+ $helpers.assert(true, "true");
+ }
+ }
+ const meaningOfLife = myParams.meaningOfLife;
+ $helpers.assert($helpers.eq(meaningOfLife, 42), "meaningOfLife == 42");
+ }
+}
+const $PlatformManager = new $stdlib.platform.PlatformManager({platformPaths: $platforms});
+const $APP = $PlatformManager.createApp({ outdir: $outdir, name: "parameters.test", rootConstruct: $Root, isTestEnvironment: $wing_is_test, entrypointDir: process.env['WING_SOURCE_DIR'], rootId: process.env['WING_ROOT_ID'] });
+$APP.synth();
+//# sourceMappingURL=preflight.js.map
+```
+
diff --git a/tools/hangar/__snapshots__/test_corpus/valid/apps_with_params/simple_test/parameters.test.w_test_sim.md b/tools/hangar/__snapshots__/test_corpus/valid/apps_with_params/simple_test/parameters.test.w_test_sim.md
new file mode 100644
index 00000000000..8d5a0d65458
--- /dev/null
+++ b/tools/hangar/__snapshots__/test_corpus/valid/apps_with_params/simple_test/parameters.test.w_test_sim.md
@@ -0,0 +1,12 @@
+# [parameters.test.w](../../../../../../../examples/tests/valid/apps_with_params/simple_test/parameters.test.w) | test | sim
+
+## stdout.log
+```log
+pass ─ parameters.test.wsim (no tests)
+
+
+Tests 1 passed (1)
+Test Files 1 passed (1)
+Duration
+```
+
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 2a75aef7ff9..e8c58f3d390 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
@@ -127,7 +127,7 @@ const cloud = $stdlib.cloud;
class $Root extends $stdlib.std.Resource {
constructor($scope, $id) {
super($scope, $id);
- 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",]});
class Super extends $stdlib.std.Resource {
constructor($scope, $id, ) {
super($scope, $id);
diff --git a/tools/hangar/__snapshots__/test_corpus/valid/parameters.test.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/valid/parameters.test.w_compile_tf-aws.md
new file mode 100644
index 00000000000..ad0d76a840d
--- /dev/null
+++ b/tools/hangar/__snapshots__/test_corpus/valid/parameters.test.w_compile_tf-aws.md
@@ -0,0 +1,56 @@
+# [parameters.test.w](../../../../../examples/tests/valid/parameters.test.w) | compile | tf-aws
+
+## main.tf.json
+```json
+{
+ "//": {
+ "metadata": {
+ "backend": "local",
+ "stackName": "root",
+ "version": "0.20.3"
+ },
+ "outputs": {}
+ },
+ "provider": {
+ "aws": [
+ {}
+ ]
+ }
+}
+```
+
+## preflight.js
+```js
+"use strict";
+const $stdlib = require('@winglang/sdk');
+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;
+class $Root extends $stdlib.std.Resource {
+ constructor($scope, $id) {
+ super($scope, $id);
+ const MyParams = $stdlib.std.Struct._createJsonSchema({$id:"/MyParams",type:"object",properties:{foo:{type:"string"},},required:[]});
+ const app = $helpers.nodeof(this).app;
+ const registrar = app.parameters;
+ (registrar.addSchema(MyParams));
+ const foo = (registrar.getValue("foo"));
+ {
+ const $if_let_value = foo;
+ if ($if_let_value != undefined) {
+ const foo = $if_let_value;
+ $helpers.assert(false, "false");
+ }
+ else {
+ $helpers.assert(true, "true");
+ }
+ }
+ }
+}
+const $PlatformManager = new $stdlib.platform.PlatformManager({platformPaths: $platforms});
+const $APP = $PlatformManager.createApp({ outdir: $outdir, name: "parameters.test", rootConstruct: $Root, isTestEnvironment: $wing_is_test, entrypointDir: process.env['WING_SOURCE_DIR'], rootId: process.env['WING_ROOT_ID'] });
+$APP.synth();
+//# sourceMappingURL=preflight.js.map
+```
+
diff --git a/tools/hangar/__snapshots__/test_corpus/valid/parameters.test.w_test_sim.md b/tools/hangar/__snapshots__/test_corpus/valid/parameters.test.w_test_sim.md
new file mode 100644
index 00000000000..bfdf85bcb57
--- /dev/null
+++ b/tools/hangar/__snapshots__/test_corpus/valid/parameters.test.w_test_sim.md
@@ -0,0 +1,12 @@
+# [parameters.test.w](../../../../../examples/tests/valid/parameters.test.w) | test | sim
+
+## stdout.log
+```log
+pass ─ parameters.test.wsim (no tests)
+
+
+Tests 1 passed (1)
+Test Files 1 passed (1)
+Duration
+```
+
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
new file mode 100644
index 00000000000..14640a022b0
--- /dev/null
+++ b/tools/hangar/__snapshots__/test_corpus/valid/parameters/nested/parameters.test.w_compile_tf-aws.md
@@ -0,0 +1,47 @@
+# [parameters.test.w](../../../../../../../examples/tests/valid/parameters/nested/parameters.test.w) | compile | tf-aws
+
+## main.tf.json
+```json
+{
+ "//": {
+ "metadata": {
+ "backend": "local",
+ "stackName": "root",
+ "version": "0.20.3"
+ },
+ "outputs": {}
+ },
+ "provider": {
+ "aws": [
+ {}
+ ]
+ }
+}
+```
+
+## preflight.js
+```js
+"use strict";
+const $stdlib = require('@winglang/sdk');
+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;
+class $Root extends $stdlib.std.Resource {
+ constructor($scope, $id) {
+ super($scope, $id);
+ 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 app = $helpers.nodeof(this).app;
+ const myParams = MyParams._fromJson((app.parameters.read({ schema: MyParams })));
+ $helpers.assert($helpers.eq(myParams.houses.length, 2), "myParams.houses.length == 2");
+ $helpers.assert($helpers.eq(((arr, index) => { if (index < 0 || index >= arr.length) throw new Error("Index out of bounds"); return arr[index]; })(myParams.houses, 0).address, "123 Main St"), "myParams.houses.at(0).address == \"123 Main St\"");
+ $helpers.assert($helpers.eq(((arr, index) => { if (index < 0 || index >= arr.length) throw new Error("Index out of bounds"); return arr[index]; })(myParams.houses, 0).residents.length, 2), "myParams.houses.at(0).residents.length == 2");
+ }
+}
+const $PlatformManager = new $stdlib.platform.PlatformManager({platformPaths: $platforms});
+const $APP = $PlatformManager.createApp({ outdir: $outdir, name: "parameters.test", rootConstruct: $Root, isTestEnvironment: $wing_is_test, entrypointDir: process.env['WING_SOURCE_DIR'], rootId: process.env['WING_ROOT_ID'] });
+$APP.synth();
+//# sourceMappingURL=preflight.js.map
+```
+
diff --git a/tools/hangar/__snapshots__/test_corpus/valid/parameters/nested/parameters.test.w_test_sim.md b/tools/hangar/__snapshots__/test_corpus/valid/parameters/nested/parameters.test.w_test_sim.md
new file mode 100644
index 00000000000..39af5eaaa1f
--- /dev/null
+++ b/tools/hangar/__snapshots__/test_corpus/valid/parameters/nested/parameters.test.w_test_sim.md
@@ -0,0 +1,12 @@
+# [parameters.test.w](../../../../../../../examples/tests/valid/parameters/nested/parameters.test.w) | test | sim
+
+## stdout.log
+```log
+pass ─ parameters.test.wsim (no tests)
+
+
+Tests 1 passed (1)
+Test Files 1 passed (1)
+Duration
+```
+
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
new file mode 100644
index 00000000000..6ed099b6449
--- /dev/null
+++ b/tools/hangar/__snapshots__/test_corpus/valid/parameters/simple/parameters.test.w_compile_tf-aws.md
@@ -0,0 +1,56 @@
+# [parameters.test.w](../../../../../../../examples/tests/valid/parameters/simple/parameters.test.w) | compile | tf-aws
+
+## main.tf.json
+```json
+{
+ "//": {
+ "metadata": {
+ "backend": "local",
+ "stackName": "root",
+ "version": "0.20.3"
+ },
+ "outputs": {}
+ },
+ "provider": {
+ "aws": [
+ {}
+ ]
+ }
+}
+```
+
+## preflight.js
+```js
+"use strict";
+const $stdlib = require('@winglang/sdk');
+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;
+class $Root extends $stdlib.std.Resource {
+ constructor($scope, $id) {
+ super($scope, $id);
+ const MyParams = $stdlib.std.Struct._createJsonSchema({$id:"/MyParams",type:"object",properties:{foo:{type:"string"},meaningOfLife:{type:"number"},},required:["meaningOfLife",]});
+ const app = $helpers.nodeof(this).app;
+ const myParams = MyParams._fromJson((app.parameters.read({ schema: MyParams })));
+ {
+ const $if_let_value = myParams.foo;
+ if ($if_let_value != undefined) {
+ const foo = $if_let_value;
+ $helpers.assert(false, "false");
+ }
+ else {
+ $helpers.assert(true, "true");
+ }
+ }
+ const meaningOfLife = myParams.meaningOfLife;
+ $helpers.assert($helpers.eq(meaningOfLife, 42), "meaningOfLife == 42");
+ }
+}
+const $PlatformManager = new $stdlib.platform.PlatformManager({platformPaths: $platforms});
+const $APP = $PlatformManager.createApp({ outdir: $outdir, name: "parameters.test", rootConstruct: $Root, isTestEnvironment: $wing_is_test, entrypointDir: process.env['WING_SOURCE_DIR'], rootId: process.env['WING_ROOT_ID'] });
+$APP.synth();
+//# sourceMappingURL=preflight.js.map
+```
+
diff --git a/tools/hangar/__snapshots__/test_corpus/valid/parameters/simple/parameters.test.w_test_sim.md b/tools/hangar/__snapshots__/test_corpus/valid/parameters/simple/parameters.test.w_test_sim.md
new file mode 100644
index 00000000000..c758692e008
--- /dev/null
+++ b/tools/hangar/__snapshots__/test_corpus/valid/parameters/simple/parameters.test.w_test_sim.md
@@ -0,0 +1,12 @@
+# [parameters.test.w](../../../../../../../examples/tests/valid/parameters/simple/parameters.test.w) | test | sim
+
+## stdout.log
+```log
+pass ─ parameters.test.wsim (no tests)
+
+
+Tests 1 passed (1)
+Test Files 1 passed (1)
+Duration
+```
+
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 26f928a21ed..52865eb4974 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
@@ -182,14 +182,14 @@ const otherExternalStructs = require("./preflight.structs2-2.js");
class $Root extends $stdlib.std.Resource {
constructor($scope, $id) {
super($scope, $id);
- 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:{m1:{type:"object",properties:{val:{type:"number"},},required:["val",]},m2:{type:"object",properties:{val:{type:"string"},},required:["val",]},},required:["m1","m2",]});
- const SomeStruct = $stdlib.std.Struct._createJsonSchema({id:"/SomeStruct",type:"object",properties:{foo:{type:"string"},},required:["foo",]});
- const Student = $stdlib.std.Struct._createJsonSchema({id:"/Student",type:"object",properties:{additionalData:{type:"object"},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_BucketProps = $stdlib.std.Struct._createJsonSchema({id:"/BucketProps",type:"object",properties:{public:{type:"boolean"},},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",]});
+ 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:{m1:{type:"object",properties:{val:{type:"number"},},required:["val",]},m2:{type:"object",properties:{val:{type:"string"},},required:["val",]},},required:["m1","m2",]});
+ const SomeStruct = $stdlib.std.Struct._createJsonSchema({$id:"/SomeStruct",type:"object",properties:{foo:{type:"string"},},required:["foo",]});
+ const Student = $stdlib.std.Struct._createJsonSchema({$id:"/Student",type:"object",properties:{additionalData:{type:"object"},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_BucketProps = $stdlib.std.Struct._createJsonSchema({$id:"/BucketProps",type:"object",properties:{public:{type:"boolean"},},required:[]});
+ const externalStructs_MyOtherStruct = $stdlib.std.Struct._createJsonSchema({$id:"/MyOtherStruct",type:"object",properties:{data:{type:"object",properties:{val:{type:"number"},},required:["val",]},},required:["data",]});
class $Closure1 extends $stdlib.std.AutoIdResource {
_id = $stdlib.core.closureId();
constructor($scope, $id, ) {
@@ -488,7 +488,7 @@ class $Root extends $stdlib.std.Resource {
$helpers.assert($helpers.eq(myStruct.m2.val, "10"), "myStruct.m2.val == \"10\"");
const schema = MyStruct;
(schema.validate(jMyStruct));
- const expectedSchema = ({"id": "/MyStruct", "type": "object", "properties": ({"m1": ({"type": "object", "properties": ({"val": ({"type": "number"})}), "required": ["val"]}), "m2": ({"type": "object", "properties": ({"val": ({"type": "string"})}), "required": ["val"]})}), "required": ["m1", "m2"]});
+ const expectedSchema = ({"$id": "/MyStruct", "type": "object", "properties": ({"m1": ({"type": "object", "properties": ({"val": ({"type": "number"})}), "required": ["val"]}), "m2": ({"type": "object", "properties": ({"val": ({"type": "string"})}), "required": ["val"]})}), "required": ["m1", "m2"]});
$helpers.assert($helpers.eq((schema.asStr()), ((json, opts) => { return JSON.stringify(json, null, opts?.indent) })(expectedSchema)), "schema.asStr() == Json.stringify(expectedSchema)");
this.node.root.new("@winglang/sdk.std.Test", std.Test, this, "test:inflight schema usage", new $Closure4(this, "$Closure4"));
(std.String.fromJson(10, { unsafe: true }));
@@ -511,14 +511,14 @@ $APP.synth();
const $stdlib = require('@winglang/sdk');
const std = $stdlib.std;
const $helpers = $stdlib.helpers;
-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:{m1:{type:"object",properties:{val:{type:"number"},},required:["val",]},m2:{type:"object",properties:{val:{type:"string"},},required:["val",]},},required:["m1","m2",]});
-const SomeStruct = $stdlib.std.Struct._createJsonSchema({id:"/SomeStruct",type:"object",properties:{foo:{type:"string"},},required:["foo",]});
-const Student = $stdlib.std.Struct._createJsonSchema({id:"/Student",type:"object",properties:{additionalData:{type:"object"},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_BucketProps = $stdlib.std.Struct._createJsonSchema({id:"/BucketProps",type:"object",properties:{public:{type:"boolean"},},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",]});
+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:{m1:{type:"object",properties:{val:{type:"number"},},required:["val",]},m2:{type:"object",properties:{val:{type:"string"},},required:["val",]},},required:["m1","m2",]});
+const SomeStruct = $stdlib.std.Struct._createJsonSchema({$id:"/SomeStruct",type:"object",properties:{foo:{type:"string"},},required:["foo",]});
+const Student = $stdlib.std.Struct._createJsonSchema({$id:"/Student",type:"object",properties:{additionalData:{type:"object"},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_BucketProps = $stdlib.std.Struct._createJsonSchema({$id:"/BucketProps",type:"object",properties:{public:{type:"boolean"},},required:[]});
+const externalStructs_MyOtherStruct = $stdlib.std.Struct._createJsonSchema({$id:"/MyOtherStruct",type:"object",properties:{data:{type:"object",properties:{val:{type:"number"},},required:["val",]},},required:["data",]});
module.exports = { };
//# sourceMappingURL=preflight.structs-1.js.map
```
@@ -529,14 +529,14 @@ module.exports = { };
const $stdlib = require('@winglang/sdk');
const std = $stdlib.std;
const $helpers = $stdlib.helpers;
-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:{m1:{type:"object",properties:{val:{type:"number"},},required:["val",]},m2:{type:"object",properties:{val:{type:"string"},},required:["val",]},},required:["m1","m2",]});
-const SomeStruct = $stdlib.std.Struct._createJsonSchema({id:"/SomeStruct",type:"object",properties:{foo:{type:"string"},},required:["foo",]});
-const Student = $stdlib.std.Struct._createJsonSchema({id:"/Student",type:"object",properties:{additionalData:{type:"object"},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_BucketProps = $stdlib.std.Struct._createJsonSchema({id:"/BucketProps",type:"object",properties:{public:{type:"boolean"},},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",]});
+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:{m1:{type:"object",properties:{val:{type:"number"},},required:["val",]},m2:{type:"object",properties:{val:{type:"string"},},required:["val",]},},required:["m1","m2",]});
+const SomeStruct = $stdlib.std.Struct._createJsonSchema({$id:"/SomeStruct",type:"object",properties:{foo:{type:"string"},},required:["foo",]});
+const Student = $stdlib.std.Struct._createJsonSchema({$id:"/Student",type:"object",properties:{additionalData:{type:"object"},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_BucketProps = $stdlib.std.Struct._createJsonSchema({$id:"/BucketProps",type:"object",properties:{public:{type:"boolean"},},required:[]});
+const externalStructs_MyOtherStruct = $stdlib.std.Struct._createJsonSchema({$id:"/MyOtherStruct",type:"object",properties:{data:{type:"object",properties:{val:{type:"number"},},required:["val",]},},required:["data",]});
class UsesStructInImportedFile extends $stdlib.std.Resource {
constructor($scope, $id, ) {
super($scope, $id);
diff --git a/tools/hangar/__snapshots__/test_corpus/valid/wing_parameters/parameters.test.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/valid/wing_parameters/parameters.test.w_compile_tf-aws.md
new file mode 100644
index 00000000000..bd6254aff1f
--- /dev/null
+++ b/tools/hangar/__snapshots__/test_corpus/valid/wing_parameters/parameters.test.w_compile_tf-aws.md
@@ -0,0 +1,56 @@
+# [parameters.test.w](../../../../../../examples/tests/valid/wing_parameters/parameters.test.w) | compile | tf-aws
+
+## main.tf.json
+```json
+{
+ "//": {
+ "metadata": {
+ "backend": "local",
+ "stackName": "root",
+ "version": "0.20.3"
+ },
+ "outputs": {}
+ },
+ "provider": {
+ "aws": [
+ {}
+ ]
+ }
+}
+```
+
+## preflight.js
+```js
+"use strict";
+const $stdlib = require('@winglang/sdk');
+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;
+class $Root extends $stdlib.std.Resource {
+ constructor($scope, $id) {
+ super($scope, $id);
+ const MyParams = $stdlib.std.Struct._createJsonSchema({$id:"/MyParams",type:"object",properties:{bar:{type:"string"},foo:{type:"string"},},required:["bar",]});
+ const app = $helpers.nodeof(this).app;
+ const registrar = app.parameters;
+ (registrar.addSchema(MyParams));
+ const foo = (registrar.getValue("foo"));
+ {
+ const $if_let_value = foo;
+ if ($if_let_value != undefined) {
+ const foo = $if_let_value;
+ $helpers.assert(false, "false");
+ }
+ else {
+ $helpers.assert(true, "true");
+ }
+ }
+ }
+}
+const $PlatformManager = new $stdlib.platform.PlatformManager({platformPaths: $platforms});
+const $APP = $PlatformManager.createApp({ outdir: $outdir, name: "parameters.test", rootConstruct: $Root, isTestEnvironment: $wing_is_test, entrypointDir: process.env['WING_SOURCE_DIR'], rootId: process.env['WING_ROOT_ID'] });
+$APP.synth();
+//# sourceMappingURL=preflight.js.map
+```
+
diff --git a/tools/hangar/__snapshots__/test_corpus/valid/wing_parameters/parameters.test.w_test_sim.md b/tools/hangar/__snapshots__/test_corpus/valid/wing_parameters/parameters.test.w_test_sim.md
new file mode 100644
index 00000000000..38a805d41f3
--- /dev/null
+++ b/tools/hangar/__snapshots__/test_corpus/valid/wing_parameters/parameters.test.w_test_sim.md
@@ -0,0 +1,12 @@
+# [parameters.test.w](../../../../../../examples/tests/valid/wing_parameters/parameters.test.w) | test | sim
+
+## stdout.log
+```log
+pass ─ parameters.test.wsim (no tests)
+
+
+Tests 1 passed (1)
+Test Files 1 passed (1)
+Duration
+```
+
diff --git a/tools/hangar/src/generate_tests.ts b/tools/hangar/src/generate_tests.ts
index c863edac72f..a38c5b4223c 100644
--- a/tools/hangar/src/generate_tests.ts
+++ b/tools/hangar/src/generate_tests.ts
@@ -1,5 +1,5 @@
import { mkdirSync, readdirSync, rmSync, writeFileSync } from "fs";
-import { sdkTestsDir, validTestDir } from "./paths";
+import { appWithParamsDir, sdkTestsDir, validTestDir } from "./paths";
import { join, extname } from "path";
import { parseMetaCommentFromPath } from "./meta_comment";
@@ -96,6 +96,12 @@ generateTests({
isRecursive: false,
includeJavaScriptInSnapshots: true,
});
+generateTests({
+ sourceDir: appWithParamsDir,
+ destination: generatedTestDir,
+ isRecursive: true,
+ includeJavaScriptInSnapshots: true,
+});
generateTests({
sourceDir: sdkTestsDir,
destination: generatedSDKTestDir,
diff --git a/tools/hangar/src/paths.ts b/tools/hangar/src/paths.ts
index b5a2051f878..5b8f5db8491 100644
--- a/tools/hangar/src/paths.ts
+++ b/tools/hangar/src/paths.ts
@@ -5,6 +5,7 @@ export const repoRoot = path.resolve(__dirname, "../../..");
export const examplesDir = path.join(repoRoot, "examples");
export const testDir = path.join(examplesDir, "tests");
export const validTestDir = path.join(testDir, "valid");
+export const appWithParamsDir = path.join(validTestDir, "parameters");
export const sdkTestsDir = path.join(testDir, "sdk_tests");
export const compatibilityTestsDir = path.join(testDir, "sdk_tests/counter");
export const platformsDir = path.join(validTestDir, "platforms");