@strapi/typescript-utils 0.0.0-next.f7babb775ed9a7e18d8351cb7f74c63e016323c4 → 0.0.0-next.f93d6eabe52aa7681655cfa08eedbc3708dbb90d
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/LICENSE +18 -3
- package/lib/__tests__/generators/schemas/attributes.test.js +280 -135
- package/lib/__tests__/generators/schemas/utils.test.js +31 -31
- package/lib/compile.js +2 -6
- package/lib/compilers/basic.js +12 -4
- package/lib/compilers/index.js +0 -2
- package/lib/generators/common/imports.js +3 -3
- package/lib/generators/common/models/attributes.js +35 -10
- package/lib/generators/common/models/mappers.js +35 -22
- package/lib/generators/common/models/schema.js +7 -5
- package/lib/generators/common/models/utils.js +7 -7
- package/lib/generators/components/index.js +21 -5
- package/lib/generators/content-types/index.js +21 -5
- package/lib/generators/index.js +1 -1
- package/lib/generators/utils.js +10 -5
- package/lib/index.js +0 -3
- package/lib/utils/index.js +2 -0
- package/lib/utils/resolve-outdir-sync.js +18 -0
- package/package.json +15 -8
- package/tsconfigs/admin.json +18 -19
- package/tsconfigs/server.json +18 -16
- package/lib/admin/create-tsconfig-file.js +0 -37
- package/lib/admin/index.js +0 -5
- package/lib/compilers/watch.js +0 -37
|
@@ -120,9 +120,9 @@ describe('Utils', () => {
|
|
|
120
120
|
|
|
121
121
|
describe('Get Schema Extends Type Name', () => {
|
|
122
122
|
test.each([
|
|
123
|
-
[{ modelType: 'component', kind: null }, '
|
|
124
|
-
[{ modelType: 'contentType', kind: 'singleType' }, '
|
|
125
|
-
[{ modelType: 'contentType', kind: 'collectionType' }, '
|
|
123
|
+
[{ modelType: 'component', kind: null }, 'Struct.ComponentSchema'],
|
|
124
|
+
[{ modelType: 'contentType', kind: 'singleType' }, 'Struct.SingleTypeSchema'],
|
|
125
|
+
[{ modelType: 'contentType', kind: 'collectionType' }, 'Struct.CollectionTypeSchema'],
|
|
126
126
|
[{ modelType: 'invalidType', kind: 'foo' }, null],
|
|
127
127
|
])("Expect %p to generate %p as the base type for a schema's interface", (schema, expected) => {
|
|
128
128
|
expect(getSchemaExtendsTypeName(schema)).toBe(expected);
|
|
@@ -247,13 +247,13 @@ describe('Utils', () => {
|
|
|
247
247
|
expect(objectNode.members).toHaveLength(2);
|
|
248
248
|
|
|
249
249
|
expect(objectNode.members[0].kind).toBe(ts.SyntaxKind.PropertyDeclaration);
|
|
250
|
-
expect(objectNode.members[0].name.escapedText).toBe('
|
|
251
|
-
expect(objectNode.members[0].type.kind).toBe(ts.SyntaxKind.
|
|
252
|
-
expect(objectNode.members[0].type.text).toBe('bar');
|
|
250
|
+
expect(objectNode.members[0].name.escapedText).toBe('bar');
|
|
251
|
+
expect(objectNode.members[0].type.kind).toBe(ts.SyntaxKind.TrueKeyword);
|
|
253
252
|
|
|
254
253
|
expect(objectNode.members[1].kind).toBe(ts.SyntaxKind.PropertyDeclaration);
|
|
255
|
-
expect(objectNode.members[1].name.escapedText).toBe('
|
|
256
|
-
expect(objectNode.members[1].type.kind).toBe(ts.SyntaxKind.
|
|
254
|
+
expect(objectNode.members[1].name.escapedText).toBe('foo');
|
|
255
|
+
expect(objectNode.members[1].type.kind).toBe(ts.SyntaxKind.StringLiteral);
|
|
256
|
+
expect(objectNode.members[1].type.text).toBe('bar');
|
|
257
257
|
});
|
|
258
258
|
|
|
259
259
|
test('Object', () => {
|
|
@@ -262,20 +262,20 @@ describe('Utils', () => {
|
|
|
262
262
|
expect(node.kind).toBe(ts.SyntaxKind.TypeLiteral);
|
|
263
263
|
expect(node.members).toHaveLength(2);
|
|
264
264
|
|
|
265
|
-
const [
|
|
265
|
+
const [barMember, fooMember] = node.members;
|
|
266
266
|
|
|
267
|
-
expect(
|
|
268
|
-
expect(
|
|
269
|
-
expect(
|
|
270
|
-
expect(
|
|
271
|
-
expect(firstMember.type.elements[0].kind).toBe(ts.SyntaxKind.StringLiteral);
|
|
272
|
-
expect(firstMember.type.elements[1].kind).toBe(ts.SyntaxKind.TrueKeyword);
|
|
273
|
-
expect(firstMember.type.elements[2].kind).toBe(ts.SyntaxKind.FirstLiteralToken);
|
|
267
|
+
expect(barMember.kind).toBe(ts.SyntaxKind.PropertyDeclaration);
|
|
268
|
+
expect(barMember.name.escapedText).toBe('bar');
|
|
269
|
+
expect(barMember.type.kind).toBe(ts.SyntaxKind.LiteralType);
|
|
270
|
+
expect(barMember.type.literal).toBe(ts.SyntaxKind.NullKeyword);
|
|
274
271
|
|
|
275
|
-
expect(
|
|
276
|
-
expect(
|
|
277
|
-
expect(
|
|
278
|
-
expect(
|
|
272
|
+
expect(fooMember.kind).toBe(ts.SyntaxKind.PropertyDeclaration);
|
|
273
|
+
expect(fooMember.name.escapedText).toBe('foo');
|
|
274
|
+
expect(fooMember.type.kind).toBe(ts.SyntaxKind.TupleType);
|
|
275
|
+
expect(fooMember.type.elements).toHaveLength(3);
|
|
276
|
+
expect(fooMember.type.elements[0].kind).toBe(ts.SyntaxKind.StringLiteral);
|
|
277
|
+
expect(fooMember.type.elements[1].kind).toBe(ts.SyntaxKind.TrueKeyword);
|
|
278
|
+
expect(fooMember.type.elements[2].kind).toBe(ts.SyntaxKind.FirstLiteralToken);
|
|
279
279
|
});
|
|
280
280
|
|
|
281
281
|
test('Object with complex keys', () => {
|
|
@@ -284,19 +284,19 @@ describe('Utils', () => {
|
|
|
284
284
|
expect(node.kind).toBe(ts.SyntaxKind.TypeLiteral);
|
|
285
285
|
expect(node.members).toHaveLength(2);
|
|
286
286
|
|
|
287
|
-
const [
|
|
287
|
+
const [fooBar, fooDashBar] = node.members;
|
|
288
288
|
|
|
289
|
-
expect(
|
|
290
|
-
expect(
|
|
291
|
-
expect(
|
|
292
|
-
expect(
|
|
293
|
-
expect(
|
|
289
|
+
expect(fooBar.kind).toBe(ts.SyntaxKind.PropertyDeclaration);
|
|
290
|
+
expect(fooBar.name.kind).toBe(ts.SyntaxKind.Identifier);
|
|
291
|
+
expect(fooBar.name.escapedText).toBe('foo');
|
|
292
|
+
expect(fooBar.type.kind).toBe(ts.SyntaxKind.StringLiteral);
|
|
293
|
+
expect(fooBar.type.text).toBe('bar');
|
|
294
294
|
|
|
295
|
-
expect(
|
|
296
|
-
expect(
|
|
297
|
-
expect(
|
|
298
|
-
expect(
|
|
299
|
-
expect(
|
|
295
|
+
expect(fooDashBar.kind).toBe(ts.SyntaxKind.PropertyDeclaration);
|
|
296
|
+
expect(fooDashBar.name.kind).toBe(ts.SyntaxKind.StringLiteral);
|
|
297
|
+
expect(fooDashBar.name.text).toBe('foo-bar');
|
|
298
|
+
expect(fooDashBar.type.kind).toBe(ts.SyntaxKind.StringLiteral);
|
|
299
|
+
expect(fooDashBar.type.text).toBe('foobar');
|
|
300
300
|
});
|
|
301
301
|
|
|
302
302
|
test('Invalid data type supplied (function)', () => {
|
package/lib/compile.js
CHANGED
|
@@ -3,12 +3,8 @@
|
|
|
3
3
|
const compilers = require('./compilers');
|
|
4
4
|
const getConfigPath = require('./utils/get-config-path');
|
|
5
5
|
|
|
6
|
-
module.exports = async (srcDir, {
|
|
7
|
-
// TODO: Use the Strapi debug logger instead or don't log at all
|
|
8
|
-
console.log(`Starting the compilation for TypeScript files in ${srcDir}`);
|
|
9
|
-
|
|
10
|
-
const compiler = watch ? compilers.watch : compilers.basic;
|
|
6
|
+
module.exports = async (srcDir, { configOptions = {} } = {}) => {
|
|
11
7
|
const configPath = getConfigPath(srcDir);
|
|
12
8
|
|
|
13
|
-
|
|
9
|
+
compilers.basic.run(configPath, configOptions);
|
|
14
10
|
};
|
package/lib/compilers/basic.js
CHANGED
|
@@ -13,15 +13,23 @@ module.exports = {
|
|
|
13
13
|
* @param {Object} configOptions
|
|
14
14
|
* @param {Array.<string>} configOptions.fileNames
|
|
15
15
|
* @param {Object} configOptions.options
|
|
16
|
+
* @param {boolean} configOptions.ignoreDiagnostics
|
|
16
17
|
*/
|
|
17
18
|
run(tsConfigPath, configOptions = {}) {
|
|
19
|
+
const { ignoreDiagnostics = false } = configOptions;
|
|
18
20
|
// Parse the tsconfig.json file & resolve the configuration options
|
|
19
21
|
const { fileNames, options, projectReferences } = resolveConfigOptions(tsConfigPath);
|
|
20
22
|
|
|
23
|
+
const compilerOptions = merge(options, configOptions.options);
|
|
24
|
+
|
|
25
|
+
if (ignoreDiagnostics) {
|
|
26
|
+
Object.assign(compilerOptions, { noEmit: false, noEmitOnError: false });
|
|
27
|
+
}
|
|
28
|
+
|
|
21
29
|
const program = ts.createProgram({
|
|
22
30
|
rootNames: configOptions.fileNames ? configOptions.fileNames : fileNames,
|
|
23
31
|
projectReferences,
|
|
24
|
-
options:
|
|
32
|
+
options: compilerOptions,
|
|
25
33
|
});
|
|
26
34
|
|
|
27
35
|
const emitResults = program.emit();
|
|
@@ -30,12 +38,12 @@ module.exports = {
|
|
|
30
38
|
ts.getPreEmitDiagnostics(program).concat(emitResults.diagnostics)
|
|
31
39
|
);
|
|
32
40
|
|
|
33
|
-
if (diagnostics.length > 0) {
|
|
41
|
+
if (!ignoreDiagnostics && diagnostics.length > 0) {
|
|
34
42
|
reportDiagnostics(diagnostics);
|
|
35
43
|
}
|
|
36
44
|
|
|
37
|
-
// If the compilation failed, exit early
|
|
38
|
-
if (emitResults.emitSkipped) {
|
|
45
|
+
// If the compilation failed and diagnostics are not ignored, exit early
|
|
46
|
+
if (!ignoreDiagnostics && emitResults.emitSkipped) {
|
|
39
47
|
process.exit(1);
|
|
40
48
|
}
|
|
41
49
|
},
|
package/lib/compilers/index.js
CHANGED
|
@@ -18,9 +18,9 @@ module.exports = {
|
|
|
18
18
|
},
|
|
19
19
|
|
|
20
20
|
generateImportDefinition() {
|
|
21
|
-
const formattedImports = imports
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
const formattedImports = imports
|
|
22
|
+
.sort()
|
|
23
|
+
.map((key) => factory.createImportSpecifier(false, undefined, factory.createIdentifier(key)));
|
|
24
24
|
|
|
25
25
|
return [
|
|
26
26
|
factory.createImportDeclaration(
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const ts = require('typescript');
|
|
4
4
|
const _ = require('lodash/fp');
|
|
5
5
|
|
|
6
6
|
const { addImport } = require('../imports');
|
|
7
7
|
const { getTypeNode, toTypeLiteral, withAttributeNamespace, NAMESPACES } = require('./utils');
|
|
8
8
|
const mappers = require('./mappers');
|
|
9
9
|
|
|
10
|
+
const { factory } = ts;
|
|
11
|
+
|
|
10
12
|
/**
|
|
11
13
|
* Create the base type node for a given attribute
|
|
12
14
|
*
|
|
@@ -26,8 +28,8 @@ const getAttributeType = (attributeName, attribute, uid) => {
|
|
|
26
28
|
|
|
27
29
|
const [attributeType, typeParams] = mappers[attribute.type]({ uid, attribute, attributeName });
|
|
28
30
|
|
|
29
|
-
// Make sure the
|
|
30
|
-
addImport(NAMESPACES.
|
|
31
|
+
// Make sure the schema namespace is imported
|
|
32
|
+
addImport(NAMESPACES.Schema);
|
|
31
33
|
|
|
32
34
|
return getTypeNode(attributeType, typeParams);
|
|
33
35
|
};
|
|
@@ -100,14 +102,39 @@ const getAttributeModifiers = (attribute) => {
|
|
|
100
102
|
}
|
|
101
103
|
|
|
102
104
|
// Min / Max
|
|
103
|
-
// TODO: Always provide a second type argument for min/max (ie: resolve the attribute scalar type with a `GetAttributeType<${mappers[attribute][0]}>` (useful for biginter (string values)))
|
|
104
105
|
if (!_.isNil(attribute.min) || !_.isNil(attribute.max)) {
|
|
105
106
|
const minMaxProperties = _.pick(['min', 'max'], attribute);
|
|
107
|
+
const { min, max } = minMaxProperties;
|
|
108
|
+
|
|
109
|
+
const typeofMin = typeof min;
|
|
110
|
+
const typeofMax = typeof max;
|
|
111
|
+
|
|
112
|
+
// Throws error if min/max exist but have different types to prevent unexpected behavior
|
|
113
|
+
if (min !== undefined && max !== undefined && typeofMin !== typeofMax) {
|
|
114
|
+
throw new Error('typeof min/max values mismatch');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
let typeKeyword;
|
|
118
|
+
|
|
119
|
+
// use 'string'
|
|
120
|
+
if (typeofMin === 'string' || typeofMax === 'string') {
|
|
121
|
+
typeKeyword = ts.SyntaxKind.StringKeyword;
|
|
122
|
+
}
|
|
123
|
+
// use 'number'
|
|
124
|
+
else if (typeofMin === 'number' || typeofMax === 'number') {
|
|
125
|
+
typeKeyword = ts.SyntaxKind.NumberKeyword;
|
|
126
|
+
}
|
|
127
|
+
// invalid type
|
|
128
|
+
else {
|
|
129
|
+
throw new Error(
|
|
130
|
+
`Invalid data type for min/max options. Must be string, number or undefined, but found { min: ${min} (${typeofMin}), max: ${max} (${typeofMax}) }`
|
|
131
|
+
);
|
|
132
|
+
}
|
|
106
133
|
|
|
107
134
|
modifiers.push(
|
|
108
135
|
factory.createTypeReferenceNode(
|
|
109
136
|
factory.createIdentifier(withAttributeNamespace('SetMinMax')),
|
|
110
|
-
[toTypeLiteral(minMaxProperties)]
|
|
137
|
+
[toTypeLiteral(minMaxProperties), factory.createKeywordTypeNode(typeKeyword)]
|
|
111
138
|
)
|
|
112
139
|
);
|
|
113
140
|
}
|
|
@@ -124,8 +151,8 @@ const getAttributeModifiers = (attribute) => {
|
|
|
124
151
|
);
|
|
125
152
|
}
|
|
126
153
|
|
|
127
|
-
// Default
|
|
128
|
-
if (!_.isNil(attribute.default)) {
|
|
154
|
+
// Default (ignore if default is a function)
|
|
155
|
+
if (!_.isNil(attribute.default) && !_.isFunction(attribute.default)) {
|
|
129
156
|
const defaultLiteral = toTypeLiteral(attribute.default);
|
|
130
157
|
|
|
131
158
|
modifiers.push(
|
|
@@ -168,6 +195,4 @@ const attributeToPropertySignature = (schema, attributeName, attribute) => {
|
|
|
168
195
|
|
|
169
196
|
module.exports = attributeToPropertySignature;
|
|
170
197
|
|
|
171
|
-
module.exports
|
|
172
|
-
module.exports.getAttributeType = getAttributeType;
|
|
173
|
-
module.exports.getAttributeModifiers = getAttributeModifiers;
|
|
198
|
+
Object.assign(module.exports, { mappers, getAttributeModifiers, getAttributeType });
|
|
@@ -47,7 +47,7 @@ module.exports = {
|
|
|
47
47
|
decimal() {
|
|
48
48
|
return [withAttributeNamespace('Decimal')];
|
|
49
49
|
},
|
|
50
|
-
uid({ attribute
|
|
50
|
+
uid({ attribute }) {
|
|
51
51
|
const { targetField, options } = attribute;
|
|
52
52
|
|
|
53
53
|
// If there are no params to compute, then return the attribute type alone
|
|
@@ -58,18 +58,15 @@ module.exports = {
|
|
|
58
58
|
const params = [];
|
|
59
59
|
|
|
60
60
|
// If the targetField property is defined, then reference it,
|
|
61
|
-
// otherwise, put `undefined` keyword type
|
|
62
|
-
const
|
|
63
|
-
?
|
|
64
|
-
|
|
65
|
-
factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword),
|
|
66
|
-
]
|
|
67
|
-
: [factory.createStringLiteral(uid), factory.createStringLiteral(targetField)];
|
|
61
|
+
// otherwise, put `undefined` keyword type node as placeholder
|
|
62
|
+
const targetFieldParam = _.isUndefined(targetField)
|
|
63
|
+
? factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword)
|
|
64
|
+
: factory.createStringLiteral(targetField);
|
|
68
65
|
|
|
69
|
-
params.push(
|
|
66
|
+
params.push(targetFieldParam);
|
|
70
67
|
|
|
71
68
|
// If the options property is defined, transform it to
|
|
72
|
-
// a type
|
|
69
|
+
// a type literal node and add it to the params list
|
|
73
70
|
if (_.isObject(options)) {
|
|
74
71
|
params.push(toTypeLiteral(options));
|
|
75
72
|
}
|
|
@@ -87,28 +84,42 @@ module.exports = {
|
|
|
87
84
|
json() {
|
|
88
85
|
return [withAttributeNamespace('JSON')];
|
|
89
86
|
},
|
|
90
|
-
|
|
91
|
-
return [withAttributeNamespace('
|
|
87
|
+
blocks() {
|
|
88
|
+
return [withAttributeNamespace('Blocks')];
|
|
92
89
|
},
|
|
93
|
-
|
|
90
|
+
media({ attribute }) {
|
|
91
|
+
const { allowedTypes, multiple } = attribute;
|
|
92
|
+
|
|
93
|
+
const params = [];
|
|
94
|
+
|
|
95
|
+
const typesParam = allowedTypes
|
|
96
|
+
? factory.createUnionTypeNode(
|
|
97
|
+
allowedTypes.map((allowedType) => factory.createStringLiteral(allowedType))
|
|
98
|
+
)
|
|
99
|
+
: factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword);
|
|
100
|
+
|
|
101
|
+
if (allowedTypes || multiple) {
|
|
102
|
+
params.push(typesParam);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (multiple) {
|
|
106
|
+
params.push(factory.createTrue());
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return [withAttributeNamespace('Media'), params];
|
|
110
|
+
},
|
|
111
|
+
relation({ attribute }) {
|
|
94
112
|
const { relation, target } = attribute;
|
|
95
113
|
|
|
96
114
|
const isMorphRelation = relation.toLowerCase().includes('morph');
|
|
97
115
|
|
|
98
116
|
if (isMorphRelation) {
|
|
99
|
-
return [
|
|
100
|
-
withAttributeNamespace('Relation'),
|
|
101
|
-
[factory.createStringLiteral(uid, true), factory.createStringLiteral(relation, true)],
|
|
102
|
-
];
|
|
117
|
+
return [withAttributeNamespace('Relation'), [factory.createStringLiteral(relation, true)]];
|
|
103
118
|
}
|
|
104
119
|
|
|
105
120
|
return [
|
|
106
121
|
withAttributeNamespace('Relation'),
|
|
107
|
-
[
|
|
108
|
-
factory.createStringLiteral(uid, true),
|
|
109
|
-
factory.createStringLiteral(relation, true),
|
|
110
|
-
factory.createStringLiteral(target, true),
|
|
111
|
-
],
|
|
122
|
+
[factory.createStringLiteral(relation, true), factory.createStringLiteral(target, true)],
|
|
112
123
|
];
|
|
113
124
|
},
|
|
114
125
|
component({ attribute }) {
|
|
@@ -117,6 +128,8 @@ module.exports = {
|
|
|
117
128
|
|
|
118
129
|
if (attribute.repeatable) {
|
|
119
130
|
params.push(factory.createTrue());
|
|
131
|
+
} else {
|
|
132
|
+
params.push(factory.createFalse());
|
|
120
133
|
}
|
|
121
134
|
|
|
122
135
|
return [withAttributeNamespace('Component'), params];
|
|
@@ -22,9 +22,11 @@ const { addImport } = require('../imports');
|
|
|
22
22
|
const generateAttributePropertySignature = (schema) => {
|
|
23
23
|
const { attributes } = schema;
|
|
24
24
|
|
|
25
|
-
const properties = Object.entries(attributes)
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
const properties = Object.entries(attributes)
|
|
26
|
+
.sort((a, b) => a[0].localeCompare(b[0]))
|
|
27
|
+
.map(([attributeName, attribute]) => {
|
|
28
|
+
return attributeToPropertySignature(schema, attributeName, attribute);
|
|
29
|
+
});
|
|
28
30
|
|
|
29
31
|
return factory.createPropertySignature(
|
|
30
32
|
undefined,
|
|
@@ -56,8 +58,8 @@ const generateSchemaDefinition = (schema) => {
|
|
|
56
58
|
const interfaceName = getSchemaInterfaceName(uid);
|
|
57
59
|
const parentType = getSchemaExtendsTypeName(schema);
|
|
58
60
|
|
|
59
|
-
// Make sure the
|
|
60
|
-
addImport(NAMESPACES.
|
|
61
|
+
// Make sure the Struct namespace is imported
|
|
62
|
+
addImport(NAMESPACES.Struct);
|
|
61
63
|
|
|
62
64
|
// Properties whose values can be mapped to a literal type expression
|
|
63
65
|
const literalPropertiesDefinitions = ['collectionName', 'info', 'options', 'pluginOptions']
|
|
@@ -18,8 +18,8 @@ const {
|
|
|
18
18
|
} = require('lodash/fp');
|
|
19
19
|
|
|
20
20
|
const NAMESPACES = {
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
Struct: 'Struct',
|
|
22
|
+
Schema: 'Schema',
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
/**
|
|
@@ -50,7 +50,7 @@ const getSchemaModelType = (schema) => {
|
|
|
50
50
|
* Get the parent type name to extend based on the schema's nature
|
|
51
51
|
*
|
|
52
52
|
* @param {object} schema
|
|
53
|
-
* @returns {string}
|
|
53
|
+
* @returns {string|null}
|
|
54
54
|
*/
|
|
55
55
|
const getSchemaExtendsTypeName = (schema) => {
|
|
56
56
|
const base = getSchemaModelType(schema);
|
|
@@ -59,7 +59,7 @@ const getSchemaExtendsTypeName = (schema) => {
|
|
|
59
59
|
return null;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
return `${NAMESPACES.
|
|
62
|
+
return `${NAMESPACES.Struct}.${upperFirst(base)}Schema`;
|
|
63
63
|
};
|
|
64
64
|
|
|
65
65
|
/**
|
|
@@ -111,7 +111,7 @@ const toTypeLiteral = (data) => {
|
|
|
111
111
|
throw new Error(`Cannot convert to object literal. Unknown type "${typeof data}"`);
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
const entries = Object.entries(data);
|
|
114
|
+
const entries = Object.entries(data).sort((a, b) => a[0].localeCompare(b[0]));
|
|
115
115
|
|
|
116
116
|
const props = entries.reduce((acc, [key, value]) => {
|
|
117
117
|
// Handle keys such as content-type-builder & co.
|
|
@@ -145,12 +145,12 @@ const getDefinitionAttributesCount = (definition) => {
|
|
|
145
145
|
};
|
|
146
146
|
|
|
147
147
|
/**
|
|
148
|
-
* Add the
|
|
148
|
+
* Add the Schema.Attribute namespace before the typename
|
|
149
149
|
*
|
|
150
150
|
* @param {string} typeName
|
|
151
151
|
* @returns {string}
|
|
152
152
|
*/
|
|
153
|
-
const withAttributeNamespace = (typeName) => `${NAMESPACES.
|
|
153
|
+
const withAttributeNamespace = (typeName) => `${NAMESPACES.Schema}.Attribute.${typeName}`;
|
|
154
154
|
|
|
155
155
|
/**
|
|
156
156
|
* Add the schema namespace before the typename
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { factory } = require('typescript');
|
|
4
|
+
const { pipe, values, sortBy, map } = require('lodash/fp');
|
|
4
5
|
|
|
5
6
|
const { models } = require('../common');
|
|
6
7
|
const { emitDefinitions, format, generateSharedExtensionDefinition } = require('../utils');
|
|
7
8
|
|
|
9
|
+
const NO_COMPONENT_PLACEHOLDER_COMMENT = `/*
|
|
10
|
+
* The app doesn't have any components yet.
|
|
11
|
+
*/
|
|
12
|
+
`;
|
|
13
|
+
|
|
8
14
|
/**
|
|
9
15
|
* Generate type definitions for Strapi Components
|
|
10
16
|
*
|
|
@@ -18,10 +24,20 @@ const generateComponentsDefinitions = async (options = {}) => {
|
|
|
18
24
|
|
|
19
25
|
const { components } = strapi;
|
|
20
26
|
|
|
21
|
-
const componentsDefinitions =
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
const componentsDefinitions = pipe(
|
|
28
|
+
values,
|
|
29
|
+
sortBy('uid'),
|
|
30
|
+
map((component) => ({
|
|
31
|
+
uid: component.uid,
|
|
32
|
+
definition: models.schema.generateSchemaDefinition(component),
|
|
33
|
+
}))
|
|
34
|
+
)(components);
|
|
35
|
+
|
|
36
|
+
options.logger.debug(`Found ${componentsDefinitions.length} components.`);
|
|
37
|
+
|
|
38
|
+
if (componentsDefinitions.length === 0) {
|
|
39
|
+
return { output: NO_COMPONENT_PLACEHOLDER_COMMENT, stats: {} };
|
|
40
|
+
}
|
|
25
41
|
|
|
26
42
|
const formattedSchemasDefinitions = componentsDefinitions.reduce((acc, def) => {
|
|
27
43
|
acc.push(
|
|
@@ -46,7 +62,7 @@ const generateComponentsDefinitions = async (options = {}) => {
|
|
|
46
62
|
...formattedSchemasDefinitions,
|
|
47
63
|
|
|
48
64
|
// Global
|
|
49
|
-
generateSharedExtensionDefinition('
|
|
65
|
+
generateSharedExtensionDefinition('ComponentSchemas', componentsDefinitions),
|
|
50
66
|
];
|
|
51
67
|
|
|
52
68
|
const output = emitDefinitions(allDefinitions);
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { factory } = require('typescript');
|
|
4
|
+
const { values, pipe, map, sortBy } = require('lodash/fp');
|
|
4
5
|
|
|
5
6
|
const { models } = require('../common');
|
|
6
7
|
const { emitDefinitions, format, generateSharedExtensionDefinition } = require('../utils');
|
|
7
8
|
|
|
9
|
+
const NO_CONTENT_TYPE_PLACEHOLDER_COMMENT = `/*
|
|
10
|
+
* The app doesn't have any content-types yet.
|
|
11
|
+
*/
|
|
12
|
+
`;
|
|
13
|
+
|
|
8
14
|
/**
|
|
9
15
|
* Generate type definitions for Strapi Content-Types
|
|
10
16
|
*
|
|
@@ -18,10 +24,20 @@ const generateContentTypesDefinitions = async (options = {}) => {
|
|
|
18
24
|
|
|
19
25
|
const { contentTypes } = strapi;
|
|
20
26
|
|
|
21
|
-
const contentTypesDefinitions =
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
const contentTypesDefinitions = pipe(
|
|
28
|
+
values,
|
|
29
|
+
sortBy('uid'),
|
|
30
|
+
map((contentType) => ({
|
|
31
|
+
uid: contentType.uid,
|
|
32
|
+
definition: models.schema.generateSchemaDefinition(contentType),
|
|
33
|
+
}))
|
|
34
|
+
)(contentTypes);
|
|
35
|
+
|
|
36
|
+
options.logger.debug(`Found ${contentTypesDefinitions.length} content-types.`);
|
|
37
|
+
|
|
38
|
+
if (contentTypesDefinitions.length === 0) {
|
|
39
|
+
return { output: NO_CONTENT_TYPE_PLACEHOLDER_COMMENT, stats: {} };
|
|
40
|
+
}
|
|
25
41
|
|
|
26
42
|
const formattedSchemasDefinitions = contentTypesDefinitions.reduce((acc, def) => {
|
|
27
43
|
acc.push(
|
|
@@ -46,7 +62,7 @@ const generateContentTypesDefinitions = async (options = {}) => {
|
|
|
46
62
|
...formattedSchemasDefinitions,
|
|
47
63
|
|
|
48
64
|
// Global
|
|
49
|
-
generateSharedExtensionDefinition('
|
|
65
|
+
generateSharedExtensionDefinition('ContentTypeSchemas', contentTypesDefinitions),
|
|
50
66
|
];
|
|
51
67
|
|
|
52
68
|
const output = emitDefinitions(allDefinitions);
|
package/lib/generators/index.js
CHANGED
|
@@ -100,7 +100,7 @@ const generate = async (config = {}) => {
|
|
|
100
100
|
|
|
101
101
|
try {
|
|
102
102
|
const outPath = await saveDefinitionToFileSystem(registryPwd, filename, report.output);
|
|
103
|
-
const relativeOutPath = path.relative(
|
|
103
|
+
const relativeOutPath = path.relative(process.cwd(), outPath);
|
|
104
104
|
|
|
105
105
|
artifactFsTimer.end();
|
|
106
106
|
|
package/lib/generators/utils.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const assert = require('assert');
|
|
3
5
|
const ts = require('typescript');
|
|
4
|
-
const prettier = require('prettier');
|
|
5
6
|
const fse = require('fs-extra');
|
|
6
|
-
const path = require('path');
|
|
7
7
|
const chalk = require('chalk');
|
|
8
|
-
const assert = require('assert');
|
|
9
8
|
|
|
10
9
|
const { factory } = ts;
|
|
11
10
|
|
|
11
|
+
const MODULE_DECLARATION = '@strapi/strapi';
|
|
12
|
+
const PUBLIC_NAMESPACE = 'Public';
|
|
13
|
+
|
|
12
14
|
/**
|
|
13
15
|
* Aggregate the given TypeScript nodes into a single string
|
|
14
16
|
*
|
|
@@ -58,6 +60,9 @@ const saveDefinitionToFileSystem = async (dir, file, content) => {
|
|
|
58
60
|
* @returns {Promise<string>}
|
|
59
61
|
*/
|
|
60
62
|
const format = async (content) => {
|
|
63
|
+
// eslint-disable-next-line node/no-unsupported-features/es-syntax
|
|
64
|
+
const prettier = await import('prettier'); // ESM-only
|
|
65
|
+
|
|
61
66
|
const configFile = await prettier.resolveConfigFile();
|
|
62
67
|
const config = configFile
|
|
63
68
|
? await prettier.resolveConfig(configFile)
|
|
@@ -92,11 +97,11 @@ const generateSharedExtensionDefinition = (registry, definitions) => {
|
|
|
92
97
|
|
|
93
98
|
return factory.createModuleDeclaration(
|
|
94
99
|
[factory.createModifier(ts.SyntaxKind.DeclareKeyword)],
|
|
95
|
-
factory.createStringLiteral(
|
|
100
|
+
factory.createStringLiteral(MODULE_DECLARATION, true),
|
|
96
101
|
factory.createModuleBlock([
|
|
97
102
|
factory.createModuleDeclaration(
|
|
98
103
|
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
99
|
-
factory.createIdentifier(
|
|
104
|
+
factory.createIdentifier(PUBLIC_NAMESPACE),
|
|
100
105
|
factory.createModuleBlock(
|
|
101
106
|
properties.length > 0
|
|
102
107
|
? [
|
package/lib/index.js
CHANGED
|
@@ -2,15 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
const compile = require('./compile');
|
|
4
4
|
const compilers = require('./compilers');
|
|
5
|
-
const admin = require('./admin');
|
|
6
5
|
const utils = require('./utils');
|
|
7
6
|
const generators = require('./generators');
|
|
8
7
|
|
|
9
8
|
module.exports = {
|
|
10
9
|
compile,
|
|
11
10
|
compilers,
|
|
12
|
-
admin,
|
|
13
11
|
generators,
|
|
14
|
-
|
|
15
12
|
...utils,
|
|
16
13
|
};
|
package/lib/utils/index.js
CHANGED
|
@@ -7,6 +7,7 @@ const reportDiagnostics = require('./report-diagnostics');
|
|
|
7
7
|
const resolveConfigOptions = require('./resolve-config-options');
|
|
8
8
|
const formatHost = require('./format-host');
|
|
9
9
|
const resolveOutDir = require('./resolve-outdir');
|
|
10
|
+
const resolveOutDirSync = require('./resolve-outdir-sync');
|
|
10
11
|
|
|
11
12
|
module.exports = {
|
|
12
13
|
isUsingTypeScript,
|
|
@@ -16,4 +17,5 @@ module.exports = {
|
|
|
16
17
|
resolveConfigOptions,
|
|
17
18
|
formatHost,
|
|
18
19
|
resolveOutDir,
|
|
20
|
+
resolveOutDirSync,
|
|
19
21
|
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const resolveConfigOptions = require('./resolve-config-options');
|
|
5
|
+
const isUsingTypescriptSync = require('./is-using-typescript-sync');
|
|
6
|
+
|
|
7
|
+
const DEFAULT_TS_CONFIG_FILENAME = 'tsconfig.json';
|
|
8
|
+
/**
|
|
9
|
+
* Gets the outDir value from config file (tsconfig)
|
|
10
|
+
* @param {string} dir
|
|
11
|
+
* @param {string | undefined} configFilename
|
|
12
|
+
* @returns {string | undefined}
|
|
13
|
+
*/
|
|
14
|
+
module.exports = (dir, configFilename = DEFAULT_TS_CONFIG_FILENAME) => {
|
|
15
|
+
return isUsingTypescriptSync(dir)
|
|
16
|
+
? resolveConfigOptions(path.join(dir, configFilename)).options.outDir
|
|
17
|
+
: undefined;
|
|
18
|
+
};
|