diff --git a/packages/serialization/json/src/jsonParseNode.ts b/packages/serialization/json/src/jsonParseNode.ts index 5295239a2..00557a7b3 100644 --- a/packages/serialization/json/src/jsonParseNode.ts +++ b/packages/serialization/json/src/jsonParseNode.ts @@ -5,7 +5,7 @@ * ------------------------------------------------------------------------------------------- */ -import { DateOnly, Duration, TimeOnly, UntypedNode, createBackedModelProxyHandler, createUntypedArray, createUntypedBoolean, createUntypedNodeFromDiscriminatorValue, createUntypedNull, createUntypedNumber, createUntypedObject, createUntypedString, inNodeEnv, isBackingStoreEnabled, isUntypedNode, parseGuidString, getEnumValueFromStringValue, type Parsable, type ParsableFactory, type ParseNode } from "@microsoft/kiota-abstractions"; +import { DateOnly, Duration, TimeOnly, UntypedNode, createBackedModelProxyHandler, createUntypedArray, createUntypedBoolean, createUntypedNodeFromDiscriminatorValue, createUntypedNull, createUntypedNumber, createUntypedObject, createUntypedString, inNodeEnv, isBackingStoreEnabled, isUntypedNode, parseGuidString, getEnumValueFromStringValue, type Parsable, type ParsableFactory, type ParseNode, AdditionalDataHolder } from "@microsoft/kiota-abstractions"; export class JsonParseNode implements ParseNode { constructor(private readonly _jsonNode: unknown) {} public onBeforeAssignFieldValues: ((value: Parsable) => void) | undefined; @@ -108,8 +108,11 @@ export class JsonParseNode implements ParseNode { if (deserializer) { deserializer(new JsonParseNode(v)); } else { + // there is no real way to test if the model is actually a holder or not // additional properties - (model as Record)[k] = v; + const modelDataHolder = model as AdditionalDataHolder; + modelDataHolder.additionalData ??= {} as Record; + modelDataHolder.additionalData[k] = v; } }); }; diff --git a/packages/serialization/json/test/common/JsonParseNode.ts b/packages/serialization/json/test/common/JsonParseNode.ts index 1930fd31a..3a77612c0 100644 --- a/packages/serialization/json/test/common/JsonParseNode.ts +++ b/packages/serialization/json/test/common/JsonParseNode.ts @@ -8,7 +8,7 @@ import { assert, describe, it } from "vitest"; import { JsonParseNode } from "../../src/index"; import { createTestParserFromDiscriminatorValue, type TestBackedModel, createTestBackedModelFromDiscriminatorValue, type TestParser, TestUnionObject, BarResponse } from "./testEntity"; -import { UntypedTestEntity, createUntypedTestEntityFromDiscriminatorValue } from "./untypedTestEntiy"; +import { UntypedTestEntity, createUntypedTestEntityFromDiscriminatorValue } from "./untypedTestEntity"; import { UntypedNode, UntypedObject, isUntypedArray, isUntypedBoolean, isUntypedNode, isUntypedNumber, isUntypedObject } from "@microsoft/kiota-abstractions"; describe("JsonParseNode", () => { diff --git a/packages/serialization/json/test/common/jsonSerializationWriter.ts b/packages/serialization/json/test/common/jsonSerializationWriter.ts index 14ad8836f..ed2f0b0ff 100644 --- a/packages/serialization/json/test/common/jsonSerializationWriter.ts +++ b/packages/serialization/json/test/common/jsonSerializationWriter.ts @@ -9,7 +9,7 @@ import { assert, describe, it, beforeEach } from "vitest"; import { JsonParseNode, JsonSerializationWriter } from "../../src/index"; import { createTestBackedModelFromDiscriminatorValue, createTestParserFromDiscriminatorValue, LongRunningOperationStatusObject, serializeTestParser, TestBackedModel, type TestParser } from "./testEntity"; -import { UntypedTestEntity, serializeUntypedTestEntity } from "./untypedTestEntiy"; +import { UntypedTestEntity, serializeUntypedTestEntity } from "./untypedTestEntity"; import { BackingStore, BackingStoreFactorySingleton, createBackedModelProxyHandler, createUntypedArray, createUntypedBoolean, createUntypedNull, createUntypedNumber, createUntypedObject, createUntypedString } from "@microsoft/kiota-abstractions"; describe("JsonParseNode", () => { @@ -36,7 +36,14 @@ describe("JsonParseNode", () => { }, testDate, }; - const expectedObject: TestParser = { + + const writer = new JsonSerializationWriter(); + writer.writeObjectValue("", inputObject, serializeTestParser); + const serializedContent = writer.getSerializedContent(); + const decoder = new TextDecoder(); + const contentAsStr = decoder.decode(serializedContent); + const result = JSON.parse(contentAsStr); + assert.deepEqual(result, { testCollection: ["2", "3"], testString: "test", testComplexString: "A more \"complex\" string with \r\nlinebreaks and 'weird' characters", @@ -46,17 +53,23 @@ describe("JsonParseNode", () => { someValue: 123, }, }, - testDate, - }; - - const writer = new JsonSerializationWriter(); - writer.writeObjectValue("", inputObject, serializeTestParser); - const serializedContent = writer.getSerializedContent(); - const decoder = new TextDecoder(); - const contentAsStr = decoder.decode(serializedContent); - const result = JSON.parse(contentAsStr); - const stringValueResult = new JsonParseNode(result).getObjectValue(createTestParserFromDiscriminatorValue) as TestParser; - assert.deepEqual(stringValueResult, expectedObject); + testDate: testDate.toISOString(), + }); + const parsedValueResult = new JsonParseNode(result).getObjectValue(createTestParserFromDiscriminatorValue); + assert.deepEqual(parsedValueResult as object, { + testCollection: ["2", "3"], + testString: "test", + testComplexString: "A more \"complex\" string with \r\nlinebreaks and 'weird' characters", + testObject: { + additionalData: { + testObjectName: "str", + testObjectProp: { + someValue: 123, + }, + }, + }, + testDate: testDate, + }); }); it("Test enum serialization", async () => { diff --git a/packages/serialization/json/test/common/testEntity.ts b/packages/serialization/json/test/common/testEntity.ts index e03eac354..c7d96b9dc 100644 --- a/packages/serialization/json/test/common/testEntity.ts +++ b/packages/serialization/json/test/common/testEntity.ts @@ -69,42 +69,53 @@ export function createBarParserFromDiscriminatorValue(parseNode: ParseNode | und return deserializeBarParser; } +export function createTestObjectFromDiscriminatorValue(parseNode: ParseNode | undefined) { + if (!parseNode) throw new Error("parseNode cannot be undefined"); + return deserializeTestObject; +} +export function deserializeTestObject(testObject: { additionalData?: Record } | undefined = {}): Record void> { + return {}; +} + export function deserializeTestParser(testParser: TestParser | undefined = {}): Record void> { return { - testCollection: (n) => { + "testObject": (n) => { + testParser.testObject = n.getObjectValue<{ additionalData?: Record }>(createTestObjectFromDiscriminatorValue); + }, + "testCollection": (n) => { testParser.testCollection = n.getCollectionOfPrimitiveValues(); }, - testString: (n) => { + "testString": (n) => { testParser.testString = n.getStringValue(); }, - testBoolean: (n) => { + "testBoolean": (n) => { testParser.testBoolean = n.getBooleanValue(); }, - textComplexString: (n) => { + "testComplexString": (n) => { testParser.testComplexString = n.getStringValue(); }, - testDate: (n) => { + "testDate": (n) => { testParser.testDate = n.getDateValue(); }, - foos: (n) => { + "foos": (n) => { testParser.foos = n.getCollectionOfObjectValues(createFooParserFromDiscriminatorValue); }, - id: (n) => { + "id": (n) => { testParser.id = n.getStringValue(); }, - testNumber: (n) => { + "testNumber": (n) => { testParser.testNumber = n.getNumberValue(); }, - testGuid: (n) => { + "testGuid": (n) => { testParser.testGuid = n.getGuidValue(); }, - testUnionObject: (n) => { + "testUnionObject": (n) => { testParser.testUnionObject = n.getStringValue() ?? n.getNumberValue() ?? n.getObjectValue(createTestUnionObjectFromDiscriminatorValue); }, - status: (n) => { + "status": (n) => { testParser.status = n.getEnumValue(LongRunningOperationStatusObject); }, - nextStatuses: (n) => { + "nextStatuses": (n) => { testParser.nextStatuses = n.getCollectionOfEnumValues(LongRunningOperationStatusObject); }, }; @@ -112,7 +123,7 @@ export function deserializeTestParser(testParser: TestParser | undefined = {}): export function deserializeTestBackedModel(testParser: TestBackedModel | undefined = {}): Record void> { return { - backingStoreEnabled: (n) => { + "backingStoreEnabled": (n) => { testParser.backingStoreEnabled = true; }, ...deserializeTestParser(testParser), @@ -121,10 +132,10 @@ export function deserializeTestBackedModel(testParser: TestBackedModel | undefin export function deserializeFooParser(fooResponse: FooResponse | undefined = {}): Record void> { return { - id: (n) => { + "id": (n) => { fooResponse.id = n.getStringValue(); }, - bars: (n) => { + "bars": (n) => { fooResponse.bars = n.getCollectionOfObjectValues(createBarParserFromDiscriminatorValue); }, }; @@ -132,22 +143,28 @@ export function deserializeFooParser(fooResponse: FooResponse | undefined = {}): export function deserializeBarParser(barResponse: BarResponse | undefined = {}): Record void> { return { - propA: (n) => { + "propA": (n) => { barResponse.propA = n.getStringValue(); }, - propB: (n) => { + "propB": (n) => { barResponse.propB = n.getStringValue(); }, - propC: (n) => { + "propC": (n) => { barResponse.propC = n.getDateValue(); }, }; } -export function serializeTestObject(writer: SerializationWriter, entity: { additionalData?: Record } | undefined = {}): void { +export function serializeTestObject(writer: SerializationWriter, entity: { additionalData?: Record } | undefined | null = {}): void { + if (!entity) { + return; + } writer.writeAdditionalData(entity.additionalData); } -export function serializeTestParser(writer: SerializationWriter, entity: TestParser | undefined = {}): void { +export function serializeTestParser(writer: SerializationWriter, entity: TestParser | undefined | null = {}): void { + if (!entity) { + return; + } writer.writeStringValue("id", entity.id); writer.writeCollectionOfPrimitiveValues("testCollection", entity.testCollection); writer.writeStringValue("testString", entity.testString); @@ -170,18 +187,27 @@ export function serializeTestParser(writer: SerializationWriter, entity: TestPar writer.writeCollectionOfEnumValues("nextStatuses", entity.nextStatuses); } -export function serializeFoo(writer: SerializationWriter, entity: FooResponse | undefined = {}): void { +export function serializeFoo(writer: SerializationWriter, entity: FooResponse | undefined | null = {}): void { + if (!entity) { + return; + } writer.writeStringValue("id", entity.id); writer.writeCollectionOfObjectValues("bars", entity.bars, serializeBar); } -export function serializeBar(writer: SerializationWriter, entity: BarResponse | undefined = {}): void { +export function serializeBar(writer: SerializationWriter, entity: BarResponse | undefined | null = {}): void { + if (!entity) { + return; + } writer.writeStringValue("propA", entity.propA); writer.writeStringValue("propB", entity.propB); writer.writeDateValue("propC", entity.propC); } -export function serializeTestBackModel(writer: SerializationWriter, entity: TestBackedModel | undefined = {}): void { +export function serializeTestBackModel(writer: SerializationWriter, entity: TestBackedModel | undefined | null = {}): void { + if (!entity) { + return; + } serializeTestParser(writer, entity); } @@ -198,7 +224,10 @@ export function deserializeIntoTestUnionObject(fooBar: Partial }; } -export function serializeTestUnionObject(writer: SerializationWriter, fooBar: Partial | undefined = {}): void { +export function serializeTestUnionObject(writer: SerializationWriter, fooBar: Partial | undefined | null = {}): void { + if (!fooBar) { + return; + } serializeFoo(writer, fooBar as FooResponse); serializeBar(writer, fooBar as BarResponse); } diff --git a/packages/serialization/json/test/common/untypedTestEntiy.ts b/packages/serialization/json/test/common/untypedTestEntity.ts similarity index 100% rename from packages/serialization/json/test/common/untypedTestEntiy.ts rename to packages/serialization/json/test/common/untypedTestEntity.ts diff --git a/packages/serialization/json/vitest.config.mts b/packages/serialization/json/vitest.config.mts index 61e5e2216..7e469b550 100644 --- a/packages/serialization/json/vitest.config.mts +++ b/packages/serialization/json/vitest.config.mts @@ -2,7 +2,7 @@ import { defineConfig, configDefaults } from "vitest/config"; export default defineConfig({ test: { - exclude: [...configDefaults.exclude, "**/*/{testEntity,index,untypedTestEntiy,unionOfObjectsAndPrimitives,testUtils}.ts"], + exclude: [...configDefaults.exclude, "**/*/{testEntity,index,untypedTestEntity,unionOfObjectsAndPrimitives,testUtils}.ts"], include: [...configDefaults.include, "test/**/*.ts"], coverage: { reporter: ["html", "cobertura"], diff --git a/prettier.config.cjs b/prettier.config.cjs index d59b7e091..290b0da6f 100644 --- a/prettier.config.cjs +++ b/prettier.config.cjs @@ -10,5 +10,6 @@ module.exports = { "singleQuote": false, "tabWidth": 4, "trailingComma": "all", - "useTabs": true + "useTabs": true, + "quoteProps": "preserve" }