Skip to content
This repository was archived by the owner on Jan 19, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions src/commands/types/generate/actions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand Down Expand Up @@ -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');
Expand Down
59 changes: 5 additions & 54 deletions src/commands/types/generate/actions.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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<Record<string, any>>(component.schema).reduce(
const requiredFields = Object.entries<Record<string, any>>(component?.schema || {}).reduce(
(acc, [key, value]) => {
if (value.required) {
return [...acc, key];
Expand Down Expand Up @@ -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
Expand Down