@strapi/typescript-utils 0.0.0-4fc90398602f → 0.0.0-8581854cb3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/__tests__/generators/schemas/attributes.test.js +2 -2
- package/lib/__tests__/generators/schemas/global.test.js +1 -1
- package/lib/admin/create-tsconfig-file.js +1 -1
- package/lib/compilers/watch.js +4 -4
- package/lib/generators/schemas/attributes.js +149 -26
- package/lib/generators/schemas/global.js +19 -21
- package/lib/generators/schemas/imports.js +1 -1
- package/lib/generators/schemas/index.js +63 -63
- package/lib/generators/schemas/schema.js +32 -32
- package/lib/generators/schemas/utils.js +18 -18
- package/lib/utils/report-diagnostics.js +1 -1
- package/lib/utils/resolve-config-options.js +1 -1
- package/lib/utils/resolve-outdir.js +0 -1
- package/package.json +2 -2
- package/lib/generators/schemas/mappers.js +0 -131
|
@@ -23,11 +23,11 @@ describe('Attributes', () => {
|
|
|
23
23
|
const schema = { uid: 'api::foo.foo' };
|
|
24
24
|
const attributeName = 'foo';
|
|
25
25
|
|
|
26
|
-
const toPropertySignature =
|
|
26
|
+
const toPropertySignature = attribute => {
|
|
27
27
|
return attributeToPropertySignature(schema, attributeName, attribute);
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
-
const defaultAssertion =
|
|
30
|
+
const defaultAssertion = node => {
|
|
31
31
|
expect(node.kind).toBe(ts.SyntaxKind.PropertySignature);
|
|
32
32
|
expect(node.name.escapedText).toBe(attributeName);
|
|
33
33
|
expect(node.type.kind).toBe(ts.SyntaxKind.IntersectionType);
|
|
@@ -17,7 +17,7 @@ describe('Global', () => {
|
|
|
17
17
|
jest.resetAllMocks();
|
|
18
18
|
});
|
|
19
19
|
|
|
20
|
-
const assertGlobalNodeStructure =
|
|
20
|
+
const assertGlobalNodeStructure = node => {
|
|
21
21
|
// "declare global"
|
|
22
22
|
expect(node.kind).toBe(ts.SyntaxKind.ModuleDeclaration);
|
|
23
23
|
expect(node.modifiers).toHaveLength(1);
|
package/lib/compilers/watch.js
CHANGED
|
@@ -10,7 +10,7 @@ const resolveConfigOptions = require('../utils/resolve-config-options');
|
|
|
10
10
|
* Prints a diagnostic every time the watch status changes.
|
|
11
11
|
* This is mainly for messages like "Starting compilation" or "Compilation completed".
|
|
12
12
|
*/
|
|
13
|
-
const reportWatchStatusChanged =
|
|
13
|
+
const reportWatchStatusChanged = diagnostic => {
|
|
14
14
|
console.info(ts.formatDiagnostic(diagnostic, formatHost));
|
|
15
15
|
};
|
|
16
16
|
|
|
@@ -18,9 +18,9 @@ module.exports = {
|
|
|
18
18
|
run(configPath) {
|
|
19
19
|
const createProgram = ts.createSemanticDiagnosticsBuilderProgram;
|
|
20
20
|
|
|
21
|
-
const { fileNames, options, projectReferences, watchOptions } =
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
const { fileNames, options, projectReferences, watchOptions } = resolveConfigOptions(
|
|
22
|
+
configPath
|
|
23
|
+
);
|
|
24
24
|
const host = ts.createWatchCompilerHost(
|
|
25
25
|
fileNames,
|
|
26
26
|
options,
|
|
@@ -1,11 +1,38 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const ts = require('typescript');
|
|
3
4
|
const { factory } = require('typescript');
|
|
4
5
|
const _ = require('lodash/fp');
|
|
5
6
|
|
|
6
7
|
const { addImport } = require('./imports');
|
|
7
8
|
const { getTypeNode, toTypeLiteral } = require('./utils');
|
|
8
|
-
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Generate a property signature node for a given attribute
|
|
12
|
+
*
|
|
13
|
+
* @param {object} schema
|
|
14
|
+
* @param {string} attributeName
|
|
15
|
+
* @param {object} attribute
|
|
16
|
+
* @returns {object}
|
|
17
|
+
*/
|
|
18
|
+
const attributeToPropertySignature = (schema, attributeName, attribute) => {
|
|
19
|
+
const baseType = getAttributeType(attributeName, attribute, schema.uid);
|
|
20
|
+
|
|
21
|
+
if (baseType === null) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const modifiers = getAttributeModifiers(attribute);
|
|
26
|
+
|
|
27
|
+
const nodes = [baseType, ...modifiers];
|
|
28
|
+
|
|
29
|
+
return factory.createPropertySignature(
|
|
30
|
+
undefined,
|
|
31
|
+
factory.createIdentifier(attributeName),
|
|
32
|
+
undefined,
|
|
33
|
+
factory.createIntersectionTypeNode(nodes)
|
|
34
|
+
);
|
|
35
|
+
};
|
|
9
36
|
|
|
10
37
|
/**
|
|
11
38
|
* Create the base type node for a given attribute
|
|
@@ -37,7 +64,7 @@ const getAttributeType = (attributeName, attribute, uid) => {
|
|
|
37
64
|
* @param {object} attribute
|
|
38
65
|
* @returns {object[]}
|
|
39
66
|
*/
|
|
40
|
-
const getAttributeModifiers =
|
|
67
|
+
const getAttributeModifiers = attribute => {
|
|
41
68
|
const modifiers = [];
|
|
42
69
|
|
|
43
70
|
// Required
|
|
@@ -124,31 +151,127 @@ const getAttributeModifiers = (attribute) => {
|
|
|
124
151
|
return modifiers;
|
|
125
152
|
};
|
|
126
153
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
154
|
+
const mappers = {
|
|
155
|
+
string() {
|
|
156
|
+
return ['StringAttribute'];
|
|
157
|
+
},
|
|
158
|
+
text() {
|
|
159
|
+
return ['TextAttribute'];
|
|
160
|
+
},
|
|
161
|
+
richtext() {
|
|
162
|
+
return ['RichTextAttribute'];
|
|
163
|
+
},
|
|
164
|
+
password() {
|
|
165
|
+
return ['PasswordAttribute'];
|
|
166
|
+
},
|
|
167
|
+
email() {
|
|
168
|
+
return ['EmailAttribute'];
|
|
169
|
+
},
|
|
170
|
+
date() {
|
|
171
|
+
return ['DateAttribute'];
|
|
172
|
+
},
|
|
173
|
+
time() {
|
|
174
|
+
return ['TimeAttribute'];
|
|
175
|
+
},
|
|
176
|
+
datetime() {
|
|
177
|
+
return ['DateTimeAttribute'];
|
|
178
|
+
},
|
|
179
|
+
timestamp() {
|
|
180
|
+
return ['TimestampAttribute'];
|
|
181
|
+
},
|
|
182
|
+
integer() {
|
|
183
|
+
return ['IntegerAttribute'];
|
|
184
|
+
},
|
|
185
|
+
biginteger() {
|
|
186
|
+
return ['BigIntegerAttribute'];
|
|
187
|
+
},
|
|
188
|
+
float() {
|
|
189
|
+
return ['FloatAttribute'];
|
|
190
|
+
},
|
|
191
|
+
decimal() {
|
|
192
|
+
return ['DecimalAttribute'];
|
|
193
|
+
},
|
|
194
|
+
uid({ attribute, uid }) {
|
|
195
|
+
const { targetField, options } = attribute;
|
|
196
|
+
|
|
197
|
+
// If there are no params to compute, then return the attribute type alone
|
|
198
|
+
if (targetField === undefined && options === undefined) {
|
|
199
|
+
return ['UIDAttribute'];
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const params = [];
|
|
203
|
+
|
|
204
|
+
// If the targetField property is defined, then reference it,
|
|
205
|
+
// otherwise, put `undefined` keyword type nodes as placeholders
|
|
206
|
+
const targetFieldParams = _.isUndefined(targetField)
|
|
207
|
+
? [
|
|
208
|
+
factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword),
|
|
209
|
+
factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword),
|
|
210
|
+
]
|
|
211
|
+
: [factory.createStringLiteral(uid), factory.createStringLiteral(targetField)];
|
|
212
|
+
|
|
213
|
+
params.push(...targetFieldParams);
|
|
214
|
+
|
|
215
|
+
// If the options property is defined, transform it to
|
|
216
|
+
// a type literral node and add it to the params list
|
|
217
|
+
if (_.isObject(options)) {
|
|
218
|
+
params.push(toTypeLiteral(options));
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return ['UIDAttribute', params];
|
|
222
|
+
},
|
|
223
|
+
enumeration({ attribute }) {
|
|
224
|
+
const { enum: enumValues } = attribute;
|
|
225
|
+
|
|
226
|
+
return ['EnumerationAttribute', [toTypeLiteral(enumValues)]];
|
|
227
|
+
},
|
|
228
|
+
boolean() {
|
|
229
|
+
return ['BooleanAttribute'];
|
|
230
|
+
},
|
|
231
|
+
json() {
|
|
232
|
+
return ['JSONAttribute'];
|
|
233
|
+
},
|
|
234
|
+
media() {
|
|
235
|
+
return ['MediaAttribute'];
|
|
236
|
+
},
|
|
237
|
+
relation({ uid, attribute }) {
|
|
238
|
+
const { relation, target } = attribute;
|
|
239
|
+
|
|
240
|
+
const isMorphRelation = relation.toLowerCase().includes('morph');
|
|
241
|
+
|
|
242
|
+
if (isMorphRelation) {
|
|
243
|
+
return [
|
|
244
|
+
'RelationAttribute',
|
|
245
|
+
[factory.createStringLiteral(uid, true), factory.createStringLiteral(relation, true)],
|
|
246
|
+
];
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return [
|
|
250
|
+
'RelationAttribute',
|
|
251
|
+
[
|
|
252
|
+
factory.createStringLiteral(uid, true),
|
|
253
|
+
factory.createStringLiteral(relation, true),
|
|
254
|
+
factory.createStringLiteral(target, true),
|
|
255
|
+
],
|
|
256
|
+
];
|
|
257
|
+
},
|
|
258
|
+
component({ attribute }) {
|
|
259
|
+
const target = attribute.component;
|
|
260
|
+
const params = [factory.createStringLiteral(target, true)];
|
|
261
|
+
|
|
262
|
+
if (attribute.repeatable) {
|
|
263
|
+
params.push(factory.createTrue());
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return ['ComponentAttribute', params];
|
|
267
|
+
},
|
|
268
|
+
dynamiczone({ attribute }) {
|
|
269
|
+
const componentsParam = factory.createTupleTypeNode(
|
|
270
|
+
attribute.components.map(component => factory.createStringLiteral(component))
|
|
271
|
+
);
|
|
145
272
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
factory.createIdentifier(attributeName),
|
|
149
|
-
undefined,
|
|
150
|
-
factory.createIntersectionTypeNode(nodes)
|
|
151
|
-
);
|
|
273
|
+
return ['DynamicZoneAttribute', [componentsParam]];
|
|
274
|
+
},
|
|
152
275
|
};
|
|
153
276
|
|
|
154
277
|
module.exports = attributeToPropertySignature;
|
|
@@ -1,31 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
/* eslint-disable no-bitwise */
|
|
4
|
-
|
|
5
3
|
const ts = require('typescript');
|
|
6
4
|
const { factory } = require('typescript');
|
|
7
5
|
|
|
8
6
|
const { getSchemaInterfaceName } = require('./utils');
|
|
9
7
|
|
|
10
|
-
/**
|
|
11
|
-
*
|
|
12
|
-
* @param {object} schemaDefinition
|
|
13
|
-
* @param {ts.InterfaceDeclaration} schemaDefinition.definition
|
|
14
|
-
* @param {object} schemaDefinition.schema
|
|
15
|
-
*/
|
|
16
|
-
const schemaDefinitionToPropertySignature = ({ schema }) => {
|
|
17
|
-
const { uid } = schema;
|
|
18
|
-
|
|
19
|
-
const interfaceTypeName = getSchemaInterfaceName(uid);
|
|
20
|
-
|
|
21
|
-
return factory.createPropertySignature(
|
|
22
|
-
undefined,
|
|
23
|
-
factory.createStringLiteral(uid, true),
|
|
24
|
-
undefined,
|
|
25
|
-
factory.createTypeReferenceNode(factory.createIdentifier(interfaceTypeName))
|
|
26
|
-
);
|
|
27
|
-
};
|
|
28
|
-
|
|
29
8
|
/**
|
|
30
9
|
* Generate the global module augmentation block
|
|
31
10
|
*
|
|
@@ -67,4 +46,23 @@ const generateGlobalDefinition = (schemasDefinitions = []) => {
|
|
|
67
46
|
);
|
|
68
47
|
};
|
|
69
48
|
|
|
49
|
+
/**
|
|
50
|
+
*
|
|
51
|
+
* @param {object} schemaDefinition
|
|
52
|
+
* @param {ts.InterfaceDeclaration} schemaDefinition.definition
|
|
53
|
+
* @param {object} schemaDefinition.schema
|
|
54
|
+
*/
|
|
55
|
+
const schemaDefinitionToPropertySignature = ({ schema }) => {
|
|
56
|
+
const { uid } = schema;
|
|
57
|
+
|
|
58
|
+
const interfaceTypeName = getSchemaInterfaceName(uid);
|
|
59
|
+
|
|
60
|
+
return factory.createPropertySignature(
|
|
61
|
+
undefined,
|
|
62
|
+
factory.createStringLiteral(uid, true),
|
|
63
|
+
undefined,
|
|
64
|
+
factory.createTypeReferenceNode(factory.createIdentifier(interfaceTypeName))
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
|
|
70
68
|
module.exports = { generateGlobalDefinition };
|
|
@@ -23,7 +23,67 @@ const {
|
|
|
23
23
|
|
|
24
24
|
const DEFAULT_OUT_FILENAME = 'schemas.d.ts';
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Generate type definitions for Strapi schemas
|
|
28
|
+
*
|
|
29
|
+
* @param {object} options
|
|
30
|
+
* @param {Strapi} options.strapi
|
|
31
|
+
* @param {{ distDir: string; appDir: string; }} options.dirs
|
|
32
|
+
* @param {string} [options.outDir]
|
|
33
|
+
* @param {string} [options.file]
|
|
34
|
+
* @param {boolean} [options.verbose]
|
|
35
|
+
*/
|
|
36
|
+
const generateSchemasDefinitions = async (options = {}) => {
|
|
37
|
+
const {
|
|
38
|
+
strapi,
|
|
39
|
+
outDir = process.cwd(),
|
|
40
|
+
file = DEFAULT_OUT_FILENAME,
|
|
41
|
+
verbose = false,
|
|
42
|
+
silent = false,
|
|
43
|
+
} = options;
|
|
44
|
+
|
|
45
|
+
const schemas = getAllStrapiSchemas(strapi);
|
|
46
|
+
|
|
47
|
+
const schemasDefinitions = Object.values(schemas).map(schema => ({
|
|
48
|
+
schema,
|
|
49
|
+
definition: generateSchemaDefinition(schema),
|
|
50
|
+
}));
|
|
51
|
+
|
|
52
|
+
const formattedSchemasDefinitions = schemasDefinitions.reduce((acc, def) => {
|
|
53
|
+
acc.push(
|
|
54
|
+
// Definition
|
|
55
|
+
def.definition,
|
|
56
|
+
|
|
57
|
+
// Add a newline between each interface declaration
|
|
58
|
+
factory.createIdentifier('\n')
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
return acc;
|
|
62
|
+
}, []);
|
|
63
|
+
|
|
64
|
+
const allDefinitions = [
|
|
65
|
+
// Imports
|
|
66
|
+
generateImportDefinition(),
|
|
67
|
+
|
|
68
|
+
// Add a newline after the import statement
|
|
69
|
+
factory.createIdentifier('\n'),
|
|
70
|
+
|
|
71
|
+
// Schemas
|
|
72
|
+
...formattedSchemasDefinitions,
|
|
73
|
+
|
|
74
|
+
// Global
|
|
75
|
+
generateGlobalDefinition(schemasDefinitions),
|
|
76
|
+
];
|
|
77
|
+
|
|
78
|
+
const output = emitDefinitions(allDefinitions);
|
|
79
|
+
const formattedOutput = await format(output);
|
|
80
|
+
|
|
81
|
+
const definitionFilepath = await saveDefinitionToFileSystem(outDir, file, formattedOutput);
|
|
82
|
+
|
|
83
|
+
logDebugInformation(schemasDefinitions, { filepath: definitionFilepath, verbose, silent });
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const emitDefinitions = definitions => {
|
|
27
87
|
const nodeArray = factory.createNodeArray(definitions);
|
|
28
88
|
|
|
29
89
|
const sourceFile = ts.createSourceFile(
|
|
@@ -54,7 +114,7 @@ const saveDefinitionToFileSystem = async (dir, file, content) => {
|
|
|
54
114
|
* @param {string} content
|
|
55
115
|
* @returns {Promise<string>}
|
|
56
116
|
*/
|
|
57
|
-
const format = async
|
|
117
|
+
const format = async content => {
|
|
58
118
|
const configFile = await prettier.resolveConfigFile();
|
|
59
119
|
const config = configFile
|
|
60
120
|
? await prettier.resolveConfig(configFile)
|
|
@@ -84,7 +144,7 @@ const logDebugInformation = (definitions, options = {}) => {
|
|
|
84
144
|
colAligns: ['center', 'left', 'left', 'center'],
|
|
85
145
|
});
|
|
86
146
|
|
|
87
|
-
const sortedDefinitions = definitions.map(
|
|
147
|
+
const sortedDefinitions = definitions.map(def => ({
|
|
88
148
|
...def,
|
|
89
149
|
attributesCount: getDefinitionAttributesCount(def.definition),
|
|
90
150
|
}));
|
|
@@ -122,64 +182,4 @@ const logDebugInformation = (definitions, options = {}) => {
|
|
|
122
182
|
}
|
|
123
183
|
};
|
|
124
184
|
|
|
125
|
-
/**
|
|
126
|
-
* Generate type definitions for Strapi schemas
|
|
127
|
-
*
|
|
128
|
-
* @param {object} options
|
|
129
|
-
* @param {Strapi} options.strapi
|
|
130
|
-
* @param {{ distDir: string; appDir: string; }} options.dirs
|
|
131
|
-
* @param {string} [options.outDir]
|
|
132
|
-
* @param {string} [options.file]
|
|
133
|
-
* @param {boolean} [options.verbose]
|
|
134
|
-
*/
|
|
135
|
-
const generateSchemasDefinitions = async (options = {}) => {
|
|
136
|
-
const {
|
|
137
|
-
strapi,
|
|
138
|
-
outDir = process.cwd(),
|
|
139
|
-
file = DEFAULT_OUT_FILENAME,
|
|
140
|
-
verbose = false,
|
|
141
|
-
silent = false,
|
|
142
|
-
} = options;
|
|
143
|
-
|
|
144
|
-
const schemas = getAllStrapiSchemas(strapi);
|
|
145
|
-
|
|
146
|
-
const schemasDefinitions = Object.values(schemas).map((schema) => ({
|
|
147
|
-
schema,
|
|
148
|
-
definition: generateSchemaDefinition(schema),
|
|
149
|
-
}));
|
|
150
|
-
|
|
151
|
-
const formattedSchemasDefinitions = schemasDefinitions.reduce((acc, def) => {
|
|
152
|
-
acc.push(
|
|
153
|
-
// Definition
|
|
154
|
-
def.definition,
|
|
155
|
-
|
|
156
|
-
// Add a newline between each interface declaration
|
|
157
|
-
factory.createIdentifier('\n')
|
|
158
|
-
);
|
|
159
|
-
|
|
160
|
-
return acc;
|
|
161
|
-
}, []);
|
|
162
|
-
|
|
163
|
-
const allDefinitions = [
|
|
164
|
-
// Imports
|
|
165
|
-
generateImportDefinition(),
|
|
166
|
-
|
|
167
|
-
// Add a newline after the import statement
|
|
168
|
-
factory.createIdentifier('\n'),
|
|
169
|
-
|
|
170
|
-
// Schemas
|
|
171
|
-
...formattedSchemasDefinitions,
|
|
172
|
-
|
|
173
|
-
// Global
|
|
174
|
-
generateGlobalDefinition(schemasDefinitions),
|
|
175
|
-
];
|
|
176
|
-
|
|
177
|
-
const output = emitDefinitions(allDefinitions);
|
|
178
|
-
const formattedOutput = await format(output);
|
|
179
|
-
|
|
180
|
-
const definitionFilepath = await saveDefinitionToFileSystem(outDir, file, formattedOutput);
|
|
181
|
-
|
|
182
|
-
logDebugInformation(schemasDefinitions, { filepath: definitionFilepath, verbose, silent });
|
|
183
|
-
};
|
|
184
|
-
|
|
185
185
|
module.exports = generateSchemasDefinitions;
|
|
@@ -8,43 +8,13 @@ const { getSchemaExtendsTypeName, getSchemaInterfaceName, toTypeLiteral } = requ
|
|
|
8
8
|
const attributeToPropertySignature = require('./attributes');
|
|
9
9
|
const { addImport } = require('./imports');
|
|
10
10
|
|
|
11
|
-
/**
|
|
12
|
-
* Generate a property signature for the schema's `attributes` field
|
|
13
|
-
*
|
|
14
|
-
* @param {object} schema
|
|
15
|
-
* @returns {ts.PropertySignature}
|
|
16
|
-
*/
|
|
17
|
-
const generateAttributePropertySignature = (schema) => {
|
|
18
|
-
const { attributes } = schema;
|
|
19
|
-
|
|
20
|
-
const properties = Object.entries(attributes).map(([attributeName, attribute]) => {
|
|
21
|
-
return attributeToPropertySignature(schema, attributeName, attribute);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
return factory.createPropertySignature(
|
|
25
|
-
undefined,
|
|
26
|
-
factory.createIdentifier('attributes'),
|
|
27
|
-
undefined,
|
|
28
|
-
factory.createTypeLiteralNode(properties)
|
|
29
|
-
);
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const generatePropertyLiteralDefinitionFactory = (schema) => (key) => {
|
|
33
|
-
return factory.createPropertySignature(
|
|
34
|
-
undefined,
|
|
35
|
-
factory.createIdentifier(key),
|
|
36
|
-
undefined,
|
|
37
|
-
toTypeLiteral(schema[key])
|
|
38
|
-
);
|
|
39
|
-
};
|
|
40
|
-
|
|
41
11
|
/**
|
|
42
12
|
* Generate an interface declaration for a given schema
|
|
43
13
|
*
|
|
44
14
|
* @param {object} schema
|
|
45
15
|
* @returns {ts.InterfaceDeclaration}
|
|
46
16
|
*/
|
|
47
|
-
const generateSchemaDefinition =
|
|
17
|
+
const generateSchemaDefinition = schema => {
|
|
48
18
|
const { uid } = schema;
|
|
49
19
|
|
|
50
20
|
// Resolve the different interface names needed to declare the schema's interface
|
|
@@ -57,7 +27,7 @@ const generateSchemaDefinition = (schema) => {
|
|
|
57
27
|
// Properties whose values can be mapped to a literal type expression
|
|
58
28
|
const literalPropertiesDefinitions = ['info', 'options', 'pluginOptions']
|
|
59
29
|
// Ignore non-existent or empty declarations
|
|
60
|
-
.filter(
|
|
30
|
+
.filter(key => !isEmpty(schema[key]))
|
|
61
31
|
// Generate literal definition for each property
|
|
62
32
|
.map(generatePropertyLiteralDefinitionFactory(schema));
|
|
63
33
|
|
|
@@ -84,4 +54,34 @@ const generateSchemaDefinition = (schema) => {
|
|
|
84
54
|
return schemaType;
|
|
85
55
|
};
|
|
86
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Generate a property signature for the schema's `attributes` field
|
|
59
|
+
*
|
|
60
|
+
* @param {object} schema
|
|
61
|
+
* @returns {ts.PropertySignature}
|
|
62
|
+
*/
|
|
63
|
+
const generateAttributePropertySignature = schema => {
|
|
64
|
+
const { attributes } = schema;
|
|
65
|
+
|
|
66
|
+
const properties = Object.entries(attributes).map(([attributeName, attribute]) => {
|
|
67
|
+
return attributeToPropertySignature(schema, attributeName, attribute);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
return factory.createPropertySignature(
|
|
71
|
+
undefined,
|
|
72
|
+
factory.createIdentifier('attributes'),
|
|
73
|
+
undefined,
|
|
74
|
+
factory.createTypeLiteralNode(properties)
|
|
75
|
+
);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const generatePropertyLiteralDefinitionFactory = schema => key => {
|
|
79
|
+
return factory.createPropertySignature(
|
|
80
|
+
undefined,
|
|
81
|
+
factory.createIdentifier(key),
|
|
82
|
+
undefined,
|
|
83
|
+
toTypeLiteral(schema[key])
|
|
84
|
+
);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
87
|
module.exports = { generateSchemaDefinition };
|
|
@@ -23,7 +23,7 @@ const {
|
|
|
23
23
|
* @param {Strapi} strapi
|
|
24
24
|
* @returns {object}
|
|
25
25
|
*/
|
|
26
|
-
const getAllStrapiSchemas =
|
|
26
|
+
const getAllStrapiSchemas = strapi => ({ ...strapi.contentTypes, ...strapi.components });
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* Extract a valid interface name from a schema uid
|
|
@@ -33,7 +33,19 @@ const getAllStrapiSchemas = (strapi) => ({ ...strapi.contentTypes, ...strapi.com
|
|
|
33
33
|
*/
|
|
34
34
|
const getSchemaInterfaceName = pipe(replace(/(:.)/, ' '), camelCase, upperFirst);
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Get the parent type name to extend based on the schema's nature
|
|
38
|
+
*
|
|
39
|
+
* @param {object} schema
|
|
40
|
+
* @returns {string}
|
|
41
|
+
*/
|
|
42
|
+
const getSchemaExtendsTypeName = schema => {
|
|
43
|
+
const base = getSchemaModelType(schema);
|
|
44
|
+
|
|
45
|
+
return upperFirst(base) + 'Schema';
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const getSchemaModelType = schema => {
|
|
37
49
|
const { modelType, kind } = schema;
|
|
38
50
|
|
|
39
51
|
// Components
|
|
@@ -42,25 +54,13 @@ const getSchemaModelType = (schema) => {
|
|
|
42
54
|
}
|
|
43
55
|
|
|
44
56
|
// Content-Types
|
|
45
|
-
if (modelType === 'contentType') {
|
|
57
|
+
else if (modelType === 'contentType') {
|
|
46
58
|
return kind;
|
|
47
59
|
}
|
|
48
60
|
|
|
49
61
|
return null;
|
|
50
62
|
};
|
|
51
63
|
|
|
52
|
-
/**
|
|
53
|
-
* Get the parent type name to extend based on the schema's nature
|
|
54
|
-
*
|
|
55
|
-
* @param {object} schema
|
|
56
|
-
* @returns {string}
|
|
57
|
-
*/
|
|
58
|
-
const getSchemaExtendsTypeName = (schema) => {
|
|
59
|
-
const base = getSchemaModelType(schema);
|
|
60
|
-
|
|
61
|
-
return `${upperFirst(base)}Schema`;
|
|
62
|
-
};
|
|
63
|
-
|
|
64
64
|
/**
|
|
65
65
|
* Get a type node based on a type and its params
|
|
66
66
|
*
|
|
@@ -77,7 +77,7 @@ const getTypeNode = (typeName, params = []) => {
|
|
|
77
77
|
* @param data
|
|
78
78
|
* @returns {ts.TypeNode}
|
|
79
79
|
*/
|
|
80
|
-
const toTypeLiteral =
|
|
80
|
+
const toTypeLiteral = data => {
|
|
81
81
|
if (isUndefined(data)) {
|
|
82
82
|
return factory.createLiteralTypeNode(ts.SyntaxKind.UndefinedKeyword);
|
|
83
83
|
}
|
|
@@ -99,7 +99,7 @@ const toTypeLiteral = (data) => {
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
if (isArray(data)) {
|
|
102
|
-
return factory.createTupleTypeNode(data.map(
|
|
102
|
+
return factory.createTupleTypeNode(data.map(item => toTypeLiteral(item)));
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
if (isDate(data)) {
|
|
@@ -139,7 +139,7 @@ const toTypeLiteral = (data) => {
|
|
|
139
139
|
* @param {ts.TypeNode} definition
|
|
140
140
|
* @returns {number | null}
|
|
141
141
|
*/
|
|
142
|
-
const getDefinitionAttributesCount =
|
|
142
|
+
const getDefinitionAttributesCount = definition => {
|
|
143
143
|
const attributesNode = definition.members.find(propEq('name.escapedText', 'attributes'));
|
|
144
144
|
|
|
145
145
|
if (!attributesNode) {
|
|
@@ -8,7 +8,7 @@ const formatHost = require('./format-host');
|
|
|
8
8
|
* Report one or several diagnostic to the console
|
|
9
9
|
* @param {ts.Diagnostic[] | ts.Diagnostic} diagnostics
|
|
10
10
|
*/
|
|
11
|
-
module.exports =
|
|
11
|
+
module.exports = diagnostics => {
|
|
12
12
|
const formattedDiagnostics = ts.formatDiagnosticsWithColorAndContext(
|
|
13
13
|
Array.isArray(diagnostics) ? diagnostics : [diagnostics],
|
|
14
14
|
formatHost
|
|
@@ -4,7 +4,7 @@ const ts = require('typescript');
|
|
|
4
4
|
|
|
5
5
|
const logDiagnostics = require('./report-diagnostics');
|
|
6
6
|
|
|
7
|
-
module.exports =
|
|
7
|
+
module.exports = configPath => {
|
|
8
8
|
// Parse the tsconfig.json file and resolve every file name & compiler options
|
|
9
9
|
const { errors, ...configOptions } = ts.getParsedCommandLineOfConfigFile(
|
|
10
10
|
configPath,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@strapi/typescript-utils",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-8581854cb3",
|
|
4
4
|
"description": "Typescript support for Strapi",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"strapi",
|
|
@@ -35,5 +35,5 @@
|
|
|
35
35
|
"node": ">=12.22.0 <=16.x.x",
|
|
36
36
|
"npm": ">=6.0.0"
|
|
37
37
|
},
|
|
38
|
-
"gitHead": "
|
|
38
|
+
"gitHead": "8581854cb3c817ae42b829ea686a1b0702ed9245"
|
|
39
39
|
}
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const ts = require('typescript');
|
|
4
|
-
const _ = require('lodash/fp');
|
|
5
|
-
|
|
6
|
-
const { toTypeLiteral } = require('./utils');
|
|
7
|
-
|
|
8
|
-
const { factory } = ts;
|
|
9
|
-
|
|
10
|
-
module.exports = {
|
|
11
|
-
string() {
|
|
12
|
-
return ['StringAttribute'];
|
|
13
|
-
},
|
|
14
|
-
text() {
|
|
15
|
-
return ['TextAttribute'];
|
|
16
|
-
},
|
|
17
|
-
richtext() {
|
|
18
|
-
return ['RichTextAttribute'];
|
|
19
|
-
},
|
|
20
|
-
password() {
|
|
21
|
-
return ['PasswordAttribute'];
|
|
22
|
-
},
|
|
23
|
-
email() {
|
|
24
|
-
return ['EmailAttribute'];
|
|
25
|
-
},
|
|
26
|
-
date() {
|
|
27
|
-
return ['DateAttribute'];
|
|
28
|
-
},
|
|
29
|
-
time() {
|
|
30
|
-
return ['TimeAttribute'];
|
|
31
|
-
},
|
|
32
|
-
datetime() {
|
|
33
|
-
return ['DateTimeAttribute'];
|
|
34
|
-
},
|
|
35
|
-
timestamp() {
|
|
36
|
-
return ['TimestampAttribute'];
|
|
37
|
-
},
|
|
38
|
-
integer() {
|
|
39
|
-
return ['IntegerAttribute'];
|
|
40
|
-
},
|
|
41
|
-
biginteger() {
|
|
42
|
-
return ['BigIntegerAttribute'];
|
|
43
|
-
},
|
|
44
|
-
float() {
|
|
45
|
-
return ['FloatAttribute'];
|
|
46
|
-
},
|
|
47
|
-
decimal() {
|
|
48
|
-
return ['DecimalAttribute'];
|
|
49
|
-
},
|
|
50
|
-
uid({ attribute, uid }) {
|
|
51
|
-
const { targetField, options } = attribute;
|
|
52
|
-
|
|
53
|
-
// If there are no params to compute, then return the attribute type alone
|
|
54
|
-
if (targetField === undefined && options === undefined) {
|
|
55
|
-
return ['UIDAttribute'];
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const params = [];
|
|
59
|
-
|
|
60
|
-
// If the targetField property is defined, then reference it,
|
|
61
|
-
// otherwise, put `undefined` keyword type nodes as placeholders
|
|
62
|
-
const targetFieldParams = _.isUndefined(targetField)
|
|
63
|
-
? [
|
|
64
|
-
factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword),
|
|
65
|
-
factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword),
|
|
66
|
-
]
|
|
67
|
-
: [factory.createStringLiteral(uid), factory.createStringLiteral(targetField)];
|
|
68
|
-
|
|
69
|
-
params.push(...targetFieldParams);
|
|
70
|
-
|
|
71
|
-
// If the options property is defined, transform it to
|
|
72
|
-
// a type literral node and add it to the params list
|
|
73
|
-
if (_.isObject(options)) {
|
|
74
|
-
params.push(toTypeLiteral(options));
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return ['UIDAttribute', params];
|
|
78
|
-
},
|
|
79
|
-
enumeration({ attribute }) {
|
|
80
|
-
const { enum: enumValues } = attribute;
|
|
81
|
-
|
|
82
|
-
return ['EnumerationAttribute', [toTypeLiteral(enumValues)]];
|
|
83
|
-
},
|
|
84
|
-
boolean() {
|
|
85
|
-
return ['BooleanAttribute'];
|
|
86
|
-
},
|
|
87
|
-
json() {
|
|
88
|
-
return ['JSONAttribute'];
|
|
89
|
-
},
|
|
90
|
-
media() {
|
|
91
|
-
return ['MediaAttribute'];
|
|
92
|
-
},
|
|
93
|
-
relation({ uid, attribute }) {
|
|
94
|
-
const { relation, target } = attribute;
|
|
95
|
-
|
|
96
|
-
const isMorphRelation = relation.toLowerCase().includes('morph');
|
|
97
|
-
|
|
98
|
-
if (isMorphRelation) {
|
|
99
|
-
return [
|
|
100
|
-
'RelationAttribute',
|
|
101
|
-
[factory.createStringLiteral(uid, true), factory.createStringLiteral(relation, true)],
|
|
102
|
-
];
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return [
|
|
106
|
-
'RelationAttribute',
|
|
107
|
-
[
|
|
108
|
-
factory.createStringLiteral(uid, true),
|
|
109
|
-
factory.createStringLiteral(relation, true),
|
|
110
|
-
factory.createStringLiteral(target, true),
|
|
111
|
-
],
|
|
112
|
-
];
|
|
113
|
-
},
|
|
114
|
-
component({ attribute }) {
|
|
115
|
-
const target = attribute.component;
|
|
116
|
-
const params = [factory.createStringLiteral(target, true)];
|
|
117
|
-
|
|
118
|
-
if (attribute.repeatable) {
|
|
119
|
-
params.push(factory.createTrue());
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return ['ComponentAttribute', params];
|
|
123
|
-
},
|
|
124
|
-
dynamiczone({ attribute }) {
|
|
125
|
-
const componentsParam = factory.createTupleTypeNode(
|
|
126
|
-
attribute.components.map((component) => factory.createStringLiteral(component))
|
|
127
|
-
);
|
|
128
|
-
|
|
129
|
-
return ['DynamicZoneAttribute', [componentsParam]];
|
|
130
|
-
},
|
|
131
|
-
};
|