json-as 0.8.2 → 0.8.4

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.
@@ -18,8 +18,5 @@ jobs:
18
18
  if: steps.node-cache.outputs.cache-hit != 'true'
19
19
  run: yarn
20
20
 
21
- - name: Test to see if the project compiles
22
- run: yarn build:test
23
-
24
21
  - name: Perform tests
25
22
  run: yarn run test
package/CHANGELOG CHANGED
@@ -1 +1,3 @@
1
- v0.8.2 - Properties starting with `static` or `private` would be ignored
1
+ v0.8.2 - Properties starting with `static` or `private` would be ignored
2
+ v0.8.3 - Dirty fix to issue #68. Add __JSON_Stringify callable to global scope.
3
+ v0.8.4 - Fix #71. Classes with the extending class overriding a property cause the property to be serialized twice.
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  ██║ ██║███████║ ╚█████╔╝███████║╚██████╔╝██║ ╚████║
8
8
  ╚═╝ ╚═╝╚══════╝ ╚════╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═══╝
9
9
 
10
- v0.8.2
10
+ v0.8.3
11
11
  </pre>
12
12
  </h3>
13
13
 
@@ -14,7 +14,32 @@ function canSer<T>(data: T, toBe: string): void {
14
14
  const serialized = JSON.stringify<T>(data);
15
15
  expect(serialized).toBe(toBe);
16
16
  }
17
+ @json
18
+ class BaseObject {
19
+ a: string;
20
+
21
+ constructor(a: string) {
22
+ this.a = a;
23
+ }
24
+ }
25
+
26
+ @json
27
+ class DerivedObject extends BaseObject {
28
+ b: string;
29
+
30
+ constructor(a: string, b: string) {
31
+ super(a);
32
+ this.b = b;
33
+ }
34
+ }
17
35
 
36
+ describe("Ser/de object hierarchies", () => {
37
+ it("should ser/de objects derived from base objects", () => {
38
+ const o = new DerivedObject("1", "2");
39
+ const s = '{"a":"1","b":"2"}';
40
+ canSerde(o, s);
41
+ });
42
+ });
18
43
  @json
19
44
  class Map4 {
20
45
  a: string;
@@ -102,6 +127,11 @@ describe("Ser/de Array", () => {
102
127
 
103
128
  canSerde<i32[]>([0, 100, 101, -100, -101]);
104
129
  canSerde<i64[]>([0, 100, 101, -100, -101]);
130
+ canDeser<i32[]>(`[
131
+ 1,
132
+ 2,
133
+ 3
134
+ ]`, [1,2,3]);
105
135
  });
106
136
 
107
137
  it("should ser/de float arrays", () => {
@@ -27,7 +27,7 @@ import {
27
27
  tabCode,
28
28
  formFeedCode,
29
29
  newLineCode,
30
-
30
+
31
31
  commaWord,
32
32
  quoteWord,
33
33
 
@@ -50,7 +50,7 @@ export namespace JSON {
50
50
  /**
51
51
  * Stringifies valid JSON data.
52
52
  * ```js
53
- * JSON.stringify<T>(data)
53
+ * __JSON_Stringify<T>(data)
54
54
  * ```
55
55
  * @param data T
56
56
  * @returns string
@@ -104,11 +104,11 @@ export namespace JSON {
104
104
  // @ts-ignore
105
105
  for (let i = 0; i < data.length - 1; i++) {
106
106
  // @ts-ignore
107
- result.write(JSON.stringify(unchecked(data[i])));
107
+ result.write(__JSON_Stringify(unchecked(data[i])));
108
108
  result.writeCodePoint(commaCode);
109
109
  }
110
110
  // @ts-ignore
111
- result.write(JSON.stringify(unchecked(data[data.length - 1])));
111
+ result.write(__JSON_Stringify(unchecked(data[data.length - 1])));
112
112
  result.writeCodePoint(rightBracketCode);
113
113
  return result.toString();
114
114
  }
@@ -116,18 +116,21 @@ export namespace JSON {
116
116
  let result = new StringSink(leftBraceWord);
117
117
  let keys = data.keys();
118
118
  let values = data.values();
119
- for (let i = 0; i < data.size; i++) {
119
+ const end = data.size - 1;
120
+ for (let i = 0; i < end; i++) {
120
121
  result.write(serializeString(unchecked(keys[i]).toString()));
121
122
  result.writeCodePoint(colonCode);
122
- result.write(JSON.stringify(unchecked(values[i])));
123
- if (i < data.size - 1) {
124
- result.writeCodePoint(commaCode);
125
- }
123
+ result.write(__JSON_Stringify(unchecked(values[i])));
124
+ result.writeCodePoint(commaCode);
126
125
  }
126
+ result.write(serializeString(unchecked(keys[end]).toString()));
127
+ result.writeCodePoint(colonCode);
128
+ result.write(__JSON_Stringify(unchecked(values[end])));
129
+
127
130
  result.writeCodePoint(rightBraceCode);
128
131
  return result.toString();
129
132
  } else {
130
- throw new Error(
133
+ throw abort(
131
134
  `Could not serialize data of type ${nameof<T>()}. Make sure to add the correct decorators to classes.`
132
135
  );
133
136
  }
@@ -135,7 +138,7 @@ export namespace JSON {
135
138
  /**
136
139
  * Stringifies valid JSON data.
137
140
  * ```js
138
- * JSON.stringify<T>(data)
141
+ * __JSON_Stringify<T>(data)
139
142
  * ```
140
143
  * @param data T
141
144
  * @returns string
@@ -198,17 +201,17 @@ export namespace JSON {
198
201
  // @ts-ignore
199
202
  for (let i = 0; i < data.length - 1; i++) {
200
203
  // @ts-ignore
201
- result.write(JSON.stringify(unchecked(data[i])));
204
+ result.write(__JSON_Stringify(unchecked(data[i])));
202
205
  result.writeCodePoint(commaCode);
203
206
  }
204
207
  // @ts-ignore
205
- result.write(JSON.stringify(unchecked(data[data.length - 1])));
208
+ result.write(__JSON_Stringify(unchecked(data[data.length - 1])));
206
209
  result.writeCodePoint(rightBracketCode);
207
210
  out = result.toString();
208
211
  return;
209
212
  }
210
213
  } else {
211
- throw new Error(
214
+ throw abort(
212
215
  `Could not serialize data of type ${nameof<T>()}. Make sure to add the correct decorators to classes.`
213
216
  );
214
217
  }
@@ -248,7 +251,7 @@ export namespace JSON {
248
251
  // @ts-ignore
249
252
  return parseDate(data);
250
253
  } else {
251
- throw new Error(
254
+ throw abort(
252
255
  `Could not deserialize data ${data} to type ${nameof<T>()}. Make sure to add the correct decorators to classes.`
253
256
  );
254
257
  }
@@ -281,7 +284,7 @@ export namespace JSON {
281
284
  // @ts-ignore
282
285
  return parseDate(data);
283
286
  } else {
284
- throw new Error(
287
+ throw abort(
285
288
  `Could not deserialize data ${data} to type ${nameof<T>()}. Make sure to add the correct decorators to classes.`
286
289
  );
287
290
  }
@@ -350,7 +353,7 @@ export namespace JSON {
350
353
 
351
354
  // @ts-ignore: Decorator
352
355
  @inline function parseString(data: string, start: i32 = 0, end: i32 = 0): string {
353
- end = end || data.length - 1;
356
+ end = end || data.length - 1;
354
357
  let result = StringSink.withCapacity(end - start - 1);
355
358
  let last = start + 1;
356
359
  for (let i = last; i < end; i++) {
@@ -408,7 +411,7 @@ export namespace JSON {
408
411
  break;
409
412
  }
410
413
  default: {
411
- throw new Error(`JSON: Cannot parse "${data}" as string. Invalid escape sequence: \\${data.charAt(i)}`);
414
+ throw abort(`JSON: Cannot parse "${data}" as string. Invalid escape sequence: \\${data.charAt(i)}`);
412
415
  }
413
416
  }
414
417
  }
@@ -422,7 +425,7 @@ export namespace JSON {
422
425
  @inline function parseBoolean<T extends boolean>(data: string): T {
423
426
  if (data.length > 3 && data.startsWith(trueWord)) return <T>true;
424
427
  else if (data.length > 4 && data.startsWith(falseWord)) return <T>false;
425
- else throw new Error(`JSON: Cannot parse "${data}" as boolean`);
428
+ else throw abort(`JSON: Cannot parse "${data}" as boolean`);
426
429
  }
427
430
 
428
431
  // @ts-ignore: Decorator
@@ -444,7 +447,7 @@ export namespace JSON {
444
447
  const schema: nonnull<T> = changetype<nonnull<T>>(
445
448
  __new(offsetof<nonnull<T>>(), idof<nonnull<T>>())
446
449
  );
447
-
450
+
448
451
  // @ts-ignore
449
452
  if (initializeDefaultValues) schema.__JSON_Initialize();
450
453
 
@@ -579,9 +582,9 @@ export namespace JSON {
579
582
  const map: nonnull<T> = changetype<nonnull<T>>(
580
583
  __new(offsetof<nonnull<T>>(), idof<nonnull<T>>())
581
584
  );
582
-
585
+
583
586
  if (!isDefined(map.set)) {
584
- return unreachable();
587
+ throw abort("Tried to parse a map, but the types did not match!")
585
588
  }
586
589
 
587
590
  const key = Virtual.createEmpty<string>();
@@ -652,7 +655,7 @@ export namespace JSON {
652
655
  key.reinst(data, outerLoopIndex, stringValueIndex);
653
656
  }
654
657
  isKey = true;
655
- } else {
658
+ } else {
656
659
  if (isString<valueof<T>>()) {
657
660
  const value = parseString(data, outerLoopIndex - 1, stringValueIndex);
658
661
  map.set(parseMapKey<indexof<T>>(key), value);
@@ -702,7 +705,7 @@ export namespace JSON {
702
705
  if (char === colonCode || char === commaCode || char === rightBraceCode || isSpace(char)) {
703
706
  if (isFloat<valueof<T>>() || isInteger<valueof<T>>()) {
704
707
  map.set(parseMapKey<indexof<T>>(key), parseNumber<valueof<T>>(data.slice(outerLoopIndex - 1, numberValueIndex)));
705
- }
708
+ }
706
709
  outerLoopIndex = numberValueIndex;
707
710
  isKey = false;
708
711
  break;
@@ -726,7 +729,7 @@ export namespace JSON {
726
729
  return parseNumber<T>(k);
727
730
  }
728
731
 
729
- throw new Error(`JSON: Cannot parse JSON object to a Map with a key of type ${nameof<T>()}`);
732
+ throw abort(`JSON: Cannot parse JSON object to a Map with a key of type ${nameof<T>()}`);
730
733
  }
731
734
 
732
735
  // @ts-ignore: Decorator
@@ -754,8 +757,8 @@ export namespace JSON {
754
757
  return parseObjectArray<T>(data);
755
758
  }
756
759
  }
757
-
758
- return unreachable();
760
+
761
+ throw abort("Tried to parse array, but failed!")
759
762
  }
760
763
 
761
764
  // @ts-ignore: Decorator
@@ -805,22 +808,18 @@ export namespace JSON {
805
808
  const result = instantiate<T>();
806
809
  let lastPos = 0;
807
810
  let i = 1;
808
- for (; i < data.length - 1; i++) {
811
+ let awaitingParse = false;
812
+ for (; i < data.length; i++) {
809
813
  const char = unsafeCharCodeAt(data, i);
810
814
  if (lastPos === 0 && ((char >= 48 && char <= 57) || char === 45)) {
815
+ awaitingParse = true;
811
816
  lastPos = i;
812
- } else if ((isSpace(char) || char == commaCode) && lastPos > 0) {
817
+ } else if (awaitingParse && (isSpace(char) || char == commaCode || char == rightBracketCode) && lastPos > 0) {
818
+ awaitingParse = false;
813
819
  result.push(parseNumber<valueof<T>>(data.slice(lastPos, i)));
814
820
  lastPos = 0;
815
821
  }
816
822
  }
817
- for (; i > lastPos - 1; i--) {
818
- const char = unsafeCharCodeAt(data, i);
819
- if (char !== rightBracketCode) {
820
- result.push(parseNumber<valueof<T>>(data.slice(lastPos, i + 1)));
821
- break;
822
- }
823
- }
824
823
  return result;
825
824
  }
826
825
 
@@ -876,7 +875,7 @@ export namespace JSON {
876
875
  return result;
877
876
  }
878
877
 
879
- function parseDate(dateTimeString: string): Date {
878
+ function parseDate(dateTimeString: string): Date {
880
879
  // Use AssemblyScript's date parser
881
880
  const d = Date.fromString(dateTimeString);
882
881
 
@@ -891,3 +890,85 @@ function parseDate(dateTimeString: string): Date {
891
890
  let type = changetype<T>(0);
892
891
  return type instanceof Map;
893
892
  }
893
+
894
+ // Dirty fix
895
+ // @ts-ignore: Decorator
896
+ @global @inline function __JSON_Stringify<T>(data: T): string {
897
+ // String
898
+ if (isString<T>() && data != null) {
899
+ return serializeString(data as string);
900
+ } else if (isBoolean<T>()) {
901
+ return data ? "true" : "false";
902
+ } else if (isNullable<T>() && data == null) {
903
+ return nullWord;
904
+ // @ts-ignore
905
+ } else if ((isInteger<T>() || isFloat<T>()) && isFinite(data)) {
906
+ // @ts-ignore
907
+ return data.toString();
908
+ // @ts-ignore: Hidden function
909
+ } else if (isDefined(data.__JSON_Serialize)) {
910
+ // @ts-ignore: Hidden function
911
+ return data.__JSON_Serialize();
912
+ } else if (data instanceof Date) {
913
+ return `"${data.toISOString()}"`;
914
+ } else if (isArrayLike<T>()) {
915
+ // @ts-ignore
916
+ if (data.length == 0) {
917
+ return emptyArrayWord;
918
+ // @ts-ignore
919
+ } else if (isString<valueof<T>>()) {
920
+ let result = leftBracketWord;
921
+ // @ts-ignore
922
+ for (let i = 0; i < data.length - 1; i++) {
923
+ // @ts-ignore
924
+ result += serializeString(unchecked(data[i]));
925
+ result += commaWord;
926
+ }
927
+ // @ts-ignore
928
+ result += serializeString(unchecked(data[data.length - 1]));
929
+ result += rightBracketWord;
930
+ return result;
931
+ // @ts-ignore
932
+ } else if (isBoolean<valueof<T>>()) {
933
+ // @ts-ignore
934
+ return leftBracketWord + data.join(commaWord) + rightBracketWord;
935
+ // @ts-ignore
936
+ } else if (isFloat<valueof<T>>() || isInteger<valueof<T>>()) {
937
+ // @ts-ignore
938
+ return leftBracketWord + data.join(commaWord) + rightBracketWord;
939
+ } else {
940
+ let result = new StringSink(leftBracketWord);
941
+ // @ts-ignore
942
+ for (let i = 0; i < data.length - 1; i++) {
943
+ // @ts-ignore
944
+ result.write(__JSON_Stringify(unchecked(data[i])));
945
+ result.writeCodePoint(commaCode);
946
+ }
947
+ // @ts-ignore
948
+ result.write(__JSON_Stringify(unchecked(data[data.length - 1])));
949
+ result.writeCodePoint(rightBracketCode);
950
+ return result.toString();
951
+ }
952
+ } else if (data instanceof Map) {
953
+ let result = new StringSink(leftBraceWord);
954
+ let keys = data.keys();
955
+ let values = data.values();
956
+ const end = data.size - 1;
957
+ for (let i = 0; i < end; i++) {
958
+ result.write(serializeString(unchecked(keys[i]).toString()));
959
+ result.writeCodePoint(colonCode);
960
+ result.write(__JSON_Stringify(unchecked(values[i])));
961
+ result.writeCodePoint(commaCode);
962
+ }
963
+ result.write(serializeString(unchecked(keys[end]).toString()));
964
+ result.writeCodePoint(colonCode);
965
+ result.write(__JSON_Stringify(unchecked(values[end])));
966
+
967
+ result.writeCodePoint(rightBraceCode);
968
+ return result.toString();
969
+ } else {
970
+ throw abort(
971
+ `Could not serialize data of type ${nameof<T>()}. Make sure to add the correct decorators to classes.`
972
+ );
973
+ }
974
+ }
package/assembly/test.ts CHANGED
@@ -1,23 +1,24 @@
1
1
  import { JSON } from "./src/json";
2
+
2
3
  @json
3
- class Person {
4
- staticprng: i32 = 23;
5
- public country: string = '';
4
+ class BaseObject {
5
+ a: string;
6
6
 
7
- constructor(id: u32) {
8
- this.staticprng = 321;
9
- const seed = id.toString();
10
- this.country = this.getCountry();
7
+ constructor(a: string) {
8
+ this.a = a;
11
9
  }
10
+ }
12
11
 
13
- // temp method, returns hard-coded string for now
14
- private getCountry(): string {
15
- return "USA";
12
+ @json
13
+ class DerivedObject extends BaseObject {
14
+ b: string;
15
+
16
+ constructor(a: string, b: string) {
17
+ super(a);
18
+ this.b = b;
16
19
  }
17
20
  }
18
21
 
19
- const person = new Person(1);
20
- person.staticprng = 32
21
- let result = JSON.stringify<Person>(person);
22
- console.log(JSON.stringify(JSON.parse<Person>(result)));
23
- console.log(result);
22
+ const o = new DerivedObject("1", "2");
23
+
24
+ console.log(JSON.stringify(o))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-as",
3
- "version": "0.8.2",
3
+ "version": "0.8.4",
4
4
  "description": "JSON encoder/decoder for AssemblyScript",
5
5
  "types": "assembly/index.ts",
6
6
  "author": "Jairus Tanaka",
@@ -53,18 +53,27 @@ class AsJSONTransform extends BaseVisitor {
53
53
  setDataStmts: [],
54
54
  initializeStmts: []
55
55
  };
56
- if (this.currentClass.parent.length > 0) {
56
+ if (this.currentClass.parent.length) {
57
57
  const parentSchema = this.schemasList.find((v) => v.name == this.currentClass.parent);
58
58
  if (parentSchema === null || parentSchema === void 0 ? void 0 : parentSchema.encodeStmts) {
59
59
  parentSchema === null || parentSchema === void 0 ? void 0 : parentSchema.encodeStmts.push((parentSchema === null || parentSchema === void 0 ? void 0 : parentSchema.encodeStmts.pop()) + ",");
60
- this.currentClass.encodeStmts.push(...parentSchema === null || parentSchema === void 0 ? void 0 : parentSchema.encodeStmts);
60
+ for (let i = 0; i < parentSchema.keys.length; i++) {
61
+ const key = parentSchema.keys[i];
62
+ if (node.members.filter(v => v.name.text == key) == undefined)
63
+ this.currentClass.encodeStmts.unshift(parentSchema.encodeStmts[i]);
64
+ }
61
65
  }
62
66
  }
63
67
  const parentSchema = this.schemasList.find((v) => v.name == this.currentClass.parent);
64
68
  const members = [
65
- ...node.members,
66
- ...(parentSchema ? parentSchema.node.members : []),
69
+ ...node.members
67
70
  ];
71
+ if (parentSchema) {
72
+ for (const mem of parentSchema.node.members) {
73
+ if (members.find(v => v.name === mem.name) == undefined)
74
+ members.unshift(mem);
75
+ }
76
+ }
68
77
  for (const mem of members) {
69
78
  // @ts-ignore
70
79
  if (mem.type && mem.type.name && mem.type.name.identifier.text) {
@@ -123,7 +132,7 @@ class AsJSONTransform extends BaseVisitor {
123
132
  }
124
133
  }
125
134
  else {
126
- this.currentClass.encodeStmts.push(`${encodeKey(aliasName)}:\${JSON.stringify<${type}>(this.${name})},`);
135
+ this.currentClass.encodeStmts.push(`${encodeKey(aliasName)}:\${__JSON_Stringify<${type}>(this.${name})},`);
127
136
  // @ts-ignore
128
137
  this.currentClass.setDataStmts.push(`if (key.equals(${JSON.stringify(aliasName)})) {
129
138
  this.${name} = __parseObjectValue<${type}>(val_start ? data.slice(val_start, val_end) : data, initializeDefaultValues);
@@ -194,11 +203,11 @@ class AsJSONTransform extends BaseVisitor {
194
203
  //
195
204
  // const stmt = SimpleParser.parseTopLevelStatement('import { Virtual as __Virtual } from "as-virtual/assembly";');
196
205
  // ... 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);
206
+ const txt = 'import { Virtual as __Virtual } from "as-virtual/assembly";';
207
+ const tokenizer = new Tokenizer(new Source(0 /* SourceKind.User */, node.normalizedPath, txt));
208
+ const parser = new Parser();
209
+ parser.currentSource = tokenizer.source;
210
+ const stmt = parser.parseTopLevelStatement(tokenizer);
202
211
  // Add the import statement to the top of the source.
203
212
  node.statements.unshift(stmt);
204
213
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@json-as/transform",
3
- "version": "0.8.2",
3
+ "version": "0.8.4",
4
4
  "description": "JSON encoder/decoder for AssemblyScript",
5
5
  "main": "./lib/index.js",
6
6
  "author": "Jairus Tanaka",
@@ -61,24 +61,33 @@ class AsJSONTransform extends BaseVisitor {
61
61
  initializeStmts: []
62
62
  };
63
63
 
64
- if (this.currentClass.parent.length > 0) {
64
+ if (this.currentClass.parent.length) {
65
65
  const parentSchema = this.schemasList.find(
66
66
  (v) => v.name == this.currentClass.parent
67
67
  );
68
68
  if (parentSchema?.encodeStmts) {
69
69
  parentSchema?.encodeStmts.push(parentSchema?.encodeStmts.pop() + ",");
70
- this.currentClass.encodeStmts.push(...parentSchema?.encodeStmts);
70
+ for (let i = 0; i < parentSchema.keys.length; i++) {
71
+ const key = parentSchema.keys[i];
72
+ if (node.members.filter(v => v.name.text == key) == undefined) this.currentClass.encodeStmts.unshift(parentSchema.encodeStmts[i]!);
73
+ }
71
74
  }
72
75
  }
73
76
 
74
77
  const parentSchema = this.schemasList.find(
75
78
  (v) => v.name == this.currentClass.parent
76
79
  );
80
+
77
81
  const members = [
78
- ...node.members,
79
- ...(parentSchema ? parentSchema.node.members : []),
82
+ ...node.members
80
83
  ];
81
84
 
85
+ if (parentSchema) {
86
+ for (const mem of parentSchema.node.members) {
87
+ if (members.find(v => v.name === mem.name) == undefined) members.unshift(mem);
88
+ }
89
+ }
90
+
82
91
  for (const mem of members) {
83
92
  // @ts-ignore
84
93
  if (mem.type && mem.type.name && mem.type.name.identifier.text) {
@@ -156,7 +165,7 @@ class AsJSONTransform extends BaseVisitor {
156
165
  }
157
166
  } else {
158
167
  this.currentClass.encodeStmts.push(
159
- `${encodeKey(aliasName)}:\${JSON.stringify<${type}>(this.${name})},`
168
+ `${encodeKey(aliasName)}:\${__JSON_Stringify<${type}>(this.${name})},`
160
169
  );
161
170
  // @ts-ignore
162
171
  this.currentClass.setDataStmts.push(
@@ -246,11 +255,11 @@ class AsJSONTransform extends BaseVisitor {
246
255
  // const stmt = SimpleParser.parseTopLevelStatement('import { Virtual as __Virtual } from "as-virtual/assembly";');
247
256
 
248
257
  // ... 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)!;
258
+ const txt = 'import { Virtual as __Virtual } from "as-virtual/assembly";'
259
+ const tokenizer = new Tokenizer(new Source(SourceKind.User, node.normalizedPath, txt));
260
+ const parser = new Parser();
261
+ parser.currentSource = tokenizer.source;
262
+ const stmt = parser.parseTopLevelStatement(tokenizer)!;
254
263
 
255
264
  // Add the import statement to the top of the source.
256
265
  node.statements.unshift(stmt);