@strapi/strapi 4.3.4 → 4.4.0-alpha.0

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.
Files changed (115) hide show
  1. package/README.md +1 -1
  2. package/bin/strapi.js +29 -26
  3. package/lib/Strapi.js +17 -9
  4. package/lib/commands/admin-create.js +2 -5
  5. package/lib/commands/admin-reset.js +1 -1
  6. package/lib/commands/build.js +1 -1
  7. package/lib/commands/builders/admin.js +1 -1
  8. package/lib/commands/builders/typescript.js +2 -2
  9. package/lib/commands/configurationDump.js +3 -3
  10. package/lib/commands/configurationRestore.js +5 -4
  11. package/lib/commands/console.js +1 -1
  12. package/lib/commands/content-types/list.js +2 -2
  13. package/lib/commands/controllers/list.js +2 -2
  14. package/lib/commands/develop.js +16 -10
  15. package/lib/commands/hooks/list.js +2 -2
  16. package/lib/commands/install.js +4 -4
  17. package/lib/commands/middlewares/list.js +2 -2
  18. package/lib/commands/new.js +1 -1
  19. package/lib/commands/opt-in-telemetry.js +12 -13
  20. package/lib/commands/opt-out-telemetry.js +3 -3
  21. package/lib/commands/policies/list.js +2 -2
  22. package/lib/commands/routes/list.js +3 -3
  23. package/lib/commands/services/list.js +2 -2
  24. package/lib/commands/start.js +1 -0
  25. package/lib/commands/ts/generate-types.js +1 -1
  26. package/lib/commands/uninstall.js +4 -4
  27. package/lib/commands/watchAdmin.js +1 -1
  28. package/lib/compile.js +1 -1
  29. package/lib/container.js +1 -1
  30. package/lib/core/app-configuration/config-loader.js +2 -2
  31. package/lib/core/app-configuration/load-config-file.js +3 -3
  32. package/lib/core/bootstrap.js +1 -1
  33. package/lib/core/domain/component/validator.js +3 -9
  34. package/lib/core/domain/content-type/index.js +2 -2
  35. package/lib/core/domain/content-type/validator.js +9 -23
  36. package/lib/core/domain/module/index.js +1 -1
  37. package/lib/core/domain/module/validation.js +3 -4
  38. package/lib/core/loaders/admin.js +1 -1
  39. package/lib/core/loaders/apis.js +22 -30
  40. package/lib/core/loaders/components.js +2 -2
  41. package/lib/core/loaders/middlewares.js +1 -1
  42. package/lib/core/loaders/plugins/get-enabled-plugins.js +7 -7
  43. package/lib/core/loaders/plugins/index.js +7 -8
  44. package/lib/core/loaders/sanitizers.js +1 -1
  45. package/lib/core/loaders/src-index.js +2 -2
  46. package/lib/core/registries/apis.js +1 -1
  47. package/lib/core/registries/config.js +1 -1
  48. package/lib/core/registries/content-types.js +1 -1
  49. package/lib/core/registries/custom-fields.js +54 -0
  50. package/lib/core/registries/modules.js +1 -1
  51. package/lib/core/registries/plugins.js +1 -1
  52. package/lib/core/registries/services.js +1 -1
  53. package/lib/core/utils.js +3 -6
  54. package/lib/core-api/controller/transform.js +4 -4
  55. package/lib/core-api/service/collection-type.js +1 -1
  56. package/lib/core-api/service/index.d.ts +6 -3
  57. package/lib/core-api/service/pagination.js +5 -5
  58. package/lib/factories.js +5 -5
  59. package/lib/load/filepath-to-prop-path.js +2 -2
  60. package/lib/load/load-files.js +1 -1
  61. package/lib/load/package-path.js +1 -1
  62. package/lib/middlewares/body.js +10 -3
  63. package/lib/middlewares/compression.js +1 -1
  64. package/lib/middlewares/cors.js +3 -10
  65. package/lib/middlewares/ip.js +1 -1
  66. package/lib/middlewares/logger.js +4 -1
  67. package/lib/middlewares/powered-by.js +1 -1
  68. package/lib/middlewares/query.js +8 -2
  69. package/lib/middlewares/response-time.js +1 -1
  70. package/lib/middlewares/responses.js +1 -1
  71. package/lib/middlewares/security.js +22 -16
  72. package/lib/middlewares/session.js +2 -2
  73. package/lib/migrations/draft-publish.js +1 -5
  74. package/lib/services/auth/index.js +1 -3
  75. package/lib/services/core-store.js +4 -4
  76. package/lib/services/custom-fields.js +11 -0
  77. package/lib/services/entity-service/components.js +12 -18
  78. package/lib/services/entity-service/index.js +65 -51
  79. package/lib/services/entity-validator/index.js +134 -127
  80. package/lib/services/entity-validator/validators.js +18 -15
  81. package/lib/services/errors.js +6 -10
  82. package/lib/services/event-hub.js +1 -0
  83. package/lib/services/fs.js +1 -1
  84. package/lib/services/metrics/index.js +6 -9
  85. package/lib/services/metrics/is-truthy.js +1 -1
  86. package/lib/services/metrics/sender.js +4 -4
  87. package/lib/services/metrics/stringify-deep.js +1 -1
  88. package/lib/services/server/admin-api.js +1 -1
  89. package/lib/services/server/compose-endpoint.js +7 -7
  90. package/lib/services/server/content-api.js +1 -1
  91. package/lib/services/server/http-server.js +9 -9
  92. package/lib/services/server/index.js +4 -4
  93. package/lib/services/server/koa.js +9 -12
  94. package/lib/services/server/middleware.js +1 -1
  95. package/lib/services/server/policy.js +1 -1
  96. package/lib/services/server/register-middlewares.js +6 -8
  97. package/lib/services/server/register-routes.js +11 -11
  98. package/lib/services/server/routing.js +11 -26
  99. package/lib/services/utils/upload-files.js +3 -3
  100. package/lib/services/webhook-runner.js +8 -7
  101. package/lib/services/webhook-store.js +3 -2
  102. package/lib/services/worker-queue.js +1 -0
  103. package/lib/types/core/strapi/index.d.ts +4 -3
  104. package/lib/types/factories.d.ts +3 -3
  105. package/lib/utils/addSlash.js +3 -3
  106. package/lib/utils/convert-custom-field-type.js +22 -0
  107. package/lib/utils/ee.js +1 -1
  108. package/lib/utils/import-default.js +1 -1
  109. package/lib/utils/open-browser.js +1 -1
  110. package/lib/utils/run-checks.js +4 -4
  111. package/lib/utils/signals.js +2 -2
  112. package/lib/utils/startup-logger.js +2 -2
  113. package/lib/utils/success.js +1 -1
  114. package/lib/utils/update-notifier/index.js +4 -4
  115. package/package.json +15 -15
@@ -1,4 +1,5 @@
1
1
  'use strict';
2
+
2
3
  const fs = require('fs');
3
4
  const tsUtils = require('@strapi/typescript-utils');
4
5
  const strapi = require('../index');
@@ -4,7 +4,7 @@ const tsUtils = require('@strapi/typescript-utils');
4
4
 
5
5
  const strapi = require('../../index');
6
6
 
7
- module.exports = async function({ outDir, file, verbose, silent }) {
7
+ module.exports = async function ({ outDir, file, verbose, silent }) {
8
8
  if (verbose && silent) {
9
9
  console.error('You cannot enable verbose and silent flags at the same time, exiting...');
10
10
  process.exit(1);
@@ -21,13 +21,13 @@ module.exports = async (plugins, { deleteFiles }) => {
21
21
  const loader = ora();
22
22
  const dir = process.cwd();
23
23
 
24
- const pluginArgs = plugins.map(name => `@strapi/plugin-${name}`);
24
+ const pluginArgs = plugins.map((name) => `@strapi/plugin-${name}`);
25
25
 
26
26
  try {
27
27
  // verify should rebuild before removing the pacakge
28
28
  let shouldRebuild = false;
29
- for (let name of plugins) {
30
- let pkgPath = findPackagePath(`@strapi/plugin-${name}`);
29
+ for (const name of plugins) {
30
+ const pkgPath = findPackagePath(`@strapi/plugin-${name}`);
31
31
  if (existsSync(join(pkgPath, 'admin', 'src', 'index.js'))) {
32
32
  shouldRebuild = true;
33
33
  }
@@ -46,7 +46,7 @@ module.exports = async (plugins, { deleteFiles }) => {
46
46
 
47
47
  if (deleteFiles === true || answers.deleteFiles === true) {
48
48
  loader.start('Deleting old files');
49
- for (let name of plugins) {
49
+ for (const name of plugins) {
50
50
  const pluginDir = join(dir, 'extensions', name);
51
51
  if (existsSync(pluginDir)) {
52
52
  removeSync(pluginDir);
@@ -7,7 +7,7 @@ const getEnabledPlugins = require('../core/loaders/plugins/get-enabled-plugins')
7
7
  const addSlash = require('../utils/addSlash');
8
8
  const strapi = require('../index');
9
9
 
10
- module.exports = async function({ browser }) {
10
+ module.exports = async function ({ browser }) {
11
11
  const appContext = await strapi.compile();
12
12
 
13
13
  const strapiInstance = strapi({
package/lib/compile.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  const tsUtils = require('@strapi/typescript-utils');
4
4
 
5
- module.exports = async dir => {
5
+ module.exports = async (dir) => {
6
6
  const appDir = dir || process.cwd();
7
7
  const isTSProject = await tsUtils.isUsingTypeScript(appDir);
8
8
  const outDir = await tsUtils.resolveOutDir(appDir);
package/lib/container.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const createContainer = strapi => {
3
+ const createContainer = (strapi) => {
4
4
  const registered = new Map();
5
5
  const resolved = new Map();
6
6
 
@@ -6,12 +6,12 @@ const loadFile = require('./load-config-file');
6
6
 
7
7
  const VALID_EXTENSIONS = ['.js', '.json'];
8
8
 
9
- module.exports = dir => {
9
+ module.exports = (dir) => {
10
10
  if (!fs.existsSync(dir)) return {};
11
11
 
12
12
  return fs
13
13
  .readdirSync(dir, { withFileTypes: true })
14
- .filter(file => file.isFile() && VALID_EXTENSIONS.includes(path.extname(file.name)))
14
+ .filter((file) => file.isFile() && VALID_EXTENSIONS.includes(path.extname(file.name)))
15
15
  .reduce((acc, file) => {
16
16
  const key = path.basename(file.name, path.extname(file.name));
17
17
 
@@ -6,7 +6,7 @@ const { templateConfiguration, env } = require('@strapi/utils');
6
6
 
7
7
  const importDefault = require('../../utils/import-default');
8
8
 
9
- const loadJsFile = file => {
9
+ const loadJsFile = (file) => {
10
10
  try {
11
11
  const jsModule = importDefault(file);
12
12
 
@@ -21,7 +21,7 @@ const loadJsFile = file => {
21
21
  }
22
22
  };
23
23
 
24
- const loadJSONFile = file => {
24
+ const loadJSONFile = (file) => {
25
25
  try {
26
26
  return templateConfiguration(JSON.parse(fs.readFileSync(file)));
27
27
  } catch (error) {
@@ -29,7 +29,7 @@ const loadJSONFile = file => {
29
29
  }
30
30
  };
31
31
 
32
- const loadFile = file => {
32
+ const loadFile = (file) => {
33
33
  const ext = path.extname(file);
34
34
 
35
35
  switch (ext) {
@@ -3,7 +3,7 @@
3
3
  const { getConfigUrls } = require('@strapi/utils');
4
4
  const fse = require('fs-extra');
5
5
 
6
- module.exports = async function({ strapi }) {
6
+ module.exports = async function ({ strapi }) {
7
7
  strapi.config.port = strapi.config.get('server.port') || strapi.config.port;
8
8
  strapi.config.host = strapi.config.get('server.host') || strapi.config.host;
9
9
 
@@ -7,20 +7,14 @@ const componentSchemaValidator = () =>
7
7
  info: yup
8
8
  .object()
9
9
  .shape({
10
- singularName: yup
11
- .string()
12
- .isCamelCase()
13
- .required(),
14
- pluralName: yup
15
- .string()
16
- .isCamelCase()
17
- .required(),
10
+ singularName: yup.string().isCamelCase().required(),
11
+ pluralName: yup.string().isCamelCase().required(),
18
12
  displayName: yup.string().required(),
19
13
  })
20
14
  .required(),
21
15
  });
22
16
 
23
- const validateComponentDefinition = data => {
17
+ const validateComponentDefinition = (data) => {
24
18
  return componentSchemaValidator.validateSync(data, { strict: true, abortEarly: false });
25
19
  };
26
20
 
@@ -114,12 +114,12 @@ const createContentType = (uid, definition) => {
114
114
  };
115
115
 
116
116
  const getGlobalId = (model, modelName, prefix) => {
117
- let globalId = prefix ? `${prefix}-${modelName}` : modelName;
117
+ const globalId = prefix ? `${prefix}-${modelName}` : modelName;
118
118
 
119
119
  return model.globalId || _.upperFirst(_.camelCase(globalId));
120
120
  };
121
121
 
122
- const pickSchema = model => {
122
+ const pickSchema = (model) => {
123
123
  const schema = _.cloneDeep(
124
124
  _.pick(model, [
125
125
  'connection',
@@ -36,14 +36,9 @@ const LIFECYCLES = [
36
36
  * TODO V5: check if we can avoid this coupling by moving this logic
37
37
  * into the GraphQL plugin.
38
38
  */
39
- const GRAPHQL_ENUM_REGEX = new RegExp('^[_A-Za-z][_0-9A-Za-z]*$');
39
+ const GRAPHQL_ENUM_REGEX = /^[_A-Za-z][_0-9A-Za-z]*$/;
40
40
 
41
- const lifecyclesShape = _.mapValues(_.keyBy(LIFECYCLES), () =>
42
- yup
43
- .mixed()
44
- .nullable()
45
- .isFunction()
46
- );
41
+ const lifecyclesShape = _.mapValues(_.keyBy(LIFECYCLES), () => yup.mixed().nullable().isFunction());
47
42
 
48
43
  const contentTypeSchemaValidator = yup.object().shape({
49
44
  schema: yup.object().shape({
@@ -51,34 +46,28 @@ const contentTypeSchemaValidator = yup.object().shape({
51
46
  .object()
52
47
  .shape({
53
48
  displayName: yup.string().required(),
54
- singularName: yup
55
- .string()
56
- .isKebabCase()
57
- .required(),
58
- pluralName: yup
59
- .string()
60
- .isKebabCase()
61
- .required(),
49
+ singularName: yup.string().isKebabCase().required(),
50
+ pluralName: yup.string().isKebabCase().required(),
62
51
  })
63
52
  .required(),
64
53
  attributes: yup.object().test({
65
54
  name: 'valuesCollide',
66
55
  message: 'Some values collide when normalized',
67
56
  test(attributes) {
68
- for (const attrName in attributes) {
57
+ for (const attrName of Object.keys(attributes)) {
69
58
  const attr = attributes[attrName];
70
59
  if (attr.type === 'enumeration') {
71
60
  const regressedValues = attr.enum.map(toRegressedEnumValue);
72
61
 
73
62
  // should match the GraphQL regex
74
- if (!regressedValues.every(value => GRAPHQL_ENUM_REGEX.test(value))) {
63
+ if (!regressedValues.every((value) => GRAPHQL_ENUM_REGEX.test(value))) {
75
64
  const message = `Invalid enumeration value. Values should have at least one alphabetical character preceeding the first occurence of a number. Update your enumeration '${attrName}'.`;
76
65
 
77
66
  return this.createError({ message });
78
67
  }
79
68
 
80
69
  // should not contain empty values
81
- if (regressedValues.some(value => value === '')) {
70
+ if (regressedValues.some((value) => value === '')) {
82
71
  return this.createError({
83
72
  message: `At least one value of the enumeration '${attrName}' appears to be empty. Only alphanumerical characters are taken into account.`,
84
73
  });
@@ -104,13 +93,10 @@ const contentTypeSchemaValidator = yup.object().shape({
104
93
  }),
105
94
  }),
106
95
  actions: yup.object().onlyContainsFunctions(),
107
- lifecycles: yup
108
- .object()
109
- .shape(lifecyclesShape)
110
- .noUnknown(),
96
+ lifecycles: yup.object().shape(lifecyclesShape).noUnknown(),
111
97
  });
112
98
 
113
- const validateContentTypeDefinition = data => {
99
+ const validateContentTypeDefinition = (data) => {
114
100
  return contentTypeSchemaValidator.validateSync(data, { strict: true, abortEarly: false });
115
101
  };
116
102
 
@@ -4,7 +4,7 @@ const _ = require('lodash');
4
4
  const { removeNamespace } = require('../../utils');
5
5
  const { validateModule } = require('./validation');
6
6
 
7
- const uidToPath = uid => uid.replace('::', '.');
7
+ const uidToPath = (uid) => uid.replace('::', '.');
8
8
 
9
9
  // Removes the namespace from a map with keys prefixed with a namespace
10
10
  const removeNamespacedKeys = (map, namespace) => {
@@ -9,12 +9,11 @@ const strapiServerSchema = yup
9
9
  destroy: yup.mixed().isFunction(),
10
10
  register: yup.mixed().isFunction(),
11
11
  config: yup.object(),
12
- routes: yup.lazy(value => {
12
+ routes: yup.lazy((value) => {
13
13
  if (Array.isArray(value)) {
14
14
  return yup.array();
15
- } else {
16
- return yup.object();
17
15
  }
16
+ return yup.object();
18
17
  }),
19
18
  controllers: yup.object(),
20
19
  services: yup.object(),
@@ -24,7 +23,7 @@ const strapiServerSchema = yup
24
23
  })
25
24
  .noUnknown();
26
25
 
27
- const validateModule = data => {
26
+ const validateModule = (data) => {
28
27
  return strapiServerSchema.validateSync(data, { strict: true, abortEarly: false });
29
28
  };
30
29
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  const _ = require('lodash');
4
4
 
5
- module.exports = strapi => {
5
+ module.exports = (strapi) => {
6
6
  strapi.admin = require('@strapi/admin/strapi-server');
7
7
 
8
8
  strapi.container.get('services').add(`admin::`, strapi.admin.services);
@@ -14,12 +14,12 @@ const DEFAULT_CONTENT_TYPE = {
14
14
  };
15
15
 
16
16
  // to handle names with numbers in it we first check if it is already in kebabCase
17
- const normalizeName = name => (isKebabCase(name) ? name : _.kebabCase(name));
17
+ const normalizeName = (name) => (isKebabCase(name) ? name : _.kebabCase(name));
18
18
 
19
- const isDirectory = fd => fd.isDirectory();
20
- const isDotFile = fd => fd.name.startsWith('.');
19
+ const isDirectory = (fd) => fd.isDirectory();
20
+ const isDotFile = (fd) => fd.name.startsWith('.');
21
21
 
22
- module.exports = async strapi => {
22
+ module.exports = async (strapi) => {
23
23
  if (!existsSync(strapi.dirs.dist.api)) {
24
24
  return;
25
25
  }
@@ -45,8 +45,8 @@ module.exports = async strapi => {
45
45
  }
46
46
  };
47
47
 
48
- const validateContentTypesUnicity = apis => {
49
- const allApisSchemas = Object.values(apis).flatMap(api => Object.values(api.contentTypes));
48
+ const validateContentTypesUnicity = (apis) => {
49
+ const allApisSchemas = Object.values(apis).flatMap((api) => Object.values(api.contentTypes));
50
50
 
51
51
  const names = [];
52
52
  allApisSchemas.forEach(({ schema }) => {
@@ -68,26 +68,18 @@ const validateContentTypesUnicity = apis => {
68
68
  });
69
69
  };
70
70
 
71
- const loadAPI = async dir => {
72
- const [
73
- index,
74
- config,
75
- routes,
76
- controllers,
77
- services,
78
- policies,
79
- middlewares,
80
- contentTypes,
81
- ] = await Promise.all([
82
- loadIndex(dir),
83
- loadDir(join(dir, 'config')),
84
- loadDir(join(dir, 'routes')),
85
- loadDir(join(dir, 'controllers')),
86
- loadDir(join(dir, 'services')),
87
- loadDir(join(dir, 'policies')),
88
- loadDir(join(dir, 'middlewares')),
89
- loadContentTypes(join(dir, 'content-types')),
90
- ]);
71
+ const loadAPI = async (dir) => {
72
+ const [index, config, routes, controllers, services, policies, middlewares, contentTypes] =
73
+ await Promise.all([
74
+ loadIndex(dir),
75
+ loadDir(join(dir, 'config')),
76
+ loadDir(join(dir, 'routes')),
77
+ loadDir(join(dir, 'controllers')),
78
+ loadDir(join(dir, 'services')),
79
+ loadDir(join(dir, 'policies')),
80
+ loadDir(join(dir, 'middlewares')),
81
+ loadContentTypes(join(dir, 'content-types')),
82
+ ]);
91
83
 
92
84
  return {
93
85
  ...(index || {}),
@@ -101,13 +93,13 @@ const loadAPI = async dir => {
101
93
  };
102
94
  };
103
95
 
104
- const loadIndex = async dir => {
96
+ const loadIndex = async (dir) => {
105
97
  if (await fse.pathExists(join(dir, 'index.js'))) {
106
98
  return loadFile(join(dir, 'index.js'));
107
99
  }
108
100
  };
109
101
 
110
- const loadContentTypes = async dir => {
102
+ const loadContentTypes = async (dir) => {
111
103
  if (!(await fse.pathExists(dir))) {
112
104
  return;
113
105
  }
@@ -130,7 +122,7 @@ const loadContentTypes = async dir => {
130
122
  return contentTypes;
131
123
  };
132
124
 
133
- const loadDir = async dir => {
125
+ const loadDir = async (dir) => {
134
126
  if (!(await fse.pathExists(dir))) {
135
127
  return;
136
128
  }
@@ -150,7 +142,7 @@ const loadDir = async dir => {
150
142
  return root;
151
143
  };
152
144
 
153
- const loadFile = file => {
145
+ const loadFile = (file) => {
154
146
  const ext = extname(file);
155
147
 
156
148
  switch (ext) {
@@ -5,7 +5,7 @@ const _ = require('lodash');
5
5
  const { pathExists } = require('fs-extra');
6
6
  const loadFiles = require('../../load/load-files');
7
7
 
8
- module.exports = async strapi => {
8
+ module.exports = async (strapi) => {
9
9
  if (!(await pathExists(strapi.dirs.dist.components))) {
10
10
  return {};
11
11
  }
@@ -13,7 +13,7 @@ module.exports = async strapi => {
13
13
  const map = await loadFiles(strapi.dirs.dist.components, '*/*.*(js|json)');
14
14
 
15
15
  return Object.keys(map).reduce((acc, category) => {
16
- Object.keys(map[category]).forEach(key => {
16
+ Object.keys(map[category]).forEach((key) => {
17
17
  const schema = map[category][key];
18
18
 
19
19
  if (!schema.collectionName) {
@@ -14,7 +14,7 @@ module.exports = async function loadMiddlewares(strapi) {
14
14
  strapi.container.get('middlewares').add(`strapi::`, internalMiddlewares);
15
15
  };
16
16
 
17
- const loadLocalMiddlewares = async strapi => {
17
+ const loadLocalMiddlewares = async (strapi) => {
18
18
  const dir = strapi.dirs.dist.middlewares;
19
19
 
20
20
  if (!(await fse.pathExists(dir))) {
@@ -7,7 +7,7 @@ const { get, has, pick, pickBy, defaultsDeep, map, prop, pipe } = require('lodas
7
7
  const { isKebabCase } = require('@strapi/utils');
8
8
  const getUserPluginsConfig = require('./get-user-plugins-config');
9
9
 
10
- const isStrapiPlugin = info => get('strapi.kind', info) === 'plugin';
10
+ const isStrapiPlugin = (info) => get('strapi.kind', info) === 'plugin';
11
11
  const INTERNAL_PLUGINS = [
12
12
  '@strapi/plugin-content-manager',
13
13
  '@strapi/plugin-content-type-builder',
@@ -15,18 +15,18 @@ const INTERNAL_PLUGINS = [
15
15
  '@strapi/plugin-upload',
16
16
  ];
17
17
 
18
- const validatePluginName = pluginName => {
18
+ const validatePluginName = (pluginName) => {
19
19
  if (!isKebabCase(pluginName)) {
20
20
  throw new Error(`Plugin name "${pluginName}" is not in kebab (an-example-of-kebab-case)`);
21
21
  }
22
22
  };
23
23
 
24
- const toDetailedDeclaration = declaration => {
24
+ const toDetailedDeclaration = (declaration) => {
25
25
  if (typeof declaration === 'boolean') {
26
26
  return { enabled: declaration };
27
27
  }
28
28
 
29
- let detailedDeclaration = pick(['enabled'], declaration);
29
+ const detailedDeclaration = pick(['enabled'], declaration);
30
30
  if (has('resolve', declaration)) {
31
31
  let pathToPlugin = '';
32
32
 
@@ -45,7 +45,7 @@ const toDetailedDeclaration = declaration => {
45
45
  return detailedDeclaration;
46
46
  };
47
47
 
48
- const getEnabledPlugins = async strapi => {
48
+ const getEnabledPlugins = async (strapi) => {
49
49
  const internalPlugins = {};
50
50
  for (const dep of INTERNAL_PLUGINS) {
51
51
  const packagePath = join(dep, 'package.json');
@@ -106,14 +106,14 @@ const getEnabledPlugins = async strapi => {
106
106
 
107
107
  const declaredPluginsResolves = map(prop('pathToPlugin'), declaredPlugins);
108
108
  const installedPluginsNotAlreadyUsed = pickBy(
109
- p => !declaredPluginsResolves.includes(p.pathToPlugin),
109
+ (p) => !declaredPluginsResolves.includes(p.pathToPlugin),
110
110
  installedPlugins
111
111
  );
112
112
 
113
113
  const enabledPlugins = pipe(
114
114
  defaultsDeep(declaredPlugins),
115
115
  defaultsDeep(installedPluginsNotAlreadyUsed),
116
- pickBy(p => p.enabled)
116
+ pickBy((p) => p.enabled)
117
117
  )(internalPlugins);
118
118
 
119
119
  return enabledPlugins;
@@ -25,7 +25,7 @@ const defaultPlugin = {
25
25
  contentTypes: {},
26
26
  };
27
27
 
28
- const applyUserExtension = async plugins => {
28
+ const applyUserExtension = async (plugins) => {
29
29
  const extensionsDir = strapi.dirs.dist.extensions;
30
30
  if (!(await fse.pathExists(extensionsDir))) {
31
31
  return;
@@ -40,11 +40,10 @@ const applyUserExtension = async plugins => {
40
40
  for (const ctName in plugin.contentTypes) {
41
41
  const extendedSchema = get([pluginName, 'content-types', ctName, 'schema'], extendedSchemas);
42
42
  if (extendedSchema) {
43
- plugin.contentTypes[ctName].schema = Object.assign(
44
- {},
45
- plugin.contentTypes[ctName].schema,
46
- extendedSchema
47
- );
43
+ plugin.contentTypes[ctName].schema = {
44
+ ...plugin.contentTypes[ctName].schema,
45
+ ...extendedSchema,
46
+ };
48
47
  }
49
48
  }
50
49
  // second: execute strapi-server extension
@@ -55,7 +54,7 @@ const applyUserExtension = async plugins => {
55
54
  }
56
55
  };
57
56
 
58
- const applyUserConfig = async plugins => {
57
+ const applyUserConfig = async (plugins) => {
59
58
  const userPluginsConfig = await getUserPluginsConfig();
60
59
 
61
60
  for (const pluginName in plugins) {
@@ -76,7 +75,7 @@ const applyUserConfig = async plugins => {
76
75
  }
77
76
  };
78
77
 
79
- const loadPlugins = async strapi => {
78
+ const loadPlugins = async (strapi) => {
80
79
  const plugins = {};
81
80
 
82
81
  const enabledPlugins = await getEnabledPlugins(strapi);
@@ -1,5 +1,5 @@
1
1
  'use strict';
2
2
 
3
- module.exports = strapi => {
3
+ module.exports = (strapi) => {
4
4
  strapi.container.get('sanitizers').set('content-api', { input: [], output: [] });
5
5
  };
@@ -15,11 +15,11 @@ const srcSchema = yup
15
15
  })
16
16
  .noUnknown();
17
17
 
18
- const validateSrcIndex = srcIndex => {
18
+ const validateSrcIndex = (srcIndex) => {
19
19
  return srcSchema.validateSync(srcIndex, { strict: true, abortEarly: false });
20
20
  };
21
21
 
22
- module.exports = strapi => {
22
+ module.exports = (strapi) => {
23
23
  if (!existsSync(strapi.dirs.dist.src)) {
24
24
  return;
25
25
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  const { has } = require('lodash/fp');
4
4
 
5
- const apisRegistry = strapi => {
5
+ const apisRegistry = (strapi) => {
6
6
  const apis = {};
7
7
 
8
8
  return {
@@ -3,7 +3,7 @@
3
3
  const _ = require('lodash');
4
4
 
5
5
  module.exports = (initialConfig = {}) => {
6
- const _config = Object.assign({}, initialConfig); // not deep clone because it would break some config
6
+ const _config = { ...initialConfig }; // not deep clone because it would break some config
7
7
 
8
8
  return {
9
9
  ..._config, // TODO: to remove
@@ -4,7 +4,7 @@ const { pickBy, has } = require('lodash/fp');
4
4
  const { createContentType } = require('../domain/content-type');
5
5
  const { addNamespace, hasNamespace } = require('../utils');
6
6
 
7
- const validateKeySameToSingularName = contentTypes => {
7
+ const validateKeySameToSingularName = (contentTypes) => {
8
8
  for (const ctName in contentTypes) {
9
9
  const contentType = contentTypes[ctName];
10
10
 
@@ -0,0 +1,54 @@
1
+ 'use strict';
2
+
3
+ const { has } = require('lodash/fp');
4
+ const validators = require('../../services/entity-validator/validators');
5
+
6
+ const customFieldsRegistry = strapi => {
7
+ const customFields = {};
8
+
9
+ return {
10
+ getAll() {
11
+ return customFields;
12
+ },
13
+ get(customField) {
14
+ const registeredCustomField = customFields[customField];
15
+ if (!registeredCustomField) {
16
+ throw new Error(`Could not find Custom Field: ${customField}`);
17
+ }
18
+
19
+ return registeredCustomField;
20
+ },
21
+ add(customField) {
22
+ const customFieldList = Array.isArray(customField) ? customField : [customField];
23
+
24
+ for (const cf of customFieldList) {
25
+ if (!has('name', cf) || !has('type', cf)) {
26
+ throw new Error(`Custom fields require a 'name' and 'type' key`);
27
+ }
28
+
29
+ const { name, plugin, type } = cf;
30
+ if (!has(type, validators)) {
31
+ throw new Error(
32
+ `Custom field type: '${type}' is not a valid Strapi type or it can't be used with a Custom Field`
33
+ );
34
+ }
35
+
36
+ const isValidObjectKey = /^(?![0-9])[a-zA-Z0-9$_-]+$/g;
37
+ if (!isValidObjectKey.test(name)) {
38
+ throw new Error(`Custom field name: '${name}' is not a valid object key`);
39
+ }
40
+
41
+ // When no plugin is specified, or it isn't found in Strapi, default to global
42
+ const uid = strapi.plugin(plugin) ? `plugin::${plugin}.${name}` : `global::${name}`;
43
+
44
+ if (has(uid, customFields)) {
45
+ throw new Error(`Custom field: '${uid}' has already been registered`);
46
+ }
47
+
48
+ customFields[uid] = cf;
49
+ }
50
+ },
51
+ };
52
+ };
53
+
54
+ module.exports = customFieldsRegistry;
@@ -3,7 +3,7 @@
3
3
  const { pickBy, has } = require('lodash/fp');
4
4
  const { createModule } = require('../domain/module');
5
5
 
6
- const modulesRegistry = strapi => {
6
+ const modulesRegistry = (strapi) => {
7
7
  const modules = {};
8
8
 
9
9
  return {
@@ -2,7 +2,7 @@
2
2
 
3
3
  const { has } = require('lodash/fp');
4
4
 
5
- const pluginsRegistry = strapi => {
5
+ const pluginsRegistry = (strapi) => {
6
6
  const plugins = {};
7
7
 
8
8
  return {
@@ -8,7 +8,7 @@ const { addNamespace, hasNamespace } = require('../utils');
8
8
  * @typedef {import('./services').ServiceFactory} ServiceFactory
9
9
  */
10
10
 
11
- const servicesRegistry = strapi => {
11
+ const servicesRegistry = (strapi) => {
12
12
  const services = {};
13
13
  const instantiatedServices = {};
14
14