Skip to content
This repository was archived by the owner on Jan 19, 2026. It is now read-only.

feat: types-generate-cmd#169

Merged
alvarosabu merged 17 commits into
nextfrom
feature/types-generate-cmd
Apr 14, 2025
Merged

feat: types-generate-cmd#169
alvarosabu merged 17 commits into
nextfrom
feature/types-generate-cmd

Conversation

@alvarosabu
Copy link
Copy Markdown
Contributor

@alvarosabu alvarosabu commented Apr 7, 2025

Type Generation Command

The Storyblok type generation command allows you to generate TypeScript type definitions for your Storyblok components. This is particularly useful for ensuring type safety when working with Storyblok content in your frontend applications.

Prerequisites

Before generating types, ensure you have:

  • Access to the target Storyblok space
  • A Storyblok account with appropriate permissions
  • TypeScript installed in your project (if you plan to use the generated types)
  • Pull components from the target space using the storyblok components pull command

Basic Usage

# Generate types for all components in a space
storyblok types generate --space 12345

# Generate types with strict mode
storyblok types generate --space 12345 --strict

# Generate types with a custom prefix for component names
storyblok types generate --space 12345 --type-prefix "Custom"

# Generate types with a custom suffix for component names (if you used the same flag when pulling components)
storyblok types generate --space 12345 --suffix "Component"

# Generate types in separate files (if you used the same flag when pulling components)
storyblok types generate --space 12345 --separate-files

# Generate types with a custom fields parser
storyblok types generate --space 12345 --custom-fields-parser ./path/to/parser.ts

# Generate types with custom compiler options
storyblok types generate --space 12345 --compiler-options ./path/to/options.json

Architecture & Flow

The type generation command is organized in three main layers with a specific processing flow to ensure accurate type generation.

Command Structure

// 1. Command Layer (index.ts)
typesCommand
  .command('generate')
  .option('--sf, --separate-files', 'Generate types in separate files')
  .option('--strict', 'Use strict mode for type generation')
  .option('--type-prefix <prefix>', 'Prefix to be prepended to all generated component type names')
  .option('--suffix <suffix>', 'Components suffix')
  .option('--custom-fields-parser <path>', 'Path to the parser file for Custom Field Types')
  .option('--compiler-options <options>', 'Path to the compiler options from json-schema-to-typescript')
  .action(async (options) => {
    // Command implementation
  });

// 2. Operations Layer (actions.ts)
  - generateTypes()
  - generateStoryblokTypes()
  - saveTypesToFile()

// 3. Actions Layer (actions.ts)
  - getComponentType()
  - getComponentPropertiesTypeAnnotations()
  - sanitizeComponentName()

Processing Flow Examples

1. Basic Type Generation

storyblok types generate --space 12345

Flow:

Read Phase

// 1. Read components from space
const spaceData = await readComponentsFiles({
  from: '12345',
  path: undefined
});

// 2. Generate Storyblok types
await generateStoryblokTypes({
  filename: undefined,
  path: undefined
});

Generation Phase

// 3. Generate component types
const typedefString = await generateTypes(spaceData, {
  // Default options
});

Save Phase

// 4. Save types to file
await saveTypesToFile('12345', typedefString, {
  // Default options
});

2. Strict Mode Type Generation

storyblok types generate --space 12345 --strict

Flow:

Generation Phase

// 1. Generate component types with strict mode
const typedefString = await generateTypes(spaceData, {
  strict: true
});

Type Annotation Example

// Without strict mode (loose types)
export interface Component {
  text?: string;
  image?: {
    filename: string;
    alt: string;
  };
  [k: string]: unknown; // Index signature for additional properties
}

// With strict mode
export interface Component {
  text?: string;
  image?: {
    filename: string;
    alt: string;
  };
  // No index signature, only explicitly defined properties are allowed
}

3. Custom Type Prefix

storyblok types generate --space 12345 --type-prefix "Custom"

Flow:

Component Type Generation

// 1. Get component type with prefix
const componentType = getComponentType(component.name, {
  typePrefix: 'Custom'
});

// 2. Result: "CustomComponentName" instead of "ComponentName"

4. Separate Files Generation

storyblok types generate --space 12345 --separate-files

Flow:

File Generation

// 1. Generate types for each component
for (const component of spaceData.components) {
  const componentType = getComponentType(component.name, options);
  const properties = getComponentPropertiesTypeAnnotations(component.schema, options);
  
  // 2. Create a separate file for each component
  const fileContent = `export interface ${componentType} {
  ${properties}
}`;
  
  // 3. Save to a separate file
  await saveToFile(`${component.name}.d.ts`, fileContent);
}

5. Custom Fields Parser

storyblok types generate --space 12345 --custom-fields-parser ./path/to/parser.ts

Flow:

Parser Loading

// 1. Load custom fields parser
const customFieldsParser = await import('./path/to/parser.ts');

// 2. Use parser for custom field types
const propertyType = customFieldsParser(property);

Key Features

Type Safety

  • Generate TypeScript interfaces for all Storyblok components
  • Ensure type safety when working with Storyblok content
  • Reduce runtime errors by catching type issues at compile time

Customization Options

  • Add prefixes to component type names
  • Add suffixes to component type names
  • Generate types in separate files
  • Use strict mode for more precise types
  • Customize compiler options

Custom Field Support

  • Parse custom field types with a custom parser
  • Extend type generation for non-standard field types
  • Support for complex field structures

Storyblok Type Definitions

  • Generate type definitions for Storyblok's built-in field types
  • Include type definitions for Storyblok's API responses
  • Ensure complete type coverage for Storyblok integration

Type Generation File Structure

Generated type files follow this structure:

// For a component named "hero" with text and image fields
export interface Hero {
  text: string;
  image: {
    filename: string;
    alt: string;
  };
}

// For a component with nested bloks
export interface Page {
  title: string;
  sections: Array<{
    component: string;
    _uid: string;
    text?: string;
    image?: {
      filename: string;
      alt: string;
    };
  }>;
}

Testing Strategy

The command includes comprehensive test coverage:

Unit Tests

  • Component type generation
  • Property type annotation generation
  • Custom field parsing
  • File saving functionality

Testing Checklist

Running Type Generation

General

  • It should show the command title
  • It should throw an error if the user is not logged in: "You are currently not logged in. Please login first to get your user info."

Required Arguments

  • --space=TARGET_SPACE_ID
    • It should read components from the target space
    • It should generate types for all components
    • It should save the generated types to a file

Options

  • --strict

    • It should generate strict types without the [k: string]: unknown index signature
    • It should only allow explicitly defined properties
  • --type-prefix=<prefix>

    • It should prepend the prefix to all component type names
    • It should handle special characters in the prefix
  • --suffix=<suffix>

    • It should append the suffix to all component type names
    • It should handle special characters in the suffix
  • --separate-files

    • It should generate a separate file for each component
    • It should name files according to component names
  • --custom-fields-parser=<path>

    • It should load the custom fields parser from the specified path
    • It should use the parser for custom field types
  • --compiler-options=<options>

    • It should load compiler options from the specified path
    • It should apply the options to the type generation

Error Handling

  • It should throw an error if the space is not provided: "Please provide the space as argument --space YOUR_SPACE_ID."
  • It should handle errors during type generation gracefully
  • It should provide meaningful error messages for common issues

…tion

- Introduced new utility functions in `format.ts` for converting strings to PascalCase, CamelCase, and SnakeCase.
- Added functions for masking tokens, slugifying text, and recursively removing properties from objects.
- Implemented a method to convert objects to string parameters for URLSearchParams.
- Created a function to generate regex patterns from glob patterns.
- Updated `index.ts` to export the new formatting utilities.
- Refactored the type generation logic to improve handling of component types, including sanitization of component names.
- Introduced a new `ComponentPropertySchema` interface and related types in `schemas.ts` for better type safety and organization.
- Updated the `generateStoryblokTypes` function to read type definitions from an external file, ensuring a more robust extraction process.
- Removed redundant type definitions from `storyblok.ts` to streamline the codebase and avoid duplication.
- Added support for component restrictions based on groups and individual whitelists in `getComponentPropertiesTypeAnnotations`.
- Introduced a new parameter `componentsMaps` to facilitate the mapping of component groups and names.
- Updated the `generateTypes` function to pass the new `componentsMaps` parameter, improving type safety and flexibility in handling component properties.
- Updated `generateTypes` and `getComponentPropertiesTypeAnnotations` functions to utilize `spaceData` instead of `componentsMaps`, improving type safety and flexibility.
- Added null checks for `spaceData.components` to prevent runtime errors.
- Removed the redundant `generateComponentGroupsAndComponentNames` function to streamline the codebase.
- Improved error handling in the `generateTypes` function by implementing a try/catch block to manage asynchronous errors effectively.
- Refactored `GenerateTypesOptions` to replace `typeNamesPrefix` and `typeNamesSuffix` with a single `typePrefix` option for improved clarity and usability.
- Enhanced `getComponentType` function to utilize the new `typePrefix` option, simplifying the type name generation process.
- Updated command options in `index.ts` to include `--type-prefix` for better user experience when generating component types.
- Adjusted handling of Storyblok property types to ensure consistent type generation without unnecessary prefixes.
- Introduced a new launch configuration in `.vscode/launch.json` for debugging the type generation process with separate files.
- This configuration allows for easier debugging of the type generation command, enhancing the development experience.
- Removed the optional `[componentName]` parameter from the `generate` command to streamline the command usage.
- Eliminated the `--fi, --filter <filter>` option to reduce complexity in type generation, focusing on essential flags for better clarity and usability.
- Added a new `suffix` option to the `GenerateTypesOptions` interface to allow for suffix customization during type generation.
- Updated the `generate` command in `index.ts` to utilize the new `suffix` option, improving flexibility in type generation.
- Modified the VSCode launch configuration to include a new debug option for generating types with a specified suffix, enhancing the development experience.
- Added a new `customFieldsParser` option to the `GenerateTypesOptions` interface, allowing for custom field type handling during type generation.
- Introduced a `custom-fields-parser.ts` file to define the structure for the 'native-color-picker' field type.
- Updated the `getComponentPropertiesTypeAnnotations` function to utilize the custom fields parser when available, enhancing flexibility in type generation.
- Enhanced the `generate` command in `index.ts` to support the new `--custom-fields-parser` option for specifying the parser file path.
- Modified the VSCode launch configuration to include a debug option for generating types with a custom fields parser, improving the development experience.
- Introduced a new `compilerOptions` option in the `GenerateTypesOptions` interface to allow for custom compiler configurations during type generation.
- Implemented a `compiler-options.ts` file to define default compiler settings.
- Updated the `generateTypes` function to load and apply compiler options when generating types, enhancing flexibility and customization.
- Enhanced the `getComponentPropertiesTypeAnnotations` function to support the new `customFieldsParser` type definition.
- Modified the VSCode launch configuration to include a debug option for generating types with specified compiler options, improving the development experience.
- Introduced a new test file `actions.test.ts` to validate the functionality of type generation actions.
- Implemented tests for `generateTypes` and `getComponentType` functions, covering various scenarios including strict mode, custom fields parser, and component property type annotations.
- Mocked necessary modules and created a virtual file system to simulate file operations, ensuring isolated and reliable tests.
- Enhanced test coverage for handling different property types such as text, textarea, number, boolean, multilink, and custom types.
- Verified that generated types align with expected outputs, improving the robustness of the type generation feature.
- Introduced a new test file `index.test.ts` to validate the functionality of the type generation command.
- Implemented tests for various scenarios including successful type generation, strict mode, type prefix, suffix, separate files, custom fields parser, and compiler options.
- Mocked necessary modules and created a controlled environment to ensure isolated and reliable tests.
- Enhanced test coverage for different command options, improving the robustness of the type generation feature.
- Removed the unused `CommandError` import from `index.test.ts` to clean up the code and improve readability.
- This change helps maintain a tidy codebase by eliminating unnecessary dependencies.
@alvarosabu alvarosabu requested a review from edodusi April 14, 2025 09:00
@alvarosabu alvarosabu self-assigned this Apr 14, 2025
@alvarosabu alvarosabu added breaking-change Changes that cause backward compatibility issues and will require a major version. p3-significant [Priority] Moderate issues, major enhancements feature [Issue] New feature or request labels Apr 14, 2025
@alvarosabu alvarosabu merged commit d80dfa0 into next Apr 14, 2025
@alvarosabu alvarosabu changed the title feat: types-generate-cmd WIP feat: types-generate-cmd Apr 14, 2025
@alvarosabu alvarosabu added this to the v4-beta milestone Apr 22, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

breaking-change Changes that cause backward compatibility issues and will require a major version. feature [Issue] New feature or request p3-significant [Priority] Moderate issues, major enhancements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant