diff --git a/src/commands/types/generate/actions.test.ts b/src/commands/types/generate/actions.test.ts index 8c5985b..0e345b9 100644 --- a/src/commands/types/generate/actions.test.ts +++ b/src/commands/types/generate/actions.test.ts @@ -611,9 +611,10 @@ describe('generateStoryblokTypes', () => { expect(readFileSync).toHaveBeenCalledWith('/mocked/path', 'utf-8'); // Verify that saveToFile was called with the correct parameters - expect(saveToFile).toHaveBeenCalledWith('/mocked/joined/path', expect.stringContaining('// This file was generated by the storyblok CLI.')); - expect(saveToFile).toHaveBeenCalledWith('/mocked/joined/path', expect.stringContaining('export type StoryblokPropertyType')); - expect(saveToFile).toHaveBeenCalledWith('/mocked/joined/path', expect.stringContaining('export interface StoryblokText')); + expect(saveToFile).toHaveBeenCalledWith( + '/mocked/joined/path', + expect.stringMatching(/^\/\/ This file was generated by the Storyblok CLI\.\n\/\/ DO NOT MODIFY THIS FILE BY HAND\.\n\n.*Storyblok.*/), + ); }); it('should generate Storyblok types with custom filename', async () => { @@ -647,7 +648,7 @@ describe('generateStoryblokTypes', () => { const savedContent = vi.mocked(saveToFile).mock.calls[0][1]; // Verify that all expected type definitions are included - expect(savedContent).toContain('export type StoryblokPropertyType'); + expect(savedContent).toContain('export type StoryblokPropertyType = \'text\' | \'textarea\' | \'number\' | \'boolean\' | \'multilink\' | \'bloks\' | \'custom\';'); expect(savedContent).toContain('export interface StoryblokText'); expect(savedContent).toContain('export interface StoryblokTextarea'); expect(savedContent).toContain('export interface StoryblokNumber'); diff --git a/src/commands/types/generate/actions.ts b/src/commands/types/generate/actions.ts index 90cbf1e..0c2eb6b 100644 --- a/src/commands/types/generate/actions.ts +++ b/src/commands/types/generate/actions.ts @@ -1,6 +1,6 @@ import { compile, type JSONSchema } from 'json-schema-to-typescript'; import type { SpaceComponent, SpaceData } from '../../../commands/components/constants'; -import { handleError, handleFileSystemError, toCamelCase, toPascalCase } from '../../../utils'; +import { __dirname, handleError, handleFileSystemError, toCamelCase, toPascalCase } from '../../../utils'; import type { GenerateTypesOptions } from './constants'; import type { StoryblokPropertyType } from '../../../types/storyblok'; import { storyblokSchemas } from '../../../utils/storyblok-schemas'; @@ -231,7 +231,7 @@ export const generateTypes = async ( // Get the component type name with proper handling of numbers at the start const type = getComponentType(component.name, options); const componentPropertiesTypeAnnotations = await getComponentPropertiesTypeAnnotations(component, options, spaceData, customFieldsParser); - const requiredFields = Object.entries>(component.schema).reduce( + const requiredFields = Object.entries>(component?.schema || {}).reduce( (acc, [key, value]) => { if (value.required) { return [...acc, key]; @@ -332,65 +332,16 @@ export const generateStoryblokTypes = async (options: SaveTypesOptions = {}) => try { // Get the path to the storyblok.ts file - const storyblokTypesPath = resolve(process.cwd(), 'src', 'types', 'storyblok.ts'); + const storyblokTypesPath = resolve(__dirname, './index.d.ts'); // Read the content of the storyblok.ts file const storyblokTypesContent = readFileSync(storyblokTypesPath, 'utf-8'); - // Extract the type definitions using a more robust approach - const lines = storyblokTypesContent.split('\n'); - const typeDefinitions: string[] = []; - let isCollecting = false; - let bracketCount = 0; - let currentType = ''; - - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; - - // Check if this line starts a type definition - if (line.includes('export type StoryblokPropertyType') - || line.includes('export interface Storyblok')) { - // If we were already collecting a type, add it to our results - if (isCollecting) { - typeDefinitions.push(''); - } - - isCollecting = true; - typeDefinitions.push(line); - currentType = line.includes('type') ? 'type' : 'interface'; - - // Count opening and closing braces to handle nested structures - bracketCount += (line.match(/\{/g) || []).length; - bracketCount -= (line.match(/\}/g) || []).length; - - // For types, we don't need to collect more lines - if (currentType === 'type') { - isCollecting = false; - continue; - } - - // For interfaces, continue collecting lines until we've matched all braces - let j = i + 1; - while (j < lines.length && bracketCount > 0) { - const nextLine = lines[j]; - bracketCount += (nextLine.match(/\{/g) || []).length; - bracketCount -= (nextLine.match(/\}/g) || []).length; - typeDefinitions.push(nextLine); - j++; - } - - // Skip the lines we've already processed - i = j - 1; - isCollecting = false; - } - } - // Define the content of the d.ts file const typeDefs = [ - '// This file was generated by the storyblok CLI.', + '// This file was generated by the Storyblok CLI.', '// DO NOT MODIFY THIS FILE BY HAND.', - '', - ...typeDefinitions, + storyblokTypesContent, ].join('\n'); // Determine the path to save the file