diff --git a/src/import/crd.ts b/src/import/crd.ts index 048a6cb21..45cdfd953 100644 --- a/src/import/crd.ts +++ b/src/import/crd.ts @@ -43,6 +43,74 @@ const SUPPORTED_API_VERSIONS = [ type CustomResourceDefinitionVersion = { name: string; schema?: any }; +/** + * TypeScript built-in utility types that may conflict with CRD kind names. + * When a CRD's kind matches one of these, we need to post-process the generated + * code to avoid naming conflicts. + */ +const TYPESCRIPT_BUILTIN_TYPES = new Set([ + 'Record', + 'Map', + 'Set', + 'Array', + 'Object', + 'String', + 'Number', + 'Boolean', + 'Symbol', + 'Function', + 'Promise', + 'Pick', + 'Omit', + 'Partial', + 'Required', + 'Readonly', + 'Extract', + 'Exclude', + 'NonNullable', + 'Parameters', + 'ReturnType', + 'InstanceType', + 'ThisType', + 'Awaited', +]); + +/** + * Post-processes generated TypeScript code to fix naming conflicts with + * TypeScript built-in utility types. + * + * When a CRD's kind matches a TypeScript built-in (e.g., "Record"), the generated + * code will have a class named "Record" which shadows the built-in Record + * utility type. This function replaces usages of the built-in type with an alias. + * + * @param renderedCode The TypeScript code generated by TypeGenerator + * @param kind The CRD kind name + * @returns Post-processed code with conflicts resolved + */ +function fixBuiltinTypeConflicts(renderedCode: string, kind: string): string { + if (!TYPESCRIPT_BUILTIN_TYPES.has(kind)) { + return renderedCode; + } + + // Replace usages of the built-in type with the alias + // Match patterns like "Record" but not "RecordProps" or "Record.GVK" + const pattern = new RegExp(`\\b${kind}<([^>]+)>`, 'g'); + return renderedCode.replace(pattern, `Json${kind}<$1>`); +} + +/** + * Generates the type alias needed to fix naming conflicts with TypeScript built-in types. + * + * @param kind The CRD kind name + * @returns The type alias declaration, or empty string if not needed + */ +function getBuiltinTypeAlias(kind: string): string { + if (!TYPESCRIPT_BUILTIN_TYPES.has(kind)) { + return ''; + } + return `// Type alias to avoid collision with the ${kind} class defined below\ntype Json${kind} = { [P in K]: T };\n\n`; +} + export class CustomResourceDefinition { private readonly kind: string; @@ -95,6 +163,12 @@ export class CustomResourceDefinition { public async generateTypeScript(code: CodeMaker, options: GenerateOptions) { + // Add type alias once at the beginning if needed for built-in type conflicts + const typeAlias = getBuiltinTypeAlias(this.kind); + if (typeAlias) { + code.line(typeAlias); + } + for (let i = 0; i < this.versions.length; i++) { const version = this.versions[i]; @@ -116,7 +190,9 @@ export class CustomResourceDefinition { suffix, }); - code.line(types.render()); + // Post-process to fix any TypeScript built-in type conflicts + const renderedCode = fixBuiltinTypeConflicts(types.render(), this.kind); + code.line(renderedCode); } } }