From c5e809c76c759e33a6336898d56d4c3ca7e6a761 Mon Sep 17 00:00:00 2001 From: Vinayak Kukreja <78971045+vinayak-kukreja@users.noreply.github.com> Date: Wed, 22 Nov 2023 06:05:32 -0800 Subject: [PATCH] fix: same values but different casing creates conflicting enums (#1259) Enums in schema which has same value but different casing creates same enum values which conflicts with each other. For instance, [observed](https://github.com/cdk8s-team/cdk8s-cli/issues/578#issuecomment-1559646717) while importing a custom resource definition in cdk8s. ``` \| 1086 REPLACE = 'replace', -- \| ~~~~~~~ \| com.coreos.monitoring.ts:1088:3 - error TS2300: Duplicate identifier 'REPLACE'. \| 1088 REPLACE = 'Replace', \| ~~~~~~~ \| com.coreos.monitoring.ts:1090:3 - error TS2300: Duplicate identifier 'KEEP'. \| 1090 KEEP = 'keep', \| ~~~~ \| com.coreos.monitoring.ts:1092:3 - error TS2300: Duplicate identifier 'KEEP'. \| 1092 KEEP = 'Keep', \| ~~~~ \| com.coreos.monitoring.ts:1094:3 - error TS2300: Duplicate identifier 'DROP'. \| 1094 DROP = 'drop', \| ~~~~ \| com.coreos.monitoring.ts:1096:3 - error TS2300: Duplicate identifier 'DROP'. \| 1096 DROP = 'Drop', ``` Fixes https://github.com/cdk8s-team/cdk8s-cli/issues/578 --------- Signed-off-by: Vinayak Kukreja --- src/type-generator.ts | 11 +++++ .../__snapshots__/type-generator.test.ts.snap | 46 +++++++++++++++++++ test/type-generator.test.ts | 20 ++++++++ 3 files changed, 77 insertions(+) diff --git a/src/type-generator.ts b/src/type-generator.ts index 4e22107bfe..3b4390012c 100644 --- a/src/type-generator.ts +++ b/src/type-generator.ts @@ -521,6 +521,8 @@ export class TypeGenerator { code.openBlock(`export enum ${typeName}`); + const processedValues = new Set(); + for (const value of def.enum) { if (!['string', 'number'].includes(typeof(value))) { throw new Error('only enums with string or number values are supported'); @@ -529,6 +531,15 @@ export class TypeGenerator { // sluggify and turn to UPPER_SNAKE_CASE let memberName = snakeCase(`${value}`.replace(/[^a-z0-9]/gi, '_')).split('_').filter(x => x).join('_').toUpperCase(); + // If enums of same value exists, then we choose one of them and skip adding others + // since that would cause conflict + const lowerCaseValue = value?.toString().toLowerCase(); + if (lowerCaseValue && !processedValues.has(lowerCaseValue)) { + processedValues.add(lowerCaseValue); + } else { + continue; + } + // if member name starts with a non-alpha character, add a prefix so it becomes a symbol if (!/^[A-Z].*/i.test(memberName)) { memberName = 'VALUE_' + memberName; diff --git a/test/__snapshots__/type-generator.test.ts.snap b/test/__snapshots__/type-generator.test.ts.snap index a15ffb0073..7accedf938 100644 --- a/test/__snapshots__/type-generator.test.ts.snap +++ b/test/__snapshots__/type-generator.test.ts.snap @@ -311,6 +311,52 @@ export enum FqnOfTestTypePercentiles { " `; +exports[`enums has repeated values 1`] = ` +"/** + * @schema fqn.of.TestType + */ +export interface TestType { + /** + * @schema fqn.of.TestType#Same + */ + readonly same?: FqnOfTestTypeSame; + +} + +/** + * Converts an object of type 'TestType' to JSON representation. + */ +/* eslint-disable max-len, quote-props */ +export function toJson_TestType(obj: TestType | undefined): Record | undefined { + if (obj === undefined) { return undefined; } + const result = { + 'Same': obj.same, + }; + // filter undefined values + return Object.entries(result).reduce((r, i) => (i[1] === undefined) ? r : ({ ...r, [i[0]]: i[1] }), {}); +} +/* eslint-enable max-len, quote-props */ + +/** + * @schema FqnOfTestTypeSame + */ +export enum FqnOfTestTypeSame { + /** replace */ + REPLACE = \\"replace\\", + /** keep */ + KEEP = \\"keep\\", + /** hashmod */ + HASHMOD = \\"hashmod\\", + /** labelmap */ + LABELMAP = \\"labelmap\\", + /** 24 */ + VALUE_24 = \\"24\\", + /** 0.99 */ + VALUE_0_99 = \\"0.99\\", +} +" +`; + exports[`enums renders a typescript enum 1`] = ` "/** * @schema fqn.of.TestType diff --git a/test/type-generator.test.ts b/test/type-generator.test.ts index be3cd9d4cb..0b88dba519 100644 --- a/test/type-generator.test.ts +++ b/test/type-generator.test.ts @@ -300,6 +300,26 @@ describe('enums', () => { }, }, }); + + which('has repeated values', { + properties: { + Same: { + type: 'string', + enum: [ + 'replace', + 'Replace', + 'keep', + 'Keep', + 'hashmod', + 'HashMod', + 'labelmap', + 'LabelMap', + '24', + '0.99', + ], + }, + }, + }); }); which('primitives', {