@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.
@@ -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 }, 'Schema.Component'],
124
- [{ modelType: 'contentType', kind: 'singleType' }, 'Schema.SingleType'],
125
- [{ modelType: 'contentType', kind: 'collectionType' }, 'Schema.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('foo');
251
- expect(objectNode.members[0].type.kind).toBe(ts.SyntaxKind.StringLiteral);
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('bar');
256
- expect(objectNode.members[1].type.kind).toBe(ts.SyntaxKind.TrueKeyword);
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 [firstMember, secondMember] = node.members;
265
+ const [barMember, fooMember] = node.members;
266
266
 
267
- expect(firstMember.kind).toBe(ts.SyntaxKind.PropertyDeclaration);
268
- expect(firstMember.name.escapedText).toBe('foo');
269
- expect(firstMember.type.kind).toBe(ts.SyntaxKind.TupleType);
270
- expect(firstMember.type.elements).toHaveLength(3);
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(secondMember.kind).toBe(ts.SyntaxKind.PropertyDeclaration);
276
- expect(secondMember.name.escapedText).toBe('bar');
277
- expect(secondMember.type.kind).toBe(ts.SyntaxKind.LiteralType);
278
- expect(secondMember.type.literal).toBe(ts.SyntaxKind.NullKeyword);
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 [firstMember, secondMember] = node.members;
287
+ const [fooBar, fooDashBar] = node.members;
288
288
 
289
- expect(firstMember.kind).toBe(ts.SyntaxKind.PropertyDeclaration);
290
- expect(firstMember.name.kind).toBe(ts.SyntaxKind.StringLiteral);
291
- expect(firstMember.name.text).toBe('foo-bar');
292
- expect(firstMember.type.kind).toBe(ts.SyntaxKind.StringLiteral);
293
- expect(firstMember.type.text).toBe('foobar');
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(secondMember.kind).toBe(ts.SyntaxKind.PropertyDeclaration);
296
- expect(secondMember.name.kind).toBe(ts.SyntaxKind.Identifier);
297
- expect(secondMember.name.escapedText).toBe('foo');
298
- expect(secondMember.type.kind).toBe(ts.SyntaxKind.StringLiteral);
299
- expect(secondMember.type.text).toBe('bar');
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, { watch = false, configOptions = {} } = {}) => {
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
- compiler.run(configPath, configOptions);
9
+ compilers.basic.run(configPath, configOptions);
14
10
  };
@@ -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: merge(options, configOptions.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
  },
@@ -1,9 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const basic = require('./basic');
4
- const watch = require('./watch');
5
4
 
6
5
  module.exports = {
7
6
  basic,
8
- watch,
9
7
  };
@@ -18,9 +18,9 @@ module.exports = {
18
18
  },
19
19
 
20
20
  generateImportDefinition() {
21
- const formattedImports = imports.map((key) =>
22
- factory.createImportSpecifier(false, undefined, factory.createIdentifier(key))
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 { factory } = require('typescript');
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 attribute namespace is imported
30
- addImport(NAMESPACES.attribute);
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.mappers = mappers;
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, uid }) {
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 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)];
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(...targetFieldParams);
66
+ params.push(targetFieldParam);
70
67
 
71
68
  // If the options property is defined, transform it to
72
- // a type literral node and add it to the params list
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
- media() {
91
- return [withAttributeNamespace('Media')];
87
+ blocks() {
88
+ return [withAttributeNamespace('Blocks')];
92
89
  },
93
- relation({ uid, attribute }) {
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).map(([attributeName, attribute]) => {
26
- return attributeToPropertySignature(schema, attributeName, attribute);
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 Schema namespace is imported
60
- addImport(NAMESPACES.schema);
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
- schema: 'Schema',
22
- attribute: 'Attribute',
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.schema}.${upperFirst(base)}`;
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 attribute namespace before the typename
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.attribute}.${typeName}`;
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 = Object.values(components).map((contentType) => ({
22
- uid: contentType.uid,
23
- definition: models.schema.generateSchemaDefinition(contentType),
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('Components', componentsDefinitions),
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 = Object.values(contentTypes).map((contentType) => ({
22
- uid: contentType.uid,
23
- definition: models.schema.generateSchemaDefinition(contentType),
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('ContentTypes', contentTypesDefinitions),
65
+ generateSharedExtensionDefinition('ContentTypeSchemas', contentTypesDefinitions),
50
66
  ];
51
67
 
52
68
  const output = emitDefinitions(allDefinitions);
@@ -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(__dirname, outPath);
103
+ const relativeOutPath = path.relative(process.cwd(), outPath);
104
104
 
105
105
  artifactFsTimer.end();
106
106
 
@@ -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('@strapi/strapi', true),
100
+ factory.createStringLiteral(MODULE_DECLARATION, true),
96
101
  factory.createModuleBlock([
97
102
  factory.createModuleDeclaration(
98
103
  [factory.createModifier(ts.SyntaxKind.ExportKeyword)],
99
- factory.createIdentifier('Shared'),
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
  };
@@ -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
+ };