Repository: nestjs/swagger
Pull request #1898 (2022-04-25 10:15:02)

fix: fix numeric enum values
## PR Checklist
Please check if your PR fulfills the following requirements:

- [x] The commit message follows our guidelines: https://github.com/nestjs/nest/blob/master/CONTRIBUTING.md
- [x] Tests for the changes have been added (for bug fixes / features)
- [ ] Docs have been added / updated (for bug fixes / features)


## PR Type
What kind of change does this PR introduce?

<!-- Please check the one that applies to this PR using "x". -->
- [x] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, local variables)
- [ ] Refactoring (no functional changes, no api changes)
- [ ] Build related changes
- [ ] CI related changes
- [ ] Other... Please describe:

## What is the current behavior?
Numeric enums
```ts
enum Size {
  SMALL = 1,
  BIG = 2,
}
```
are currently displayed as 
```js
['SMALL', 'BIG']
```

Issue Number: #1884


## What is the new behavior?

Numeric enums
```ts
enum Size {
  SMALL = 1,
  BIG = 2,
}
```
should be displayed as 
```js
[1, 2]
```
in schemas and examples.

![Screenshot of the new behaivor](https://user-images.githubusercontent.com/7000918/216777272-550d3bf6-86b4-4099-a8d4-d51bdff1eec4.png)

This is done by fixing the logic which removes reverse mapping.

## Does this PR introduce a breaking change?
- [ ] Yes
- [x] No

I consider this more of a bug than a breaking change.


## Other information

Besides numeric enum, this handles [heterogenous enums](https://www.typescriptlang.org/docs/handbook/enums.html#heterogeneous-enums) as well (not in tests, because Swagger officially supports only enum values of the [same type](https://swagger.io/docs/specification/data-models/enums/)) and keeps the order of keys for them.

References:
- https://www.typescriptlang.org/docs/handbook/enums.html
- https://swagger.io/docs/specification/data-models/enums/


Patch:
diff --git a/lib/utils/enum.utils.ts b/lib/utils/enum.utils.ts
index c33fb54c..9ddab59b 100644
--- a/lib/utils/enum.utils.ts
+++ b/lib/utils/enum.utils.ts
@@ -10,22 +10,27 @@ export function getEnumValues(enumType: SwaggerEnumType): string[] | number[] {
   if (typeof enumType !== 'object') {
     return [];
   }
+  /*
+    Enums with numeric values
+      enum Size {
+        SMALL = 1,
+        BIG = 2
+      }
+    are transpiled to include a reverse mapping
+      const Size = {
+        "1": "SMALL",
+        "2": "BIG",
+        "SMALL": 1,
+        "BIG": 2,
+      }
+   */
+  const numericValues = Object.values(enumType)
+    .filter((value) => typeof value === 'number')
+    .map((value) => value.toString());
 
-  const values = [];
-  const uniqueValues = {};
-
-  for (const key in enumType) {
-    const value = enumType[key];
-    // filter out cases where enum key also becomes its value (A: B, B: A)
-    if (
-      !uniqueValues.hasOwnProperty(value) &&
-      !uniqueValues.hasOwnProperty(key)
-    ) {
-      values.push(value);
-      uniqueValues[value] = value;
-    }
-  }
-  return values;
+  return Object.keys(enumType)
+    .filter((key) => !numericValues.includes(key))
+    .map((key) => enumType[key]);
 }
 
 export function getEnumType(values: (string | number)[]): 'string' | 'number' {


Test patch:
diff --git a/test/explorer/swagger-explorer.spec.ts b/test/explorer/swagger-explorer.spec.ts
index 9b3e0d32..648ca7cc 100644
--- a/test/explorer/swagger-explorer.spec.ts
+++ b/test/explorer/swagger-explorer.spec.ts
@@ -860,9 +860,9 @@ describe('SwaggerExplorer', () => {
     }
 
     enum QueryEnum {
-      D = 'd',
-      E = 'e',
-      F = 'f'
+      D = 1,
+      E,
+      F = (() => 3)()
     }
 
     class Foo {}
@@ -952,8 +952,8 @@ describe('SwaggerExplorer', () => {
           name: 'order',
           required: true,
           schema: {
-            type: 'string',
-            enum: ['d', 'e', 'f']
+            type: 'number',
+            enum: [1, 2, 3]
           }
         },
         {
@@ -994,8 +994,8 @@ describe('SwaggerExplorer', () => {
           name: 'order',
           required: true,
           schema: {
-            type: 'string',
-            enum: ['d', 'e', 'f']
+            type: 'number',
+            enum: [1, 2, 3]
           }
         },
         {