json-as 0.7.2 → 0.8.0

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.
@@ -1,3 +1,4 @@
1
+ import { Parser, Source, Tokenizer, } from "assemblyscript/dist/assemblyscript.js";
1
2
  import { toString, isStdlib } from "visitor-as/dist/utils.js";
2
3
  import { BaseVisitor, SimpleParser } from "visitor-as/dist/index.js";
3
4
  import { Transform } from "assemblyscript/dist/transform.js";
@@ -17,7 +18,7 @@ class AsJSONTransform extends BaseVisitor {
17
18
  constructor() {
18
19
  super(...arguments);
19
20
  this.schemasList = [];
20
- this.sources = [];
21
+ this.sources = new Set();
21
22
  }
22
23
  visitMethodDeclaration() { }
23
24
  visitClassDeclaration(node) {
@@ -68,71 +69,69 @@ class AsJSONTransform extends BaseVisitor {
68
69
  // @ts-ignore
69
70
  if (mem.type && mem.type.name && mem.type.name.identifier.text) {
70
71
  const member = mem;
71
- if (toString(member).startsWith("static"))
72
- return;
73
72
  const lineText = toString(member);
74
- if (lineText.startsWith("private"))
75
- return;
76
- // @ts-ignore
77
- let type = toString(member.type);
78
- const name = member.name.text;
79
- let aliasName = name;
80
- if (member.decorators && ((_d = member.decorators[0]) === null || _d === void 0 ? void 0 : _d.name.text) === "alias") {
81
- if (member.decorators[0] && member.decorators[0].args[0]) {
82
- aliasName = member.decorators[0].args[0].value;
83
- }
84
- }
85
- this.currentClass.keys.push(name);
86
- // @ts-ignore
87
- this.currentClass.types.push(type);
88
- // @ts-ignore
89
- if ([
90
- "u8",
91
- "i8",
92
- "u16",
93
- "i16",
94
- "u32",
95
- "i32",
96
- "u64",
97
- "i64",
98
- ].includes(type.toLowerCase())) {
99
- this.currentClass.encodeStmts.push(`"${aliasName}":\${this.${name}.toString()},`);
73
+ console.log("Member: " + lineText);
74
+ if (!lineText.startsWith("private") && !lineText.startsWith("static")) {
100
75
  // @ts-ignore
101
- this.currentClass.setDataStmts.push(`if (key.equals("${aliasName}")) {
102
- this.${name} = __atoi_fast<${type}>(data, val_start << 1, val_end << 1);
103
- return;
104
- }
105
- `);
106
- if (member.initializer) {
107
- this.currentClass.initializeStmts.push(`this.${name} = ${toString(member.initializer)}`);
108
- }
109
- }
110
- else // @ts-ignore
111
- if ([
112
- "f32",
113
- "f64",
114
- ].includes(type.toLowerCase())) {
115
- this.currentClass.encodeStmts.push(`"${aliasName}":\${this.${name}.toString()},`);
76
+ let type = toString(member.type);
77
+ const name = member.name.text;
78
+ let aliasName = name;
116
79
  // @ts-ignore
117
- this.currentClass.setDataStmts.push(`if (key.equals("${aliasName}")) {
118
- this.${name} = __parseObjectValue<${type}>(data.slice(val_start, val_end), initializeDefaultValues);
119
- return;
120
- }
121
- `);
122
- if (member.initializer) {
123
- this.currentClass.initializeStmts.push(`this.${name} = ${toString(member.initializer)}`);
80
+ if (member.decorators && ((_d = member.decorators[0]) === null || _d === void 0 ? void 0 : _d.name.text) === "alias") {
81
+ if (member.decorators[0] && member.decorators[0].args[0]) {
82
+ // @ts-ignore
83
+ aliasName = member.decorators[0].args[0].value;
84
+ }
124
85
  }
125
- }
126
- else {
127
- this.currentClass.encodeStmts.push(`"${aliasName}":\${JSON.stringify<${type}>(this.${name})},`);
86
+ this.currentClass.keys.push(name);
128
87
  // @ts-ignore
129
- this.currentClass.setDataStmts.push(`if (key.equals("${aliasName}")) {
130
- this.${name} = __parseObjectValue<${type}>(val_start ? data.slice(val_start, val_end) : data, initializeDefaultValues);
131
- return;
132
- }
133
- `);
134
- if (member.initializer) {
135
- this.currentClass.initializeStmts.push(`this.${name} = ${toString(member.initializer)}`);
88
+ this.currentClass.types.push(type);
89
+ // @ts-ignore
90
+ if ([
91
+ "u8",
92
+ "i8",
93
+ "u16",
94
+ "i16",
95
+ "u32",
96
+ "i32",
97
+ "u64",
98
+ "i64",
99
+ ].includes(type.toLowerCase())) {
100
+ this.currentClass.encodeStmts.push(`${encodeKey(aliasName)}:\${this.${name}},`);
101
+ // @ts-ignore
102
+ this.currentClass.setDataStmts.push(`if (key.equals(${JSON.stringify(aliasName)})) {
103
+ this.${name} = __atoi_fast<${type}>(data, val_start << 1, val_end << 1);
104
+ return;
105
+ }`);
106
+ if (member.initializer) {
107
+ this.currentClass.initializeStmts.push(`this.${name} = ${toString(member.initializer)}`);
108
+ }
109
+ }
110
+ else // @ts-ignore
111
+ if ([
112
+ "f32",
113
+ "f64",
114
+ ].includes(type.toLowerCase())) {
115
+ this.currentClass.encodeStmts.push(`${encodeKey(aliasName)}:\${this.${name}},`);
116
+ // @ts-ignore
117
+ this.currentClass.setDataStmts.push(`if (key.equals(${JSON.stringify(aliasName)})) {
118
+ this.${name} = __parseObjectValue<${type}>(data.slice(val_start, val_end), initializeDefaultValues);
119
+ return;
120
+ }`);
121
+ if (member.initializer) {
122
+ this.currentClass.initializeStmts.push(`this.${name} = ${toString(member.initializer)}`);
123
+ }
124
+ }
125
+ else {
126
+ this.currentClass.encodeStmts.push(`${encodeKey(aliasName)}:\${JSON.stringify<${type}>(this.${name})},`);
127
+ // @ts-ignore
128
+ this.currentClass.setDataStmts.push(`if (key.equals(${JSON.stringify(aliasName)})) {
129
+ this.${name} = __parseObjectValue<${type}>(val_start ? data.slice(val_start, val_end) : data, initializeDefaultValues);
130
+ return;
131
+ }`);
132
+ if (member.initializer) {
133
+ this.currentClass.initializeStmts.push(`this.${name} = ${toString(member.initializer)}`);
134
+ }
136
135
  }
137
136
  }
138
137
  }
@@ -143,38 +142,32 @@ class AsJSONTransform extends BaseVisitor {
143
142
  this.currentClass.encodeStmts[this.currentClass.encodeStmts.length - 1] =
144
143
  stmt.slice(0, stmt.length - 1);
145
144
  serializeFunc = `
146
- @inline __JSON_Serialize(): string {
145
+ __JSON_Serialize(): string {
147
146
  return \`{${this.currentClass.encodeStmts.join("")}}\`;
148
- }
149
- `;
147
+ }`;
150
148
  }
151
149
  else {
152
150
  serializeFunc = `
153
- @inline __JSON_Serialize(): string {
151
+ __JSON_Serialize(): string {
154
152
  return "{}";
155
- }
156
- `;
153
+ }`;
157
154
  }
158
- // Odd behavior here... When pairing this transform with asyncify, having @inline on __JSON_Set_Key<T> with a generic will cause it to freeze.
159
- // Binaryen cannot predict and add/mangle code when it is genericed.
160
155
  const setKeyFunc = `
161
- __JSON_Set_Key<__JSON_Key_Type>(key: __JSON_Key_Type, data: string, val_start: i32, val_end: i32, initializeDefaultValues: boolean): void {
162
- ${
163
- // @ts-ignore
164
- this.currentClass.setDataStmts.join("")}
156
+ __JSON_Set_Key(key: __Virtual<string>, data: string, val_start: i32, val_end: i32, initializeDefaultValues: boolean): void {
157
+ ${this.currentClass.setDataStmts.join("\n ")}
165
158
  }
166
159
  `;
167
160
  let initializeFunc = "";
168
161
  if (this.currentClass.initializeStmts.length > 0) {
169
162
  initializeFunc = `
170
- @inline __JSON_Initialize(): void {
163
+ __JSON_Initialize(): void {
171
164
  ${this.currentClass.initializeStmts.join(";\n")};
172
165
  }
173
166
  `;
174
167
  }
175
168
  else {
176
169
  initializeFunc = `
177
- @inline __JSON_Initialize(): void {}
170
+ __JSON_Initialize(): void {}
178
171
  `;
179
172
  }
180
173
  const serializeMethod = SimpleParser.parseClassMember(serializeFunc, node);
@@ -184,12 +177,37 @@ class AsJSONTransform extends BaseVisitor {
184
177
  const initializeMethod = SimpleParser.parseClassMember(initializeFunc, node);
185
178
  node.members.push(initializeMethod);
186
179
  this.schemasList.push(this.currentClass);
187
- //console.log(toString(node));
180
+ this.sources.add(node.name.range.source);
181
+ // Uncomment to see the generated code for debugging.
182
+ //console.log(serializeFunc);
183
+ //console.log(setKeyFunc);
184
+ //console.log(initializeFunc);
188
185
  }
189
186
  visitSource(node) {
190
187
  super.visitSource(node);
188
+ // Only add the import statement to sources that have JSON decorated classes.
189
+ if (!this.sources.has(node)) {
190
+ return;
191
+ }
192
+ // Note, the following one liner would be easier, but it fails with an assertion error
193
+ // because as-virtual's SimpleParser doesn't set the parser.currentSource correctly.
194
+ //
195
+ // const stmt = SimpleParser.parseTopLevelStatement('import { Virtual as __Virtual } from "as-virtual/assembly";');
196
+ // ... So we have to do it the long way:
197
+ const s = 'import { Virtual as __Virtual } from "as-virtual/assembly";';
198
+ const t = new Tokenizer(new Source(0 /* SourceKind.User */, "index.ts", s));
199
+ const p = new Parser();
200
+ p.currentSource = t.source;
201
+ const stmt = p.parseTopLevelStatement(t);
202
+ // Add the import statement to the top of the source.
203
+ node.statements.unshift(stmt);
191
204
  }
192
205
  }
206
+ function encodeKey(aliasName) {
207
+ return JSON.stringify(aliasName)
208
+ .replace(/\\/g, "\\\\")
209
+ .replace(/\`/g, '\\`');
210
+ }
193
211
  export default class Transformer extends Transform {
194
212
  // Trigger the transform after parse.
195
213
  afterParse(parser) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@json-as/transform",
3
- "version": "0.7.2",
3
+ "version": "0.8.0",
4
4
  "description": "JSON encoder/decoder for AssemblyScript",
5
5
  "main": "./lib/index.js",
6
6
  "author": "Jairus Tanaka",
@@ -1,9 +1,12 @@
1
1
  import {
2
2
  ClassDeclaration,
3
3
  FieldDeclaration,
4
- Source,
5
4
  Parser,
6
- } from "assemblyscript/dist/assemblyscript";
5
+ Source,
6
+ SourceKind,
7
+ Tokenizer,
8
+ } from "assemblyscript/dist/assemblyscript.js";
9
+
7
10
  import { toString, isStdlib } from "visitor-as/dist/utils.js";
8
11
  import { BaseVisitor, SimpleParser } from "visitor-as/dist/index.js";
9
12
  import { Transform } from "assemblyscript/dist/transform.js";
@@ -23,7 +26,7 @@ class SchemaData {
23
26
  class AsJSONTransform extends BaseVisitor {
24
27
  public schemasList: SchemaData[] = [];
25
28
  public currentClass!: SchemaData;
26
- public sources: Source[] = [];
29
+ public sources = new Set<Source>();
27
30
 
28
31
  visitMethodDeclaration(): void { }
29
32
  visitClassDeclaration(node: ClassDeclaration): void {
@@ -80,93 +83,95 @@ class AsJSONTransform extends BaseVisitor {
80
83
  // @ts-ignore
81
84
  if (mem.type && mem.type.name && mem.type.name.identifier.text) {
82
85
  const member = mem as FieldDeclaration;
83
- if (toString(member).startsWith("static")) return;
84
86
  const lineText = toString(member);
85
- if (lineText.startsWith("private")) return;
87
+ console.log("Member: " + lineText)
86
88
 
87
- // @ts-ignore
88
- let type = toString(member.type);
89
+ if (!lineText.startsWith("private") && !lineText.startsWith("static")) {
89
90
 
90
- const name = member.name.text;
91
- let aliasName = name;
92
- if (member.decorators && member.decorators[0]?.name.text === "alias") {
93
- if (member.decorators[0] && member.decorators[0].args![0]) {
94
- aliasName = member.decorators[0].args![0].value;
95
- }
96
- }
97
- this.currentClass.keys.push(name);
98
- // @ts-ignore
99
- this.currentClass.types.push(type);
100
- // @ts-ignore
101
- if (
102
- [
103
- "u8",
104
- "i8",
105
- "u16",
106
- "i16",
107
- "u32",
108
- "i32",
109
- "u64",
110
- "i64",
111
- ].includes(type.toLowerCase())
112
- ) {
113
- this.currentClass.encodeStmts.push(
114
- `"${aliasName}":\${this.${name}.toString()},`
115
- );
116
91
  // @ts-ignore
117
- this.currentClass.setDataStmts.push(
118
- `if (key.equals("${aliasName}")) {
119
- this.${name} = __atoi_fast<${type}>(data, val_start << 1, val_end << 1);
120
- return;
121
- }
122
- `
123
- );
124
- if (member.initializer) {
125
- this.currentClass.initializeStmts.push(
126
- `this.${name} = ${toString(member.initializer)}`
127
- );
92
+ let type = toString(member.type);
93
+
94
+ const name = member.name.text;
95
+ let aliasName = name;
96
+
97
+ // @ts-ignore
98
+ if (member.decorators && member.decorators[0]?.name.text === "alias") {
99
+ if (member.decorators[0] && member.decorators[0].args![0]) {
100
+ // @ts-ignore
101
+ aliasName = member.decorators[0].args![0].value;
102
+ }
128
103
  }
129
- } else // @ts-ignore
104
+ this.currentClass.keys.push(name);
105
+ // @ts-ignore
106
+ this.currentClass.types.push(type);
107
+ // @ts-ignore
130
108
  if (
131
109
  [
132
- "f32",
133
- "f64",
110
+ "u8",
111
+ "i8",
112
+ "u16",
113
+ "i16",
114
+ "u32",
115
+ "i32",
116
+ "u64",
117
+ "i64",
134
118
  ].includes(type.toLowerCase())
135
119
  ) {
136
120
  this.currentClass.encodeStmts.push(
137
- `"${aliasName}":\${this.${name}.toString()},`
121
+ `${encodeKey(aliasName)}:\${this.${name}},`
138
122
  );
139
123
  // @ts-ignore
140
124
  this.currentClass.setDataStmts.push(
141
- `if (key.equals("${aliasName}")) {
142
- this.${name} = __parseObjectValue<${type}>(data.slice(val_start, val_end), initializeDefaultValues);
143
- return;
144
- }
145
- `
125
+ `if (key.equals(${JSON.stringify(aliasName)})) {
126
+ this.${name} = __atoi_fast<${type}>(data, val_start << 1, val_end << 1);
127
+ return;
128
+ }`
146
129
  );
147
130
  if (member.initializer) {
148
131
  this.currentClass.initializeStmts.push(
149
132
  `this.${name} = ${toString(member.initializer)}`
150
133
  );
151
134
  }
152
- } else {
153
- this.currentClass.encodeStmts.push(
154
- `"${aliasName}":\${JSON.stringify<${type}>(this.${name})},`
155
- );
156
- // @ts-ignore
157
- this.currentClass.setDataStmts.push(
158
- `if (key.equals("${aliasName}")) {
159
- this.${name} = __parseObjectValue<${type}>(val_start ? data.slice(val_start, val_end) : data, initializeDefaultValues);
160
- return;
161
- }
162
- `
163
- );
164
- if (member.initializer) {
165
- this.currentClass.initializeStmts.push(
166
- `this.${name} = ${toString(member.initializer)}`
135
+ } else // @ts-ignore
136
+ if (
137
+ [
138
+ "f32",
139
+ "f64",
140
+ ].includes(type.toLowerCase())
141
+ ) {
142
+ this.currentClass.encodeStmts.push(
143
+ `${encodeKey(aliasName)}:\${this.${name}},`
144
+ );
145
+ // @ts-ignore
146
+ this.currentClass.setDataStmts.push(
147
+ `if (key.equals(${JSON.stringify(aliasName)})) {
148
+ this.${name} = __parseObjectValue<${type}>(data.slice(val_start, val_end), initializeDefaultValues);
149
+ return;
150
+ }`
151
+ );
152
+ if (member.initializer) {
153
+ this.currentClass.initializeStmts.push(
154
+ `this.${name} = ${toString(member.initializer)}`
155
+ );
156
+ }
157
+ } else {
158
+ this.currentClass.encodeStmts.push(
159
+ `${encodeKey(aliasName)}:\${JSON.stringify<${type}>(this.${name})},`
160
+ );
161
+ // @ts-ignore
162
+ this.currentClass.setDataStmts.push(
163
+ `if (key.equals(${JSON.stringify(aliasName)})) {
164
+ this.${name} = __parseObjectValue<${type}>(val_start ? data.slice(val_start, val_end) : data, initializeDefaultValues);
165
+ return;
166
+ }`
167
167
  );
168
+ if (member.initializer) {
169
+ this.currentClass.initializeStmts.push(
170
+ `this.${name} = ${toString(member.initializer)}`
171
+ );
172
+ }
168
173
  }
169
- }
174
+ }
170
175
  }
171
176
  }
172
177
 
@@ -180,26 +185,19 @@ class AsJSONTransform extends BaseVisitor {
180
185
  this.currentClass.encodeStmts[this.currentClass.encodeStmts.length - 1] =
181
186
  stmt!.slice(0, stmt.length - 1);
182
187
  serializeFunc = `
183
- @inline __JSON_Serialize(): string {
188
+ __JSON_Serialize(): string {
184
189
  return \`{${this.currentClass.encodeStmts.join("")}}\`;
185
- }
186
- `;
190
+ }`;
187
191
  } else {
188
192
  serializeFunc = `
189
- @inline __JSON_Serialize(): string {
193
+ __JSON_Serialize(): string {
190
194
  return "{}";
191
- }
192
- `;
195
+ }`;
193
196
  }
194
197
 
195
- // Odd behavior here... When pairing this transform with asyncify, having @inline on __JSON_Set_Key<T> with a generic will cause it to freeze.
196
- // Binaryen cannot predict and add/mangle code when it is genericed.
197
198
  const setKeyFunc = `
198
- __JSON_Set_Key<__JSON_Key_Type>(key: __JSON_Key_Type, data: string, val_start: i32, val_end: i32, initializeDefaultValues: boolean): void {
199
- ${
200
- // @ts-ignore
201
- this.currentClass.setDataStmts.join("")
202
- }
199
+ __JSON_Set_Key(key: __Virtual<string>, data: string, val_start: i32, val_end: i32, initializeDefaultValues: boolean): void {
200
+ ${this.currentClass.setDataStmts.join("\n ")}
203
201
  }
204
202
  `;
205
203
 
@@ -207,13 +205,13 @@ class AsJSONTransform extends BaseVisitor {
207
205
 
208
206
  if (this.currentClass.initializeStmts.length > 0) {
209
207
  initializeFunc = `
210
- @inline __JSON_Initialize(): void {
208
+ __JSON_Initialize(): void {
211
209
  ${this.currentClass.initializeStmts.join(";\n")};
212
210
  }
213
211
  `;
214
212
  } else {
215
213
  initializeFunc = `
216
- @inline __JSON_Initialize(): void {}
214
+ __JSON_Initialize(): void {}
217
215
  `;
218
216
  }
219
217
  const serializeMethod = SimpleParser.parseClassMember(serializeFunc, node);
@@ -226,13 +224,45 @@ class AsJSONTransform extends BaseVisitor {
226
224
  node.members.push(initializeMethod);
227
225
 
228
226
  this.schemasList.push(this.currentClass);
229
- //console.log(toString(node));
227
+ this.sources.add(node.name.range.source);
228
+
229
+ // Uncomment to see the generated code for debugging.
230
+ //console.log(serializeFunc);
231
+ //console.log(setKeyFunc);
232
+ //console.log(initializeFunc);
230
233
  }
234
+
231
235
  visitSource(node: Source): void {
232
236
  super.visitSource(node);
237
+
238
+ // Only add the import statement to sources that have JSON decorated classes.
239
+ if (!this.sources.has(node)) {
240
+ return;
241
+ }
242
+
243
+ // Note, the following one liner would be easier, but it fails with an assertion error
244
+ // because as-virtual's SimpleParser doesn't set the parser.currentSource correctly.
245
+ //
246
+ // const stmt = SimpleParser.parseTopLevelStatement('import { Virtual as __Virtual } from "as-virtual/assembly";');
247
+
248
+ // ... So we have to do it the long way:
249
+ const s = 'import { Virtual as __Virtual } from "as-virtual/assembly";'
250
+ const t = new Tokenizer(new Source(SourceKind.User, "index.ts", s));
251
+ const p = new Parser();
252
+ p.currentSource = t.source;
253
+ const stmt = p.parseTopLevelStatement(t)!;
254
+
255
+ // Add the import statement to the top of the source.
256
+ node.statements.unshift(stmt);
233
257
  }
234
258
  }
235
259
 
260
+ function encodeKey(aliasName: string): string {
261
+ return JSON.stringify(aliasName)
262
+ .replace(/\\/g, "\\\\")
263
+ .replace(/\`/g, '\\`');
264
+ }
265
+
236
266
  export default class Transformer extends Transform {
237
267
  // Trigger the transform after parse.
238
268
  afterParse(parser: Parser): void {