@lowdefy/build 0.0.0-experimental-20251203202233 → 0.0.0-experimental-20260112140412

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 (52) hide show
  1. package/dist/build/addKeys.js +2 -0
  2. package/dist/build/buildApi/buildEndpoint.js +6 -0
  3. package/dist/build/buildApi/buildRoutine/countStepTypes.js +1 -1
  4. package/dist/build/buildApi/validateStepReferences.js +65 -0
  5. package/dist/build/buildAuth/buildAuthPlugins.js +42 -12
  6. package/dist/build/buildAuth/validateAuthConfig.js +10 -2
  7. package/dist/build/buildAuth/validateMutualExclusivity.js +18 -4
  8. package/dist/build/buildConnections.js +25 -6
  9. package/dist/build/buildImports/buildIconImports.js +19 -36
  10. package/dist/build/buildLogger.js +41 -0
  11. package/dist/build/buildMenu.js +40 -13
  12. package/dist/build/buildPages/buildBlock/buildEvents.js +90 -9
  13. package/dist/build/buildPages/buildBlock/buildRequests.js +47 -7
  14. package/dist/build/buildPages/buildBlock/countBlockTypes.js +1 -1
  15. package/dist/build/buildPages/buildBlock/validateBlock.js +33 -7
  16. package/dist/build/buildPages/buildPage.js +28 -4
  17. package/dist/build/buildPages/buildPages.js +26 -1
  18. package/dist/build/buildPages/buildTestPage.js +9 -1
  19. package/dist/build/buildPages/validateLinkReferences.js +33 -0
  20. package/dist/build/buildPages/validatePayloadReferences.js +52 -0
  21. package/dist/build/buildPages/validateRequestReferences.js +33 -0
  22. package/dist/build/buildPages/validateStateReferences.js +52 -0
  23. package/dist/build/buildRefs/buildRefs.js +11 -30
  24. package/dist/build/buildRefs/evaluateBuildOperators.js +8 -2
  25. package/dist/build/buildRefs/getConfigFile.js +2 -1
  26. package/dist/build/buildRefs/getRefContent.js +17 -31
  27. package/dist/build/buildRefs/getRefsFromFile.js +8 -3
  28. package/dist/build/buildRefs/makeRefDefinition.js +9 -8
  29. package/dist/build/buildRefs/parseRefContent.js +61 -2
  30. package/dist/build/buildRefs/populateRefs.js +14 -11
  31. package/dist/build/buildRefs/recursiveBuild.js +64 -63
  32. package/dist/build/buildTypes.js +19 -2
  33. package/dist/build/formatBuildError.js +34 -0
  34. package/dist/build/writeLogger.js +19 -0
  35. package/dist/createContext.js +2 -15
  36. package/dist/defaultTypesMap.js +494 -487
  37. package/dist/index.js +130 -125
  38. package/dist/lowdefySchema.js +75 -0
  39. package/dist/test/testContext.js +2 -1
  40. package/dist/utils/countOperators.js +24 -11
  41. package/dist/utils/createCheckDuplicateId.js +30 -9
  42. package/dist/utils/createCounter.js +15 -2
  43. package/dist/utils/extractOperatorKey.js +36 -0
  44. package/dist/utils/findSimilarString.js +53 -0
  45. package/dist/utils/formatConfigError.js +24 -0
  46. package/dist/utils/formatConfigMessage.js +33 -0
  47. package/dist/utils/formatConfigWarning.js +24 -0
  48. package/dist/utils/traverseConfig.js +43 -0
  49. package/package.json +39 -39
  50. package/dist/utils/createBuildProfiler.js +0 -125
  51. package/dist/utils/invalidateChangedFiles.js +0 -74
  52. package/dist/utils/makeRefHash.js +0 -15
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /*
1
+ /* eslint-disable no-console */ /*
2
2
  Copyright 2020-2024 Lowdefy, Inc
3
3
 
4
4
  Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,8 +12,7 @@
12
12
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
- */ import createBuildProfiler from './utils/createBuildProfiler.js';
16
- import createContext from './createContext.js';
15
+ */ import createContext from './createContext.js';
17
16
  import createPluginTypesMap from './utils/createPluginTypesMap.js';
18
17
  import addDefaultPages from './build/addDefaultPages/addDefaultPages.js';
19
18
  import addKeys from './build/addKeys.js';
@@ -23,6 +22,7 @@ import buildConnections from './build/buildConnections.js';
23
22
  import buildApi from './build/buildApi/buildApi.js';
24
23
  import buildImports from './build/buildImports/buildImports.js';
25
24
  import buildJs from './build/buildJs/buildJs.js';
25
+ import buildLogger from './build/buildLogger.js';
26
26
  import buildMenu from './build/buildMenu.js';
27
27
  import buildPages from './build/buildPages/buildPages.js';
28
28
  import buildRefs from './build/buildRefs/buildRefs.js';
@@ -39,6 +39,7 @@ import writeConnections from './build/writeConnections.js';
39
39
  import writeApi from './build/writeApi.js';
40
40
  import writeGlobal from './build/writeGlobal.js';
41
41
  import writeJs from './build/buildJs/writeJs.js';
42
+ import writeLogger from './build/writeLogger.js';
42
43
  import writeMaps from './build/writeMaps.js';
43
44
  import writeMenus from './build/writeMenus.js';
44
45
  import writePages from './build/writePages.js';
@@ -47,128 +48,132 @@ import writeRequests from './build/writeRequests.js';
47
48
  import writeTypes from './build/writeTypes.js';
48
49
  async function build(options) {
49
50
  const context = createContext(options);
50
- const { time, printSummary } = createBuildProfiler({
51
- logger: context.logger
52
- });
53
- const components = await time('buildRefs', ()=>buildRefs({
54
- context
55
- }));
56
- await time('testSchema', ()=>testSchema({
57
- components,
58
- context
59
- }));
60
- await time('buildApp', ()=>buildApp({
61
- components,
62
- context
63
- }));
64
- await time('validateConfig', ()=>validateConfig({
65
- components,
66
- context
67
- }));
68
- await time('addDefaultPages', ()=>addDefaultPages({
69
- components,
70
- context
71
- }));
72
- await time('buildAuth', ()=>buildAuth({
73
- components,
74
- context
75
- }));
76
- await time('buildConnections', ()=>buildConnections({
77
- components,
78
- context
79
- }));
80
- await time('buildApi', ()=>buildApi({
81
- components,
82
- context
83
- }));
84
- await time('buildPages', ()=>buildPages({
85
- components,
86
- context
87
- }));
88
- await time('buildMenu', ()=>buildMenu({
89
- components,
90
- context
91
- }));
92
- await time('buildJs', ()=>buildJs({
93
- components,
94
- context
95
- }));
96
- await time('addKeys', ()=>addKeys({
97
- components,
98
- context
99
- }));
100
- await time('buildTypes', ()=>buildTypes({
101
- components,
102
- context
103
- }));
104
- await time('buildImports', ()=>buildImports({
105
- components,
106
- context
107
- }));
108
- await time('cleanBuildDirectory', ()=>cleanBuildDirectory({
109
- context
110
- }));
111
- await time('writeApp', ()=>writeApp({
112
- components,
113
- context
114
- }));
115
- await time('writeAuth', ()=>writeAuth({
116
- components,
117
- context
118
- }));
119
- await time('writeConnections', ()=>writeConnections({
120
- components,
121
- context
122
- }));
123
- await time('writeApi', ()=>writeApi({
124
- components,
125
- context
126
- }));
127
- await time('writeRequests', ()=>writeRequests({
128
- components,
129
- context
130
- }));
131
- await time('writePages', ()=>writePages({
132
- components,
133
- context
134
- }));
135
- await time('writeConfig', ()=>writeConfig({
136
- components,
137
- context
138
- }));
139
- await time('writeGlobal', ()=>writeGlobal({
140
- components,
141
- context
142
- }));
143
- await time('writeMaps', ()=>writeMaps({
144
- components,
145
- context
146
- }));
147
- await time('writeMenus', ()=>writeMenus({
148
- components,
149
- context
150
- }));
151
- await time('writeTypes', ()=>writeTypes({
152
- components,
153
- context
154
- }));
155
- await time('writePluginImports', ()=>writePluginImports({
156
- components,
157
- context
158
- }));
159
- await time('writeJs', ()=>writeJs({
160
- components,
161
- context
162
- }));
163
- await time('updateServerPackageJson', ()=>updateServerPackageJson({
164
- components,
165
- context
166
- }));
167
- await time('copyPublicFolder', ()=>copyPublicFolder({
168
- components,
169
- context
170
- }));
171
- printSummary();
51
+ const components = await buildRefs({
52
+ context
53
+ });
54
+ testSchema({
55
+ components,
56
+ context
57
+ });
58
+ buildApp({
59
+ components,
60
+ context
61
+ });
62
+ buildLogger({
63
+ components,
64
+ context
65
+ });
66
+ validateConfig({
67
+ components,
68
+ context
69
+ });
70
+ addDefaultPages({
71
+ components,
72
+ context
73
+ });
74
+ addKeys({
75
+ components,
76
+ context
77
+ });
78
+ buildAuth({
79
+ components,
80
+ context
81
+ });
82
+ buildConnections({
83
+ components,
84
+ context
85
+ });
86
+ buildApi({
87
+ components,
88
+ context
89
+ });
90
+ buildPages({
91
+ components,
92
+ context
93
+ });
94
+ buildMenu({
95
+ components,
96
+ context
97
+ });
98
+ buildJs({
99
+ components,
100
+ context
101
+ });
102
+ buildTypes({
103
+ components,
104
+ context
105
+ });
106
+ buildImports({
107
+ components,
108
+ context
109
+ });
110
+ await cleanBuildDirectory({
111
+ context
112
+ });
113
+ await writeApp({
114
+ components,
115
+ context
116
+ });
117
+ await writeAuth({
118
+ components,
119
+ context
120
+ });
121
+ await writeConnections({
122
+ components,
123
+ context
124
+ });
125
+ await writeApi({
126
+ components,
127
+ context
128
+ });
129
+ await writeRequests({
130
+ components,
131
+ context
132
+ });
133
+ await writePages({
134
+ components,
135
+ context
136
+ });
137
+ await writeConfig({
138
+ components,
139
+ context
140
+ });
141
+ await writeGlobal({
142
+ components,
143
+ context
144
+ });
145
+ await writeLogger({
146
+ components,
147
+ context
148
+ });
149
+ await writeMaps({
150
+ components,
151
+ context
152
+ });
153
+ await writeMenus({
154
+ components,
155
+ context
156
+ });
157
+ await writeTypes({
158
+ components,
159
+ context
160
+ });
161
+ await writePluginImports({
162
+ components,
163
+ context
164
+ });
165
+ await writeJs({
166
+ components,
167
+ context
168
+ });
169
+ await updateServerPackageJson({
170
+ components,
171
+ context
172
+ });
173
+ await copyPublicFolder({
174
+ components,
175
+ context
176
+ });
172
177
  }
173
178
  export { createPluginTypesMap };
174
179
  export default build;
@@ -967,6 +967,81 @@ export default {
967
967
  errorMessage: {
968
968
  type: 'App "pages" should be an array.'
969
969
  }
970
+ },
971
+ logger: {
972
+ type: 'object',
973
+ additionalProperties: false,
974
+ errorMessage: {
975
+ type: 'App "logger" should be an object.'
976
+ },
977
+ properties: {
978
+ sentry: {
979
+ type: 'object',
980
+ additionalProperties: false,
981
+ errorMessage: {
982
+ type: 'App "logger.sentry" should be an object.'
983
+ },
984
+ properties: {
985
+ client: {
986
+ type: 'boolean',
987
+ errorMessage: {
988
+ type: 'App "logger.sentry.client" should be a boolean.'
989
+ }
990
+ },
991
+ server: {
992
+ type: 'boolean',
993
+ errorMessage: {
994
+ type: 'App "logger.sentry.server" should be a boolean.'
995
+ }
996
+ },
997
+ tracesSampleRate: {
998
+ type: 'number',
999
+ minimum: 0,
1000
+ maximum: 1,
1001
+ errorMessage: {
1002
+ type: 'App "logger.sentry.tracesSampleRate" should be a number between 0 and 1.'
1003
+ }
1004
+ },
1005
+ replaysSessionSampleRate: {
1006
+ type: 'number',
1007
+ minimum: 0,
1008
+ maximum: 1,
1009
+ errorMessage: {
1010
+ type: 'App "logger.sentry.replaysSessionSampleRate" should be a number between 0 and 1.'
1011
+ }
1012
+ },
1013
+ replaysOnErrorSampleRate: {
1014
+ type: 'number',
1015
+ minimum: 0,
1016
+ maximum: 1,
1017
+ errorMessage: {
1018
+ type: 'App "logger.sentry.replaysOnErrorSampleRate" should be a number between 0 and 1.'
1019
+ }
1020
+ },
1021
+ feedback: {
1022
+ type: 'boolean',
1023
+ errorMessage: {
1024
+ type: 'App "logger.sentry.feedback" should be a boolean.'
1025
+ }
1026
+ },
1027
+ environment: {
1028
+ type: 'string',
1029
+ errorMessage: {
1030
+ type: 'App "logger.sentry.environment" should be a string.'
1031
+ }
1032
+ },
1033
+ userFields: {
1034
+ type: 'array',
1035
+ items: {
1036
+ type: 'string'
1037
+ },
1038
+ errorMessage: {
1039
+ type: 'App "logger.sentry.userFields" should be an array of strings.'
1040
+ }
1041
+ }
1042
+ }
1043
+ }
1044
+ }
970
1045
  }
971
1046
  },
972
1047
  errorMessage: {
@@ -47,7 +47,8 @@ function testContext({ writeBuildArtifact, configDirectory, readConfigFile, logg
47
47
  readConfigFile: readConfigFile || (()=>{}),
48
48
  refMap: {},
49
49
  keyMap: {},
50
- jsMap: {}
50
+ jsMap: {},
51
+ connectionIds: new Set()
51
52
  };
52
53
  context.logger = {
53
54
  ...defaultLogger,
@@ -13,18 +13,31 @@
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  */ import { type } from '@lowdefy/helpers';
16
- function countOperators(obj, { counter }) {
17
- function getOperatorsReviver(_, value) {
18
- if (type.isObject(value) && Object.keys(value).length === 1) {
19
- const key = Object.keys(value)[0];
20
- const [op] = key.split('.');
21
- const operator = op.replace(/^(_+)/gm, '_');
22
- if (operator.length > 1 && operator[0] === '_') {
23
- counter.increment(operator);
24
- }
16
+ function walkAndCount(value, counter, parentConfigKey) {
17
+ if (type.isArray(value)) {
18
+ value.forEach((item)=>walkAndCount(item, counter, parentConfigKey));
19
+ return;
20
+ }
21
+ if (!type.isObject(value)) {
22
+ return;
23
+ }
24
+ const configKey = value['~k'] || parentConfigKey;
25
+ const keys = Object.keys(value);
26
+ // Check if this object is an operator (single key starting with _)
27
+ if (keys.length === 1) {
28
+ const key = keys[0];
29
+ const [op] = key.split('.');
30
+ const operator = op.replace(/^(_+)/gm, '_');
31
+ if (operator.length > 1 && operator[0] === '_') {
32
+ counter.increment(operator, configKey);
25
33
  }
26
- return value;
27
34
  }
28
- JSON.parse(JSON.stringify(obj), getOperatorsReviver);
35
+ // Recurse into all values
36
+ keys.forEach((key)=>{
37
+ walkAndCount(value[key], counter, configKey);
38
+ });
39
+ }
40
+ function countOperators(obj, { counter }) {
41
+ walkAndCount(obj, counter, null);
29
42
  }
30
43
  export default countOperators;
@@ -13,17 +13,38 @@
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  */ import { nunjucksFunction } from '@lowdefy/nunjucks';
16
- function createCheckDuplicateId({ message }) {
16
+ import { resolveConfigLocation } from '@lowdefy/helpers';
17
+ function createCheckDuplicateId({ message, context }) {
17
18
  const template = nunjucksFunction(message);
18
19
  const ids = new Set();
19
- function checkDuplicateId({ id, blockId, eventId, menuId, pageId }) {
20
- if (ids.has(id.toLowerCase())) throw new Error(template({
21
- id,
22
- blockId,
23
- eventId,
24
- menuId,
25
- pageId
26
- }));
20
+ function checkDuplicateId({ id, blockId, configKey, eventId, menuId, pageId }) {
21
+ if (ids.has(id.toLowerCase())) {
22
+ let errorMessage = template({
23
+ id,
24
+ blockId,
25
+ eventId,
26
+ menuId,
27
+ pageId
28
+ });
29
+ if (configKey && context) {
30
+ const location = resolveConfigLocation({
31
+ configKey,
32
+ keyMap: context.keyMap,
33
+ refMap: context.refMap,
34
+ configDirectory: context.directories.config
35
+ });
36
+ if (location) {
37
+ const source = location.source ? `${location.source} at ${location.config}` : '';
38
+ const link = location.link || '';
39
+ errorMessage = `[Config Error] ${errorMessage}\n ${source}\n ${link}`;
40
+ } else {
41
+ errorMessage = `[Config Error] ${errorMessage}`;
42
+ }
43
+ } else {
44
+ errorMessage = `[Config Error] ${errorMessage}`;
45
+ }
46
+ throw new Error(errorMessage);
47
+ }
27
48
  ids.add(id.toLowerCase());
28
49
  }
29
50
  return checkDuplicateId;
@@ -14,9 +14,14 @@
14
14
  limitations under the License.
15
15
  */ function createCounter() {
16
16
  const counts = new Map();
17
- function increment(key) {
17
+ const locations = new Map();
18
+ function increment(key, configKey) {
18
19
  const count = counts.get(key) || 0;
19
20
  counts.set(key, count + 1);
21
+ // Store first occurrence location for error reporting
22
+ if (configKey && !locations.has(key)) {
23
+ locations.set(key, configKey);
24
+ }
20
25
  }
21
26
  function getCount(key) {
22
27
  return counts.get(key) || 0;
@@ -24,10 +29,18 @@
24
29
  function getCounts() {
25
30
  return Object.fromEntries(counts);
26
31
  }
32
+ function getLocation(key) {
33
+ return locations.get(key) || null;
34
+ }
35
+ function getLocations() {
36
+ return Object.fromEntries(locations);
37
+ }
27
38
  return {
28
39
  increment,
29
40
  getCount,
30
- getCounts
41
+ getCounts,
42
+ getLocation,
43
+ getLocations
31
44
  };
32
45
  }
33
46
  export default createCounter;
@@ -0,0 +1,36 @@
1
+ /*
2
+ Copyright 2020-2024 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ import { type } from '@lowdefy/helpers';
16
+ /**
17
+ * Extracts the top-level key from an operator reference value.
18
+ *
19
+ * Handles both string and object forms of operator references:
20
+ * - String: "_state: 'user.name'" -> 'user'
21
+ * - Object: "_state: { key: 'user.name' }" -> 'user'
22
+ * - Object: "_state: { path: 'user[0].name' }" -> 'user'
23
+ *
24
+ * @param {Object} params
25
+ * @param {string|Object} params.operatorValue - The value of the operator (e.g., obj._state)
26
+ * @returns {string|null} The top-level key, or null if not extractable
27
+ */ function extractOperatorKey({ operatorValue }) {
28
+ const value = type.isString(operatorValue) ? operatorValue : type.isObject(operatorValue) ? operatorValue.key || operatorValue.path : null;
29
+ if (!value) {
30
+ return null;
31
+ }
32
+ // Extract first segment before any '.' or '['
33
+ const topLevelKey = value.split(/[.[]/)[0];
34
+ return topLevelKey || null;
35
+ }
36
+ export default extractOperatorKey;
@@ -0,0 +1,53 @@
1
+ /*
2
+ Copyright 2020-2024 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ function levenshteinDistance(a, b) {
16
+ const matrix = [];
17
+ for(let i = 0; i <= b.length; i++){
18
+ matrix[i] = [
19
+ i
20
+ ];
21
+ }
22
+ for(let j = 0; j <= a.length; j++){
23
+ matrix[0][j] = j;
24
+ }
25
+ for(let i = 1; i <= b.length; i++){
26
+ for(let j = 1; j <= a.length; j++){
27
+ if (b[i - 1] === a[j - 1]) {
28
+ matrix[i][j] = matrix[i - 1][j - 1];
29
+ } else {
30
+ matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j] + 1);
31
+ }
32
+ }
33
+ }
34
+ return matrix[b.length][a.length];
35
+ }
36
+ function findSimilarString({ input, candidates, maxDistance = 3 }) {
37
+ if (!input || !candidates || candidates.length === 0) {
38
+ return null;
39
+ }
40
+ const inputLower = input.toLowerCase();
41
+ let bestMatch = null;
42
+ let bestDistance = Infinity;
43
+ for (const candidate of candidates){
44
+ const candidateLower = candidate.toLowerCase();
45
+ const distance = levenshteinDistance(inputLower, candidateLower);
46
+ if (distance < bestDistance && distance <= maxDistance) {
47
+ bestDistance = distance;
48
+ bestMatch = candidate;
49
+ }
50
+ }
51
+ return bestMatch;
52
+ }
53
+ export default findSimilarString;
@@ -0,0 +1,24 @@
1
+ /*
2
+ Copyright 2020-2024 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ import formatConfigMessage from './formatConfigMessage.js';
16
+ function formatConfigError({ message, configKey, context }) {
17
+ return formatConfigMessage({
18
+ prefix: '[Config Error]',
19
+ message,
20
+ configKey,
21
+ context
22
+ });
23
+ }
24
+ export default formatConfigError;
@@ -0,0 +1,33 @@
1
+ /*
2
+ Copyright 2020-2024 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ import { resolveConfigLocation } from '@lowdefy/helpers';
16
+ function formatConfigMessage({ prefix, message, configKey, context }) {
17
+ if (!configKey || !context) {
18
+ return `${prefix} ${message}`;
19
+ }
20
+ const location = resolveConfigLocation({
21
+ configKey,
22
+ keyMap: context.keyMap,
23
+ refMap: context.refMap,
24
+ configDirectory: context.directories.config
25
+ });
26
+ if (!location) {
27
+ return `${prefix} ${message}`;
28
+ }
29
+ const source = location.source ? `${location.source} at ${location.config}` : '';
30
+ const link = location.link || '';
31
+ return `${prefix} ${message}\n ${source}\n ${link}`;
32
+ }
33
+ export default formatConfigMessage;