From fa0cb103d4d7b903688f41b15496e269be4c1c0b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sandra=20Tatarevi=C4=87ov=C3=A1?=
 <sandra.tatarevicova@windy.com>
Date: Wed, 21 Feb 2024 08:39:18 +0100
Subject: [PATCH] feat: add support for parsing boolean strings

---
 src/TransformOperationExecutor.ts                    |  6 +++++-
 src/constants/default-options.constant.ts            |  1 +
 .../class-transformer-options.interface.ts           |  8 ++++++++
 test/functional/implicit-type-declarations.spec.ts   | 12 +++++++++++-
 4 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/src/TransformOperationExecutor.ts b/src/TransformOperationExecutor.ts
index 0533f03df..c64b14410 100644
--- a/src/TransformOperationExecutor.ts
+++ b/src/TransformOperationExecutor.ts
@@ -107,7 +107,11 @@ export class TransformOperationExecutor {
       return Number(value);
     } else if (targetType === Boolean && !isMap) {
       if (value === null || value === undefined) return value;
-      return Boolean(value);
+      if (this.options.parseBooleanStrings && typeof value === 'string') {
+        return value.toLowerCase() === 'true' || value === '1';
+      } else {
+        return Boolean(value);
+      }
     } else if ((targetType === Date || value instanceof Date) && !isMap) {
       if (value instanceof Date) {
         return new Date(value.valueOf());
diff --git a/src/constants/default-options.constant.ts b/src/constants/default-options.constant.ts
index b2f5f3b76..10030bc32 100644
--- a/src/constants/default-options.constant.ts
+++ b/src/constants/default-options.constant.ts
@@ -10,6 +10,7 @@ export const defaultOptions: Partial<ClassTransformOptions> = {
   excludePrefixes: undefined,
   exposeDefaultValues: false,
   exposeUnsetFields: true,
+  parseBooleanStrings: false,
   groups: undefined,
   ignoreDecorators: false,
   strategy: undefined,
diff --git a/src/interfaces/class-transformer-options.interface.ts b/src/interfaces/class-transformer-options.interface.ts
index 25be8f18e..2f6e6aa05 100644
--- a/src/interfaces/class-transformer-options.interface.ts
+++ b/src/interfaces/class-transformer-options.interface.ts
@@ -76,4 +76,12 @@ export interface ClassTransformOptions {
    * DEFAULT: `true`
    */
   exposeUnsetFields?: boolean;
+
+  /**
+   * When set to true, boolean fields with string `true` (case insensitive) or `1` as value will be converted to true, other
+   * string values will be converted to false.
+   *
+   * DEFAULT: `false`
+   */
+  parseBooleanStrings?: boolean;
 }
diff --git a/test/functional/implicit-type-declarations.spec.ts b/test/functional/implicit-type-declarations.spec.ts
index 889565512..1b1e1a188 100644
--- a/test/functional/implicit-type-declarations.spec.ts
+++ b/test/functional/implicit-type-declarations.spec.ts
@@ -102,6 +102,12 @@ describe('plainToInstance transforms built-in primitive types properly', () => {
 
     @Type()
     boolean2: boolean;
+
+    @Type()
+    boolean3: boolean;
+
+    @Type()
+    boolean4: boolean;
   }
 
   const result: Example = plainToInstance(
@@ -114,8 +120,10 @@ describe('plainToInstance transforms built-in primitive types properly', () => {
       number2: 100,
       boolean: 1,
       boolean2: 0,
+      boolean3: 'true',
+      boolean4: 'false',
     },
-    { enableImplicitConversion: true }
+    { enableImplicitConversion: true, parseBooleanStrings: true }
   );
 
   it('should recognize and convert to Date', () => {
@@ -140,5 +148,7 @@ describe('plainToInstance transforms built-in primitive types properly', () => {
   it('should recognize and convert to boolean', () => {
     expect(result.boolean).toBeTruthy();
     expect(result.boolean2).toBeFalsy();
+    expect(result.boolean3).toBeTruthy();
+    expect(result.boolean4).toBeFalsy();
   });
 });