-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgenerate-types.ts
123 lines (110 loc) · 4.42 KB
/
generate-types.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#!/usr/bin/env node
import ts from 'ts-morph';
import { pascalCase } from 'change-case';
import { models, components, AttributesSetting } from './strapi-settings.js';
import { destroy } from './strapi.js';
const isReadonly = process.argv.includes('--immutable-types');
const project = new ts.Project();
const sf = project.createSourceFile('models.ts', '', { overwrite: true });
for (const [name, modelSetting] of Object.entries(models)) {
if (modelSetting.primaryKeyType !== 'integer') throw new Error(`Unsupported primary key type: ${modelSetting.primaryKeyType}`);
sf.addInterface({
name: modelInterfaceName(name),
isExported: true,
properties: [
{
name: modelSetting.primaryKey,
type: 'number',
isReadonly,
},
...interfacePropertiesFromAttributesSetting(modelSetting.attributes),
],
});
}
sf.addTypeAlias({
name: 'Model',
isExported: true,
type: Object.keys(models).map(name => modelInterfaceName(name)).join(' | '),
});
sf.addInterface({
isExported: true,
properties: Object.entries(models).map(([name]) => ({ name: `'${name}'`, type: modelInterfaceName(name), isReadonly })),
name: 'ModelByName',
});
for (const [name, setting] of Object.entries(components)) {
sf.addInterface({
name: componentInterfaceName(name),
isExported: true,
properties: interfacePropertiesFromAttributesSetting(setting.attributes),
});
}
sf.addTypeAlias({
name: 'Component',
isExported: true,
type: Object.keys(components).map(name => componentInterfaceName(name)).join(' | '),
});
sf.formatText({ indentSize: 2 });
sf.save();
console.log(`${Object.keys(models).length} models and ${Object.keys(components).length} components are imported and saved to models.ts.`);
destroy();
function modelInterfaceName(name: string) {
return pascalCase(name);
}
function componentInterfaceName(component: string) {
return `${pascalCase(component)}Component`;
}
function interfacePropertiesFromAttributesSetting(attributes: AttributesSetting) {
return Object.entries(attributes).flatMap(([name, attr]) => {
if (attr.writable === false) return [];
const isOptional = attr.required == undefined ? true : !attr.required;
const base = {
name,
hasQuestionToken: isOptional,
isReadonly,
} as const;
const optionalTypeSuffix = isOptional ? ' | null' : '';
if ('type' in attr) {
switch (attr.type) {
case 'text':
return [{ ...base, type: 'string' + optionalTypeSuffix }];
case 'string':
return [{ ...base, type: 'string' + optionalTypeSuffix }];
case 'richtext':
return [{ ...base, type: 'string' + optionalTypeSuffix }];
case 'integer':
return [{ ...base, type: 'number' + optionalTypeSuffix }];
case 'float':
return [{ ...base, type: 'number' + optionalTypeSuffix }];
case 'boolean':
return [{ ...base, type: 'boolean' + optionalTypeSuffix }];
case 'datetime':
return [{ ...base, type: 'string' + optionalTypeSuffix }];
case 'json':
return [{ ...base, type: 'unknown' + optionalTypeSuffix }];
case 'email':
return [{ ...base, type: 'string' + optionalTypeSuffix }];
case 'enumeration':
return [{ ...base, type: attr.enum.map(value => `'${value}'`).join(' | ') + optionalTypeSuffix }];
case 'component':
return [{
...base,
hasQuestionToken: attr.repeatable ? false : isOptional, // For repeatable component field, at least empty array is necessary.
type: attr.repeatable ? `${isReadonly ? 'readonly ' : ''}${componentInterfaceName(attr.component)}[]` : (componentInterfaceName(attr.component) + optionalTypeSuffix),
}];
case 'decimal':
return [{ ...base, type: 'number' + optionalTypeSuffix }];
case 'password':
return [{ ...base, type: 'string' + optionalTypeSuffix }];
}
}
if ('model' in attr) {
// return [{ ...base, type: modelInterfaceName(attr.model) + optionalTypeSuffix }];
return [{ ...base, type: 'number' + optionalTypeSuffix }];
}
if ('collection' in attr) {
// return [{ ...base, type: attr.collection === '*' ? 'any' : modelInterfaceName(attr.collection) + optionalTypeSuffix }];
return [{ ...base, type: `${isReadonly ? 'readonly ' : ''}number[]` + optionalTypeSuffix }];
}
throw new Error(`Unknown attribute type: ${JSON.stringify(attr)}`);
})
}