From 147ae635c5f324ebe526231e7e02cb1558c4ac77 Mon Sep 17 00:00:00 2001 From: Romain Lenzotti Date: Thu, 5 Oct 2023 08:29:24 +0200 Subject: [PATCH] fix(json-mapper): fix serialization and deserialization of optional collections produce [null] when null is passed Closes: #2465 --- commitlint.config.js | 29 ++++++++++++++++++- .../src/middlewares/PlatformLogMiddleware.ts | 2 +- .../src/domain/JsonDeserializer.spec.ts | 27 +++++++++++++++++ .../src/domain/JsonDeserializer.ts | 12 ++++++++ .../src/domain/JsonSerializer.spec.ts | 26 +++++++++++++++++ .../json-mapper/src/domain/JsonSerializer.ts | 11 +++++++ 6 files changed, 105 insertions(+), 2 deletions(-) diff --git a/commitlint.config.js b/commitlint.config.js index 3aa829787ff..e0fffe997be 100644 --- a/commitlint.config.js +++ b/commitlint.config.js @@ -1,6 +1,33 @@ +const globby = require("globby"); +const {basename, dirname} = require("path"); +const pkg = require("./package.json"); +const {RuleConfigSeverity} = require("@commitlint/types"); + +function findPackages() { + const patterns = pkg.workspaces.packages.map((pkgPattern) => { + return `${pkgPattern}/package.json`; + }); + + let pkgs = globby.sync(patterns, { + cwd: __dirname + }); + + return pkgs.map((pkg) => { + return basename(pkg.replace("/package.json", "")); + }); +} + module.exports = { extends: ["@commitlint/config-conventional"], rules: { + "scope-enum": [RuleConfigSeverity.Error, "always", findPackages()], "header-max-length": [0, "always", 120] - } + }, + ignores: [ + (message) => + message.includes("[skip ci]") || + !!message.match( + /^((feat|fix|hotfix|tech|bugfix)\/(([0-9]+)\.?)+(\.[a-zA-Z]+)+) \(#+([0-9]+)\)/g // merge commits (matching a branch name, eg. 'feat/999.bla.bla (#123)') + ) + ] }; diff --git a/packages/platform/platform-log-middleware/src/middlewares/PlatformLogMiddleware.ts b/packages/platform/platform-log-middleware/src/middlewares/PlatformLogMiddleware.ts index 81216b42b2c..181908eacca 100644 --- a/packages/platform/platform-log-middleware/src/middlewares/PlatformLogMiddleware.ts +++ b/packages/platform/platform-log-middleware/src/middlewares/PlatformLogMiddleware.ts @@ -132,7 +132,7 @@ export class PlatformLogMiddleware implements MiddlewareMethods { return { method: request.method, url: request.url, - route: request.route, + route: request.route || request.url, headers: request.headers, body: request.body, query: request.query, diff --git a/packages/specs/json-mapper/src/domain/JsonDeserializer.spec.ts b/packages/specs/json-mapper/src/domain/JsonDeserializer.spec.ts index 644670501b3..8dfc7d13967 100644 --- a/packages/specs/json-mapper/src/domain/JsonDeserializer.spec.ts +++ b/packages/specs/json-mapper/src/domain/JsonDeserializer.spec.ts @@ -542,6 +542,33 @@ describe("deserialize()", () => { } }); }); + it("should transform keep array, map, set without nullable value", () => { + class Model { + @CollectionOf(String) + public bars?: string[]; + + @CollectionOf(String) + public barsSet?: Set; + + @CollectionOf(String) + public barsMap?: Map; + } + + const payload = { + bars: null, + barsSet: null, + barsMap: null + }; + + const result = deserialize(payload, {type: Model}); + + expect(result).toBeInstanceOf(Model); + expect(result).toEqual({ + bars: null, + barsSet: null, + barsMap: null + }); + }); it("should transform object to class (date/nullable)", () => { class Product { @Nullable(Date) diff --git a/packages/specs/json-mapper/src/domain/JsonDeserializer.ts b/packages/specs/json-mapper/src/domain/JsonDeserializer.ts index b0c619f0e6c..0e7335f3081 100644 --- a/packages/specs/json-mapper/src/domain/JsonDeserializer.ts +++ b/packages/specs/json-mapper/src/domain/JsonDeserializer.ts @@ -348,6 +348,10 @@ export class JsonDeserializer extends JsonMapperCompiler { + if (isNil(input)) { + return input; + } + const obj = new Set(); objectKeys(input).forEach((key) => { @@ -358,12 +362,20 @@ export class JsonDeserializer extends JsonMapperCompiler { return this.mapItem(item, options); }); } private mapMap(input: any, options: JsonDeserializerOptions): Map { + if (isNil(input)) { + return input; + } + const obj = new Map(); objectKeys(input).forEach((key) => { diff --git a/packages/specs/json-mapper/src/domain/JsonSerializer.spec.ts b/packages/specs/json-mapper/src/domain/JsonSerializer.spec.ts index 9d2b80357f3..8731008c893 100644 --- a/packages/specs/json-mapper/src/domain/JsonSerializer.spec.ts +++ b/packages/specs/json-mapper/src/domain/JsonSerializer.spec.ts @@ -658,6 +658,32 @@ describe("JsonSerializer", () => { prop4: null }); }); + it("should transform keep array, map, set without nullable value", () => { + class Model { + @CollectionOf(String) + public bars?: string[]; + + @CollectionOf(String) + public barsSet?: Set; + + @CollectionOf(String) + public barsMap?: Map; + } + + const payload = { + bars: null, + barsSet: null, + barsMap: null + }; + + const result = serialize(payload, {type: Model}); + + expect(result).toEqual({ + bars: null, + barsSet: null, + barsMap: null + }); + }); it("should serialize array model with alias property", () => { class SpaBooking { @Required() diff --git a/packages/specs/json-mapper/src/domain/JsonSerializer.ts b/packages/specs/json-mapper/src/domain/JsonSerializer.ts index ee3a03d399f..cecbf97c076 100644 --- a/packages/specs/json-mapper/src/domain/JsonSerializer.ts +++ b/packages/specs/json-mapper/src/domain/JsonSerializer.ts @@ -266,18 +266,29 @@ export class JsonSerializer extends JsonMapperCompiler { } private mapSet(input: any, options: JsonSerializerOptions) { + if (isNil(input)) { + return input; + } return [...input.values()].map((item) => { return this.mapItem(item, options); }); } private mapArray(input: any, options: JsonSerializerOptions) { + if (isNil(input)) { + return input; + } + return [].concat(input).map((item: any) => { return this.mapItem(item, options); }); } private mapMap(input: any, options: JsonSerializerOptions) { + if (isNil(input)) { + return input; + } + return [...input.entries()].reduce((obj, [key, item]) => { return { ...obj,