json-as 0.9.4 → 0.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,9 +11,23 @@ jobs:
11
11
  - uses: actions/checkout@v4
12
12
  - uses: actions/setup-node@v3
13
13
  with:
14
- node-version: 16
15
- - run: npm ci
16
- - run: npm test
14
+ node-version: 16
15
+
16
+ - name: Install Wasmtime
17
+ uses: jcbhmr/setup-wasmtime@v2
18
+
19
+ - name: Setup Node.js
20
+ uses: actions/setup-node@v2
21
+
22
+ - name: Install dependencies
23
+ if: steps.node-cache.outputs.cache-hit != 'true'
24
+ run: yarn
25
+
26
+ - name: Build tests
27
+ run: yarn run tests:build
28
+
29
+ - name: Perform tests
30
+ run: yarn run test
17
31
 
18
32
  publish-gpr:
19
33
  needs: build
@@ -25,7 +39,7 @@ jobs:
25
39
  - uses: actions/checkout@v4
26
40
  - uses: actions/setup-node@v3
27
41
  with:
28
- node-version: 16
42
+ node-version: 22
29
43
  registry-url: https://npm.pkg.github.com/
30
44
  - run: npm ci
31
45
  - run: npm publish
package/CHANGELOG CHANGED
@@ -9,5 +9,6 @@ v0.9.1 - Fix #71
9
9
  v0.9.2 - Fix #75 + Build sizes significantly reduced
10
10
  v0.9.3 - Fix #76
11
11
  v0.9.4 - Fix #77
12
+ v0.9.5 - Fix #46
12
13
 
13
14
  [UNRELEASED] v0.9.x - Port JSON.Value from the `develop` branch to allow for union types, parsing of arbitrary data, and whatever the hell you want.
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  ██║ ██║███████║ ╚█████╔╝███████║╚██████╔╝██║ ╚████║
8
8
  ╚═╝ ╚═╝╚══════╝ ╚════╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═══╝
9
9
 
10
- v0.9.4
10
+ v0.9.6
11
11
  </pre>
12
12
  </h3>
13
13
 
@@ -111,6 +111,17 @@ const serialized = JSON.stringify(arr);
111
111
  const parsed = JSON.parse<Base[]>(serialized);
112
112
  ```
113
113
 
114
+ Classes can even have inheritance. Here's a nasty example
115
+
116
+ ```js
117
+ @json
118
+ class Base {}
119
+
120
+ const serialized = JSON.stringify(arr);
121
+ // [{"x":1.0},{"x":1.0,"y":2.0},{"y":2.0,"x":1.0,"z":3.0}]
122
+ const parsed = JSON.parse<Base[]>(serialized);
123
+ ```
124
+
114
125
  If you use this project in your codebase, consider dropping a [star](https://github.com/JairusSW/as-json). I would really appreciate it!
115
126
 
116
127
  ## Notes
@@ -28,3 +28,9 @@ declare function omitif(condition: string): Function;
28
28
  * Property decorator that allows a field to be omitted when a property is null.
29
29
  */
30
30
  declare function omitnull(): Function;
31
+
32
+ /**
33
+ * Property decorator that allows a field to be flattened.
34
+ * @param fieldName - Points to the field to flatten. Can use dot-notation here like @omit("foo.identifier.text")
35
+ */
36
+ declare function flatten(fieldName: string = "value"): Function;
package/assembly/test.ts CHANGED
@@ -1,25 +1,51 @@
1
1
  import { JSON } from ".";
2
2
 
3
+ // @json or @serializable work here
3
4
  @json
4
- class Base {}
5
- @json
6
- class Vec1 extends Base {
7
- x: f64 = 1.0;
5
+ class Vec3 {
6
+ x: f32 = 0.0;
7
+ y: f32 = 0.0;
8
+ z: f32 = 0.0;
8
9
  }
9
- @json
10
- class Vec2 extends Vec1 {
11
- @omit()
12
- y: f32 = 2.0;
10
+
11
+ class Box<T> {
12
+ value: T;
13
13
  }
14
+
14
15
  @json
15
- class Vec3 extends Vec2 {
16
- z: f32 = 3.0;
16
+ class Player {
17
+ @alias("first name")
18
+ @omitnull()
19
+ firstName: string | null;
20
+ lastName!: string;
21
+ lastActive!: i32[];
22
+ // Drop in a code block, function, or expression that evaluates to a boolean
23
+ @omitif("this.age < 18")
24
+ age!: i32;
25
+ @omitnull()
26
+ pos!: Vec3 | null;
27
+ isVerified!: boolean;
28
+ @flatten("value")
29
+ box: Box<i32> | null;
17
30
  }
18
31
 
19
- const arr: Base[] = [
20
- new Vec1(),
21
- new Vec2(),
22
- new Vec3()
23
- ];
32
+ const player: Player = {
33
+ firstName: null,
34
+ lastName: "West",
35
+ lastActive: [8, 27, 2022],
36
+ age: 23,
37
+ pos: {
38
+ x: 3.4,
39
+ y: 1.2,
40
+ z: 8.3
41
+ },
42
+ isVerified: true,
43
+ box: null
44
+ };
45
+
46
+ const stringified = JSON.stringify<Player>(player);
47
+
48
+ const parsed = JSON.parse<Player>(stringified);
24
49
 
25
- console.log(JSON.stringify(arr));
50
+ console.log("Stringified: " + stringified);
51
+ console.log("Parsed: " + JSON.stringify(parsed));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-as",
3
- "version": "0.9.4",
3
+ "version": "0.9.6",
4
4
  "description": "JSON encoder/decoder for AssemblyScript",
5
5
  "types": "assembly/index.ts",
6
6
  "author": "Jairus Tanaka",
@@ -15,7 +15,9 @@
15
15
  ],
16
16
  "license": "MIT",
17
17
  "scripts": {
18
- "test": "wasmtime build/serialize.spec.wasm && wasmtime build/deserialize.spec.wasm",
18
+ "test": "npm run test:serialize && npm run test:deserialize",
19
+ "test:serialize": "wasmtime build/serialize.spec.wasm",
20
+ "test:deserialize": "wasmtime build/deserialize.spec.wasm",
19
21
  "tests:build": "asc assembly/__tests__/serialize.spec.ts -o build/serialize.spec.wasm --transform ./transform --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json --optimizeLevel 0 --shrinkLevel 0 --noAssert --uncheckedBehavior always & asc assembly/__tests__/deserialize.spec.ts -o build/deserialize.spec.wasm --transform ./transform --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json --optimizeLevel 0 --shrinkLevel 0 --noAssert --uncheckedBehavior always",
20
22
  "build:test": "JSON_DEBUG=true asc assembly/test.ts -o build/test.wasm --transform ./transform --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json --optimizeLevel 0 --shrinkLevel 0 --noAssert --uncheckedBehavior always",
21
23
  "build:bench": "asc bench/benchmark.ts -o bench/benchmark.wasm --transform ./transform --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json --optimizeLevel 3 --shrinkLevel 0 --converge --noAssert --uncheckedBehavior always --runtime stub",
@@ -85,48 +85,67 @@ class JSONTransform extends BaseVisitor {
85
85
  mem.value = value;
86
86
  mem.node = member;
87
87
  if (member.decorators) {
88
- for (let i = 0; i < (member.decorators).length; i++) {
89
- const decorator = member.decorators[i];
88
+ let decorator = null;
89
+ if (decorator = member.decorators.find(v => v.name.text == "alias")) {
90
90
  if (decorator.name.text == "alias") {
91
91
  if (!decorator.args?.length)
92
92
  throw new Error("Expected 1 argument but got zero at @alias in " + node.range.source.normalizedPath);
93
- mem.flag = PropertyFlags.Alias;
93
+ mem.flags.push(PropertyFlags.Alias);
94
94
  mem.alias = decorator.args[0].value;
95
95
  }
96
- else if (decorator.name.text == "omitnull") {
97
- mem.flag = PropertyFlags.OmitNull;
96
+ }
97
+ for (let i = 0; i < (member.decorators).length; i++) {
98
+ const decorator = member.decorators[i];
99
+ if (decorator.name.text == "omitnull") {
100
+ mem.flags.push(PropertyFlags.OmitNull);
98
101
  }
99
102
  else if (decorator.name.text == "omitif") {
100
103
  if (!decorator.args?.length)
101
104
  throw new Error("Expected 1 argument but got zero at @omitif in " + node.range.source.normalizedPath);
102
105
  mem.args?.push(decorator.args[0].value);
103
- mem.flag = PropertyFlags.OmitIf;
106
+ mem.flags.push(PropertyFlags.OmitIf);
107
+ }
108
+ else if (decorator.name.text == "flatten") {
109
+ if (!decorator.args?.length)
110
+ throw new Error("Expected 1 argument but got zero at @flatten in " + node.range.source.normalizedPath);
111
+ mem.flags.push(PropertyFlags.Flatten);
112
+ mem.args = [decorator.args[0].value];
104
113
  }
105
114
  }
106
115
  }
107
- if (mem.flag === PropertyFlags.Alias) {
108
- mem.name = mem.alias;
109
- }
110
- else if (mem.flag === PropertyFlags.None) {
111
- mem.serialize = escapeString(JSON.stringify(mem.name)) + ":${__SERIALIZE<" + type + ">(this." + name.text + ")}";
116
+ if (!mem.flags.length) {
117
+ mem.flags = [PropertyFlags.None];
118
+ mem.serialize = escapeString(JSON.stringify(mem.alias || mem.name)) + ":${__SERIALIZE<" + type + ">(this." + name.text + ")}";
112
119
  mem.deserialize = "this." + name.text + " = " + "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end));";
113
120
  }
114
- if (mem.flag == PropertyFlags.OmitNull) {
115
- mem.serialize = "${changetype<usize>(this." + mem.name + ") == <usize>0" + " ? \"\" : '" + escapeString(JSON.stringify(mem.name)) + ":' + __SERIALIZE<" + type + ">(this." + name.text + ") + \",\"}";
121
+ if (mem.flags.includes(PropertyFlags.OmitNull)) {
122
+ mem.serialize = "${changetype<usize>(this." + mem.name + ") == <usize>0" + " ? \"\" : '" + escapeString(JSON.stringify(mem.alias || mem.name)) + ":' + __SERIALIZE<" + type + ">(this." + name.text + ") + \",\"}";
116
123
  mem.deserialize = "this." + name.text + " = " + "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end));";
117
124
  }
118
- else if (mem.flag == PropertyFlags.OmitIf) {
119
- mem.serialize = "${" + mem.args[0] + " ? \"\" : '" + escapeString(JSON.stringify(mem.name)) + ":' + __SERIALIZE<" + type + ">(this." + name.text + ") + \",\"}";
125
+ else if (mem.flags.includes(PropertyFlags.OmitIf)) {
126
+ mem.serialize = "${" + mem.args[0] + " ? \"\" : '" + escapeString(JSON.stringify(mem.alias || mem.name)) + ":' + __SERIALIZE<" + type + ">(this." + name.text + ") + \",\"}";
120
127
  mem.deserialize = "this." + name.text + " = " + "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end));";
121
128
  }
122
- else if (mem.flag == PropertyFlags.Alias) {
123
- mem.serialize = escapeString(JSON.stringify(mem.name)) + ":${__SERIALIZE<" + type + ">(this." + name.text + ")}";
129
+ else if (mem.flags.includes(PropertyFlags.Alias)) {
130
+ mem.serialize = escapeString(JSON.stringify(mem.alias || mem.name)) + ":${__SERIALIZE<" + type + ">(this." + name.text + ")}";
124
131
  mem.deserialize = "this." + name.text + " = " + "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end));";
125
132
  mem.name = name.text;
126
133
  }
134
+ else if (mem.flags.includes(PropertyFlags.Flatten)) {
135
+ const nullable = mem.node.type.isNullable;
136
+ if (nullable) {
137
+ mem.serialize = escapeString(JSON.stringify(mem.alias || mem.name)) + ":${this." + name.text + " ? __SERIALIZE(changetype<nonnull<" + type + ">>(this." + name.text + ")" + (mem.args?.length ? '.' + mem.args[0] : '') + ") : \"null\"}";
138
+ mem.deserialize = "if (value_end - value_start == 4 && load<u64>(changetype<usize>(data) + <usize>(value_start << 1)) == " + charCodeAt64("null", 0) + ") {\n this." + name.text + " = null;\n } else {\n this." + name.text + " = " + "__DESERIALIZE<" + type + ">('{\"" + mem.args[0] + "\":' + data.substring(value_start, value_end) + \"}\");\n }";
139
+ }
140
+ else {
141
+ mem.serialize = escapeString(JSON.stringify(mem.alias || mem.name)) + ":${this." + name.text + " ? __SERIALIZE(this." + name.text + (mem.args?.length ? '.' + mem.args[0] : '') + ") : \"null\"}";
142
+ mem.deserialize = "this." + name.text + " = " + "__DESERIALIZE<" + type + ">('{\"" + mem.args[0] + "\":' + data.substring(value_start, value_end) + \"}\");";
143
+ }
144
+ mem.name = name.text;
145
+ }
127
146
  const t = mem.node.type.name.identifier.text;
128
147
  if (this.schemasList.find(v => v.name == t)) {
129
- mem.initialize = "this." + name.text + " = changetype<nonnull<" + t + ">>(__new(offsetof<nonnull<" + t + ">>(), idof<nonnull<" + t + ">>()));\n changetype<nonnull<" + t + ">>(this." + name.text + ").__INITIALIZE()";
148
+ mem.initialize = "this." + name.text + " = changetype<nonnull<" + mem.type + ">>(__new(offsetof<nonnull<" + mem.type + ">>(), idof<nonnull<" + mem.type + ">>()));\n changetype<nonnull<" + mem.type + ">>(this." + name.text + ").__INITIALIZE()";
130
149
  }
131
150
  else if (mem.value) {
132
151
  mem.initialize = "this." + name.text + " = " + mem.value;
@@ -141,8 +160,8 @@ class JSONTransform extends BaseVisitor {
141
160
  if (!schema.members.length)
142
161
  return;
143
162
  found = false;
144
- if (schema.members[0]?.flag === PropertyFlags.OmitNull
145
- || schema.members[0]?.flag === PropertyFlags.OmitIf) {
163
+ if (schema.members[0]?.flags.includes(PropertyFlags.OmitNull)
164
+ || schema.members[0]?.flags.includes(PropertyFlags.OmitIf)) {
146
165
  SERIALIZE_RAW += schema.members[0]?.serialize;
147
166
  SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize;
148
167
  }
@@ -157,8 +176,8 @@ class JSONTransform extends BaseVisitor {
157
176
  const member = schema.members[i];
158
177
  if (member.initialize)
159
178
  INITIALIZE += " " + member.initialize + ";\n";
160
- if (member.flag === PropertyFlags.OmitNull
161
- || member.flag === PropertyFlags.OmitIf) {
179
+ if (member.flags.includes(PropertyFlags.OmitNull)
180
+ || member.flags.includes(PropertyFlags.OmitIf)) {
162
181
  SERIALIZE_RAW += member.serialize;
163
182
  SERIALIZE_PRETTY += member.serialize;
164
183
  }
@@ -348,6 +367,7 @@ var PropertyFlags;
348
367
  PropertyFlags[PropertyFlags["OmitNull"] = 2] = "OmitNull";
349
368
  PropertyFlags[PropertyFlags["OmitIf"] = 3] = "OmitIf";
350
369
  PropertyFlags[PropertyFlags["Alias"] = 4] = "Alias";
370
+ PropertyFlags[PropertyFlags["Flatten"] = 5] = "Flatten";
351
371
  })(PropertyFlags || (PropertyFlags = {}));
352
372
  class Property {
353
373
  constructor() {
@@ -355,7 +375,7 @@ class Property {
355
375
  this.alias = null;
356
376
  this.type = "";
357
377
  this.value = null;
358
- this.flag = PropertyFlags.None;
378
+ this.flags = [];
359
379
  this.args = [];
360
380
  this.serialize = null;
361
381
  this.deserialize = null;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@json-as/transform",
3
- "version": "0.9.4",
3
+ "version": "0.9.6",
4
4
  "description": "JSON encoder/decoder for AssemblyScript",
5
5
  "main": "./lib/index.js",
6
6
  "author": "Jairus Tanaka",
@@ -12,6 +12,7 @@ import { toString, isStdlib } from "visitor-as/dist/utils.js";
12
12
  import { BaseVisitor, SimpleParser } from "visitor-as/dist/index.js";
13
13
  import { Transform } from "assemblyscript/dist/transform.js";
14
14
  import { CommonFlags } from "types:assemblyscript/src/common";
15
+ import { DecoratorNode } from "types:assemblyscript/src/ast";
15
16
 
16
17
  class JSONTransform extends BaseVisitor {
17
18
  public schemasList: SchemaData[] = [];
@@ -105,44 +106,62 @@ class JSONTransform extends BaseVisitor {
105
106
  mem.node = member;
106
107
 
107
108
  if (member.decorators) {
108
- for (let i = 0; i < (member.decorators).length; i++) {
109
- const decorator = member.decorators[i]!;
109
+ let decorator: DecoratorNode | null = null;
110
+ if (decorator = member.decorators.find(v => (<IdentifierExpression>v.name).text == "alias") as DecoratorNode | null) {
110
111
  if ((<IdentifierExpression>decorator.name).text == "alias") {
111
112
  if (!decorator.args?.length) throw new Error("Expected 1 argument but got zero at @alias in " + node.range.source.normalizedPath);
112
- mem.flag = PropertyFlags.Alias;
113
+ mem.flags.push(PropertyFlags.Alias);
113
114
  mem.alias = (decorator.args[0] as StringLiteralExpression).value;
114
- } else if ((<IdentifierExpression>decorator.name).text == "omitnull") {
115
- mem.flag = PropertyFlags.OmitNull;
115
+ }
116
+ }
117
+
118
+ for (let i = 0; i < (member.decorators).length; i++) {
119
+ const decorator = member.decorators[i]!;
120
+ if ((<IdentifierExpression>decorator.name).text == "omitnull") {
121
+ mem.flags.push(PropertyFlags.OmitNull);
116
122
  } else if ((<IdentifierExpression>decorator.name).text == "omitif") {
117
123
  if (!decorator.args?.length) throw new Error("Expected 1 argument but got zero at @omitif in " + node.range.source.normalizedPath);
118
124
  mem.args?.push((decorator.args[0] as StringLiteralExpression).value);
119
- mem.flag = PropertyFlags.OmitIf;
125
+ mem.flags.push(PropertyFlags.OmitIf);
126
+ } else if ((<IdentifierExpression>decorator.name).text == "flatten") {
127
+ if (!decorator.args?.length) throw new Error("Expected 1 argument but got zero at @flatten in " + node.range.source.normalizedPath);
128
+ mem.flags.push(PropertyFlags.Flatten);
129
+ mem.args = [(decorator.args[0] as StringLiteralExpression).value];
120
130
  }
121
131
  }
122
132
  }
123
133
 
124
- if (mem.flag === PropertyFlags.Alias) {
125
- mem.name = mem.alias!;
126
- } else if (mem.flag === PropertyFlags.None) {
127
- mem.serialize = escapeString(JSON.stringify(mem.name)) + ":${__SERIALIZE<" + type + ">(this." + name.text + ")}";
134
+ if (!mem.flags.length) {
135
+ mem.flags = [PropertyFlags.None];
136
+ mem.serialize = escapeString(JSON.stringify(mem.alias || mem.name)) + ":${__SERIALIZE<" + type + ">(this." + name.text + ")}";
128
137
  mem.deserialize = "this." + name.text + " = " + "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end));"
129
138
  }
130
139
 
131
- if (mem.flag == PropertyFlags.OmitNull) {
132
- mem.serialize = "${changetype<usize>(this." + mem.name + ") == <usize>0" + " ? \"\" : '" + escapeString(JSON.stringify(mem.name)) + ":' + __SERIALIZE<" + type + ">(this." + name.text + ") + \",\"}";
140
+ if (mem.flags.includes(PropertyFlags.OmitNull)) {
141
+ mem.serialize = "${changetype<usize>(this." + mem.name + ") == <usize>0" + " ? \"\" : '" + escapeString(JSON.stringify(mem.alias || mem.name)) + ":' + __SERIALIZE<" + type + ">(this." + name.text + ") + \",\"}";
133
142
  mem.deserialize = "this." + name.text + " = " + "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end));"
134
- } else if (mem.flag == PropertyFlags.OmitIf) {
135
- mem.serialize = "${" + mem.args![0]! + " ? \"\" : '" + escapeString(JSON.stringify(mem.name)) + ":' + __SERIALIZE<" + type + ">(this." + name.text + ") + \",\"}";
143
+ } else if (mem.flags.includes(PropertyFlags.OmitIf)) {
144
+ mem.serialize = "${" + mem.args![0]! + " ? \"\" : '" + escapeString(JSON.stringify(mem.alias || mem.name)) + ":' + __SERIALIZE<" + type + ">(this." + name.text + ") + \",\"}";
136
145
  mem.deserialize = "this." + name.text + " = " + "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end));"
137
- } else if (mem.flag == PropertyFlags.Alias) {
138
- mem.serialize = escapeString(JSON.stringify(mem.name)) + ":${__SERIALIZE<" + type + ">(this." + name.text + ")}";
146
+ } else if (mem.flags.includes(PropertyFlags.Alias)) {
147
+ mem.serialize = escapeString(JSON.stringify(mem.alias || mem.name)) + ":${__SERIALIZE<" + type + ">(this." + name.text + ")}";
139
148
  mem.deserialize = "this." + name.text + " = " + "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end));"
140
149
  mem.name = name.text;
150
+ } else if (mem.flags.includes(PropertyFlags.Flatten)) {
151
+ const nullable = (mem.node.type as NamedTypeNode).isNullable;
152
+ if (nullable) {
153
+ mem.serialize = escapeString(JSON.stringify(mem.alias || mem.name)) + ":${this." + name.text + " ? __SERIALIZE(changetype<nonnull<" + type + ">>(this." + name.text + ")" + (mem.args?.length ? '.' + mem.args[0]! : '') + ") : \"null\"}";
154
+ mem.deserialize = "if (value_end - value_start == 4 && load<u64>(changetype<usize>(data) + <usize>(value_start << 1)) == " + charCodeAt64("null", 0) + ") {\n this." + name.text + " = null;\n } else {\n this." + name.text + " = " + "__DESERIALIZE<" + type + ">('{\"" + mem.args![0]! + "\":' + data.substring(value_start, value_end) + \"}\");\n }";
155
+ } else {
156
+ mem.serialize = escapeString(JSON.stringify(mem.alias || mem.name)) + ":${this." + name.text + " ? __SERIALIZE(this." + name.text + (mem.args?.length ? '.' + mem.args[0]! : '') + ") : \"null\"}";
157
+ mem.deserialize = "this." + name.text + " = " + "__DESERIALIZE<" + type + ">('{\"" + mem.args![0]! + "\":' + data.substring(value_start, value_end) + \"}\");";
158
+ }
159
+ mem.name = name.text;
141
160
  }
142
161
 
143
162
  const t = (mem.node.type as NamedTypeNode).name.identifier.text;
144
163
  if (this.schemasList.find(v => v.name == t)) {
145
- mem.initialize = "this." + name.text + " = changetype<nonnull<" + t + ">>(__new(offsetof<nonnull<" + t + ">>(), idof<nonnull<" + t + ">>()));\n changetype<nonnull<" + t + ">>(this." + name.text + ").__INITIALIZE()"
164
+ mem.initialize = "this." + name.text + " = changetype<nonnull<" + mem.type + ">>(__new(offsetof<nonnull<" + mem.type + ">>(), idof<nonnull<" + mem.type + ">>()));\n changetype<nonnull<" + mem.type + ">>(this." + name.text + ").__INITIALIZE()";
146
165
  } else if (mem.value) {
147
166
  mem.initialize = "this." + name.text + " = " + mem.value;
148
167
  }
@@ -163,8 +182,8 @@ class JSONTransform extends BaseVisitor {
163
182
  found = false;
164
183
 
165
184
  if (
166
- schema.members[0]?.flag === PropertyFlags.OmitNull
167
- || schema.members[0]?.flag === PropertyFlags.OmitIf
185
+ schema.members[0]?.flags.includes(PropertyFlags.OmitNull)
186
+ || schema.members[0]?.flags.includes(PropertyFlags.OmitIf)
168
187
  ) {
169
188
  SERIALIZE_RAW += schema.members[0]?.serialize;
170
189
  SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize;
@@ -180,8 +199,8 @@ class JSONTransform extends BaseVisitor {
180
199
  const member = schema.members[i]!;
181
200
  if (member.initialize) INITIALIZE += " " + member.initialize + ";\n";
182
201
  if (
183
- member.flag === PropertyFlags.OmitNull
184
- || member.flag === PropertyFlags.OmitIf
202
+ member.flags.includes(PropertyFlags.OmitNull)
203
+ || member.flags.includes(PropertyFlags.OmitIf)
185
204
  ) {
186
205
  SERIALIZE_RAW += member.serialize;
187
206
  SERIALIZE_PRETTY += member.serialize;
@@ -362,7 +381,8 @@ enum PropertyFlags {
362
381
  Omit,
363
382
  OmitNull,
364
383
  OmitIf,
365
- Alias
384
+ Alias,
385
+ Flatten
366
386
  }
367
387
 
368
388
  class Property {
@@ -370,7 +390,7 @@ class Property {
370
390
  public alias: string | null = null;
371
391
  public type: string = "";
372
392
  public value: string | null = null;
373
- public flag: PropertyFlags = PropertyFlags.None;
393
+ public flags: PropertyFlags[] = [];
374
394
  public args: string[] | null = [];
375
395
 
376
396
  public serialize: string | null = null;