Skip to content

Commit 8b7ccbd

Browse files
author
Andrew Omondi
committed
Untyped nodes in typescript
1 parent a10ebaa commit 8b7ccbd

File tree

10 files changed

+110
-27
lines changed

10 files changed

+110
-27
lines changed

packages/abstractions/src/serialization/untypedArray.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ export class UntypedArray extends UntypedNode {
1010
}
1111

1212
export function isUntypedArray(node: UntypedNode): node is UntypedArray {
13-
const value = (node as UntypedArray).value;
14-
return value instanceof Array && value.every((item) => isUntypedNode(item));
13+
const proposedNode = node as UntypedArray;
14+
return (
15+
proposedNode &&
16+
proposedNode.value instanceof Array &&
17+
proposedNode.value.every((item) => isUntypedNode(item))
18+
);
1519
}

packages/abstractions/src/serialization/untypedBoolean.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ export class UntypedBoolean extends UntypedNode {
1010
}
1111

1212
export function isUntypedBoolean(node: UntypedNode): node is UntypedBoolean {
13-
return typeof (node as UntypedBoolean).value === "boolean";
13+
return typeof (node as UntypedBoolean)?.value === "boolean";
1414
}

packages/abstractions/src/serialization/untypedNode.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,16 @@ export function isUntypedNode(node: any): node is UntypedNode {
2525
}
2626

2727
export function deserializeIntoUntypedNode(
28-
_untypedNode: Partial<UntypedNode> | undefined = {},
28+
untypedNode: Partial<UntypedNode> | undefined = {},
2929
): Record<string, (node: ParseNode) => void> {
30-
return {};
30+
return {
31+
value: (n) => {
32+
untypedNode.value = null;
33+
},
34+
getValue: (n) => {
35+
untypedNode.getValue = () => untypedNode.value;
36+
},
37+
};
3138
}
3239

3340
export function serializeUntypedNode(

packages/abstractions/src/serialization/untypedNull.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ export class UntypedNull extends UntypedNode {
1010
}
1111

1212
export function isUntypedNull(node: UntypedNode): node is UntypedNull {
13-
return (node as UntypedNull).value === null;
13+
return (node as UntypedNull)?.value === null;
1414
}

packages/abstractions/src/serialization/untypedNumber.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ export class UntypedNumber extends UntypedNode {
1010
}
1111

1212
export function isUntypedNumber(node: UntypedNode): node is UntypedNumber {
13-
return typeof (node as UntypedNumber).value === "number";
13+
return typeof (node as UntypedNumber)?.value === "number";
1414
}

packages/abstractions/src/serialization/untypedObject.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export class UntypedObject extends UntypedNode {
1010
}
1111

1212
export function isUntypedObject(node: UntypedNode): node is UntypedObject {
13-
const value = (node as UntypedObject).value;
13+
const value = (node as UntypedObject)?.value;
1414
return (
1515
value instanceof Object &&
1616
value instanceof Array === false &&

packages/abstractions/src/serialization/untypedString.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ export class UntypedString extends UntypedNode {
1010
}
1111

1212
export function isUntypedString(node: UntypedNode): node is UntypedString {
13-
return typeof (node as UntypedString).value === "string";
13+
return typeof (node as UntypedString)?.value === "string";
1414
}

packages/serialization/json/src/jsonParseNode.ts

+14-11
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
UntypedObject,
1818
UntypedString,
1919
createUntypedNodeFromDiscriminatorValue,
20+
UntypedNull,
2021
} from "@microsoft/kiota-abstractions";
2122

2223
export class JsonParseNode implements ParseNode {
@@ -81,33 +82,35 @@ export class JsonParseNode implements ParseNode {
8182
): T => {
8283
const temp: T = {} as T;
8384
if (isUntypedNode(parsableFactory(this)(temp))) {
84-
const valueType = typeof temp;
85+
const valueType = typeof this._jsonNode;
8586
let value: T = temp;
8687
if (valueType === "boolean") {
87-
value = new UntypedBoolean(value as any as boolean) as any as T;
88+
value = new UntypedBoolean(this._jsonNode as boolean) as any as T;
8889
} else if (valueType === "string") {
89-
value = new UntypedString(value as any as string) as any as T;
90+
value = new UntypedString(this._jsonNode as string) as any as T;
9091
} else if (valueType === "number") {
91-
value = new UntypedNumber(value as any as number) as any as T;
92-
} else if (Array.isArray(value)) {
92+
value = new UntypedNumber(this._jsonNode as number) as any as T;
93+
} else if (Array.isArray(this._jsonNode)) {
9394
const nodes: UntypedNode[] = [];
9495
// eslint-disable-next-line @typescript-eslint/no-unused-vars
95-
value.forEach((v, idx) => {
96-
const currentParseNode = new JsonParseNode(v);
97-
const untypedNode: UntypedNode = currentParseNode.getObjectValue(
98-
createUntypedNodeFromDiscriminatorValue,
96+
(this._jsonNode as any[]).forEach((x) => {
97+
nodes.push(
98+
new JsonParseNode(x).getObjectValue(
99+
createUntypedNodeFromDiscriminatorValue,
100+
),
99101
);
100-
nodes.push(untypedNode);
101102
});
102103
value = new UntypedArray(nodes) as any as T;
103-
} else if (valueType === "object") {
104+
} else if (this._jsonNode && valueType === "object") {
104105
const properties: Record<string, UntypedNode> = {};
105106
Object.entries(this._jsonNode as any).forEach(([k, v]) => {
106107
properties[k] = new JsonParseNode(v).getObjectValue(
107108
createUntypedNodeFromDiscriminatorValue,
108109
);
109110
});
110111
value = new UntypedObject(properties) as any as T;
112+
} else if (!this._jsonNode) {
113+
value = new UntypedNull() as any as T;
111114
}
112115
return value;
113116
}

packages/serialization/json/test/common/JsonParseNode.ts

+70-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { assert } from "chai";
2-
32
import { JsonParseNode } from "../../src/index";
43
import {
54
createTestParserFromDiscriminatorValue,
65
type TestBackedModel,
76
createTestBackedModelFromDiscriminatorValue,
87
type TestParser
98
} from "./testEntity";
9+
import { UntypedTestEntity, createUntypedTestEntityFromDiscriminatorValue } from "./untypedTestEntiy";
10+
import { UntypedNode, UntypedObject, isUntypedArray, isUntypedBoolean, isUntypedNode, isUntypedNumber, isUntypedObject } from "@microsoft/kiota-abstractions";
1011

1112
describe("JsonParseNode", () => {
1213
it("jsonParseNode:initializes", async () => {
@@ -169,4 +170,72 @@ describe("JsonParseNode", () => {
169170
assert.equal(jsonObjectStr, resultStr);
170171
});
171172

173+
it("untyped nodes are deserialized correctly", async () => {
174+
const jsonObject = {
175+
id: "1",
176+
title: "title",
177+
location: {
178+
address: {
179+
city: "Redmond",
180+
postalCode: "98052",
181+
state: "Washington",
182+
street: "NE 36th St",
183+
},
184+
coordinates: {
185+
latitude: 47.678581,
186+
longitude: -122.131577,
187+
},
188+
displayName: "Microsoft Building 25",
189+
floorCount: 50,
190+
hasReception: true,
191+
contact: null,
192+
},
193+
keywords: [
194+
{
195+
created: "2023-07-26T10:41:26Z",
196+
label: "Keyword1",
197+
termGuid: "10e9cc83-b5a4-4c8d-8dab-4ada1252dd70",
198+
wssId: 6442450941,
199+
},
200+
{
201+
created: "2023-07-26T10:51:26Z",
202+
label: "Keyword2",
203+
termGuid: "2cae6c6a-9bb8-4a78-afff-81b88e735fef",
204+
wssId: 6442450942,
205+
},
206+
],
207+
extra: {
208+
value: {
209+
createdDateTime: {
210+
value: "2024-01-15T00:00:00+00:00",
211+
},
212+
},
213+
},
214+
};
215+
216+
const result = new JsonParseNode(jsonObject).getObjectValue(
217+
createUntypedTestEntityFromDiscriminatorValue,
218+
) as UntypedTestEntity;
219+
assert.equal(result.id, "1");
220+
assert.equal(result.title, "title");
221+
assert.isNotNull(result.location);
222+
assert.isTrue(isUntypedNode(result.location));
223+
const location = result.location as UntypedObject;
224+
const locationProperties = location.getValue();
225+
assert.isTrue(isUntypedObject(location));
226+
assert.isTrue(isUntypedObject(locationProperties["address"]));
227+
assert.isTrue(isUntypedObject(locationProperties["coordinates"]));
228+
assert.isTrue(isUntypedBoolean(locationProperties["hasReception"]));
229+
assert.isTrue(isUntypedNumber(locationProperties["floorCount"]));
230+
assert.isTrue(isUntypedBoolean(locationProperties["hasReception"]));
231+
assert.equal(locationProperties["hasReception"].getValue(), true);
232+
assert.equal(locationProperties["contact"].getValue(), null);
233+
assert.equal(locationProperties["floorCount"].getValue(), 50);
234+
const keywords = result.keywords as UntypedNode;
235+
assert.isTrue(isUntypedArray(keywords));
236+
assert.equal(
237+
locationProperties["displayName"].getValue(),
238+
"Microsoft Building 25",
239+
);
240+
});
172241
});

packages/serialization/json/test/common/untypedTestEntiy.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,19 @@ export function deserializeUntypedTestEntity(
3232
untypedTestEntity.title = n.getStringValue();
3333
},
3434
location: (n) => {
35-
untypedTestEntity.location = n.getObjectValue(
35+
untypedTestEntity.location = n.getObjectValue<UntypedNode>(
3636
createUntypedNodeFromDiscriminatorValue,
37-
) as UntypedNode;
37+
);
3838
},
3939
keywords: (n) => {
40-
untypedTestEntity.keywords = n.getObjectValue(
40+
untypedTestEntity.keywords = n.getObjectValue<UntypedNode>(
4141
createUntypedNodeFromDiscriminatorValue,
42-
) as UntypedNode;
42+
);
4343
},
4444
detail: (n) => {
45-
untypedTestEntity.detail = n.getObjectValue(
45+
untypedTestEntity.detail = n.getObjectValue<UntypedNode>(
4646
createUntypedNodeFromDiscriminatorValue,
47-
) as UntypedNode;
47+
);
4848
},
4949
};
5050
}

0 commit comments

Comments
 (0)