1
1
import { compile , type JSONSchema } from 'json-schema-to-typescript' ;
2
2
import type { SpaceComponent , SpaceData } from '../../../commands/components/constants' ;
3
- import { __dirname , handleError , handleFileSystemError , toCamelCase , toPascalCase } from '../../../utils' ;
3
+ import { __dirname , capitalize , handleError , handleFileSystemError , toCamelCase , toPascalCase } from '../../../utils' ;
4
4
import type { GenerateTypesOptions } from './constants' ;
5
5
import type { StoryblokPropertyType } from '../../../types/storyblok' ;
6
6
import { storyblokSchemas } from '../../../utils/storyblok-schemas' ;
@@ -15,20 +15,20 @@ export interface ComponentGroupsAndNamesObject {
15
15
}
16
16
17
17
// Constants
18
+ const STORY_TYPE = 'ISbStoryData' ;
18
19
const DEFAULT_TYPEDEFS_HEADER = [
19
20
'// This file was generated by the storyblok CLI.' ,
20
21
'// DO NOT MODIFY THIS FILE BY HAND.' ,
21
22
] ;
22
23
23
- const getPropertyTypeAnnotation = ( property : ComponentPropertySchema ) => {
24
+ const getPropertyTypeAnnotation = ( property : ComponentPropertySchema , prefix ?: string ) => {
24
25
// If a property type is one of the ones provided by Storyblok, return that type
25
26
// Casting as string[] to avoid TS error on using Array.includes on different narrowed types
26
27
if ( Array . from ( storyblokSchemas . keys ( ) ) . includes ( property . type as StoryblokPropertyType ) ) {
27
28
return { type : property . type } ;
28
29
}
29
-
30
30
// Initialize property type as any (fallback type)
31
- // const type: string | string[] = 'any ';
31
+ let type : string | string [ ] = 'unknown ' ;
32
32
33
33
const options = property . options && property . options . length > 0 ? property . options . map ( ( item : { value : string } ) => item . value ) : [ ] ;
34
34
@@ -37,6 +37,67 @@ const getPropertyTypeAnnotation = (property: ComponentPropertySchema) => {
37
37
options . unshift ( '' ) ;
38
38
}
39
39
40
+ if ( property . source === 'internal_stories' ) {
41
+ // Only if there is a filter_content_type, we can return a proper type
42
+ if ( property . filter_content_type ) {
43
+ if ( typeof property . filter_content_type === 'string' ) {
44
+ return {
45
+ tsType : `(${ getStoryType ( property . filter_content_type , prefix ) } | string )${ property . type === 'options' ? '[]' : '' } ` ,
46
+ } ;
47
+ }
48
+
49
+ return {
50
+ tsType : `(${ property . filter_content_type
51
+ . map ( type2 => getStoryType ( type2 , prefix ) )
52
+ // In this case property.type can be `option` or `options`. In case of `options` the type should be an array
53
+ . join ( ' | ' ) } | string )${ property . type === 'options' ? '[]' : '' } `,
54
+ } ;
55
+ }
56
+ }
57
+
58
+ if (
59
+ // If there is no `source` and there are options, the data source is the component itself
60
+ // TODO: check if this is an old behaviour (shouldn't this be handled as an "internal" source?)
61
+ ( options . length > 0 && ! property . source )
62
+ || property . source === 'internal_languages'
63
+ || property . source === 'external'
64
+ ) {
65
+ type = 'string' ;
66
+ }
67
+
68
+ if ( property . source === 'internal' ) {
69
+ type = [ 'number' , 'string' ] ;
70
+ }
71
+
72
+ if ( property . type === 'option' ) {
73
+ if ( options . length > 0 ) {
74
+ return {
75
+ type,
76
+ enum : options ,
77
+ } ;
78
+ }
79
+
80
+ return {
81
+ type,
82
+ } ;
83
+ }
84
+
85
+ if ( property . type === 'options' ) {
86
+ if ( options . length > 0 ) {
87
+ return {
88
+ type : 'array' ,
89
+ items : {
90
+ enum : options ,
91
+ } ,
92
+ } ;
93
+ }
94
+
95
+ return {
96
+ type : 'array' ,
97
+ items : { type } ,
98
+ } ;
99
+ }
100
+
40
101
switch ( property . type ) {
41
102
case 'bloks' :
42
103
return { type : 'array' } ;
@@ -54,6 +115,10 @@ const getPropertyTypeAnnotation = (property: ComponentPropertySchema) => {
54
115
}
55
116
} ;
56
117
118
+ export function getStoryType ( property : string , prefix ?: string ) {
119
+ return `${ STORY_TYPE } <${ prefix ?? '' } ${ capitalize ( toCamelCase ( property ) ) } >` ;
120
+ }
121
+
57
122
/**
58
123
* Generates a TypeScript type name for a component
59
124
* @param componentName - The name of the component
@@ -102,7 +167,7 @@ const getComponentPropertiesTypeAnnotations = async (
102
167
103
168
const propertyType = value . type ;
104
169
const propertyTypeAnnotation : JSONSchema = {
105
- [ key ] : getPropertyTypeAnnotation ( value as ComponentPropertySchema ) ,
170
+ [ key ] : getPropertyTypeAnnotation ( value as ComponentPropertySchema , options . typePrefix ) ,
106
171
} ;
107
172
108
173
if ( propertyType === 'custom' && customFieldsParser ) {
0 commit comments