@lowdefy/build 0.0.0-experimental-20260114142524 → 0.0.0-experimental-20260122074446
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/dist/build/addKeys.js +31 -18
- package/dist/build/buildApi/validateStepReferences.js +3 -4
- package/dist/build/buildAuth/buildAuth.js +2 -1
- package/dist/build/buildAuth/buildAuthPlugins.js +13 -13
- package/dist/build/buildAuth/validateAuthConfig.js +40 -8
- package/dist/build/buildAuth/validateMutualExclusivity.js +7 -7
- package/dist/build/buildConnections.js +20 -39
- package/dist/build/buildMenu.js +9 -14
- package/dist/build/buildPages/buildBlock/buildEvents.js +13 -13
- package/dist/build/buildPages/buildBlock/buildRequests.js +15 -15
- package/dist/build/buildPages/buildBlock/validateBlock.js +13 -13
- package/dist/build/buildPages/buildPage.js +5 -5
- package/dist/build/buildPages/validateLinkReferences.js +8 -9
- package/dist/build/buildPages/validatePayloadReferences.js +3 -4
- package/dist/build/buildPages/validateRequestReferences.js +7 -8
- package/dist/build/buildPages/validateStateReferences.js +3 -4
- package/dist/build/buildRefs/buildRefs.js +8 -0
- package/dist/build/buildRefs/evaluateBuildOperators.js +11 -1
- package/dist/build/buildRefs/evaluateStaticOperators.js +54 -0
- package/dist/build/buildRefs/getConfigFile.js +18 -13
- package/dist/build/buildRefs/getRefContent.js +15 -5
- package/dist/build/buildRefs/makeRefDefinition.js +1 -1
- package/dist/build/buildRefs/parseRefContent.js +32 -2
- package/dist/build/buildRefs/recursiveBuild.js +9 -7
- package/dist/build/buildRefs/runRefResolver.js +13 -2
- package/dist/build/buildTypes.js +9 -0
- package/dist/build/collectDynamicIdentifiers.js +35 -0
- package/dist/{utils/formatConfigError.js → build/collectTypeNames.js} +20 -8
- package/dist/build/formatBuildError.js +1 -1
- package/dist/build/testSchema.js +45 -6
- package/dist/build/validateOperatorsDynamic.js +28 -0
- package/dist/build/writeRequests.js +3 -3
- package/dist/createContext.js +42 -1
- package/dist/defaultTypesMap.js +447 -447
- package/dist/index.js +43 -4
- package/dist/lowdefySchema.js +60 -0
- package/dist/test-utils/parseTestYaml.js +110 -0
- package/dist/test-utils/runBuild.js +270 -0
- package/dist/test-utils/runBuildForSnapshots.js +698 -0
- package/dist/{test → test-utils}/testContext.js +15 -1
- package/dist/utils/collectConfigError.js +6 -6
- package/dist/utils/countOperators.js +5 -3
- package/dist/utils/createCheckDuplicateId.js +1 -1
- package/dist/utils/findConfigKey.js +37 -0
- package/dist/utils/makeId.js +12 -7
- package/dist/utils/tryBuildStep.js +12 -5
- package/package.json +39 -39
- package/dist/utils/formatConfigMessage.js +0 -33
- package/dist/utils/formatConfigWarning.js +0 -24
- package/dist/utils/formatErrorMessage.js +0 -56
- /package/dist/{test → test-utils}/buildRefs/testBuildRefsAsyncFunction.js +0 -0
- /package/dist/{test → test-utils}/buildRefs/testBuildRefsErrorResolver.js +0 -0
- /package/dist/{test → test-utils}/buildRefs/testBuildRefsNullResolver.js +0 -0
- /package/dist/{test → test-utils}/buildRefs/testBuildRefsParsingResolver.js +0 -0
- /package/dist/{test → test-utils}/buildRefs/testBuildRefsResolver.js +0 -0
- /package/dist/{test → test-utils}/buildRefs/testBuildRefsTransform.js +0 -0
- /package/dist/{test → test-utils}/buildRefs/testBuildRefsTransformIdentity.js +0 -0
package/dist/index.js
CHANGED
|
@@ -12,8 +12,10 @@
|
|
|
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
|
|
15
|
+
*/ import { ConfigError } from '@lowdefy/node-utils';
|
|
16
|
+
import createContext from './createContext.js';
|
|
16
17
|
import createPluginTypesMap from './utils/createPluginTypesMap.js';
|
|
18
|
+
import makeId from './utils/makeId.js';
|
|
17
19
|
import tryBuildStep from './utils/tryBuildStep.js';
|
|
18
20
|
import addDefaultPages from './build/addDefaultPages/addDefaultPages.js';
|
|
19
21
|
import addKeys from './build/addKeys.js';
|
|
@@ -48,15 +50,44 @@ import writePluginImports from './build/writePluginImports/writePluginImports.js
|
|
|
48
50
|
import writeRequests from './build/writeRequests.js';
|
|
49
51
|
import writeTypes from './build/writeTypes.js';
|
|
50
52
|
async function build(options) {
|
|
53
|
+
// Reset makeId counter for each build (dev server may run multiple builds)
|
|
54
|
+
makeId.reset();
|
|
51
55
|
const context = createContext(options);
|
|
52
|
-
|
|
56
|
+
let components;
|
|
57
|
+
try {
|
|
58
|
+
components = await buildRefs({
|
|
59
|
+
context
|
|
60
|
+
});
|
|
61
|
+
} catch (err) {
|
|
62
|
+
// Handle ConfigError from buildRefs (e.g., missing _ref files)
|
|
63
|
+
if (err instanceof ConfigError) {
|
|
64
|
+
context.logger.error(err.message);
|
|
65
|
+
const error = new Error('Build failed with 1 error(s). See above for details.');
|
|
66
|
+
error.isFormatted = true;
|
|
67
|
+
error.hideStack = true;
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
throw err;
|
|
71
|
+
}
|
|
72
|
+
// Build steps - collect all errors before stopping
|
|
73
|
+
// addKeys runs first so testSchema has ~k markers for error location info
|
|
74
|
+
tryBuildStep(addKeys, 'addKeys', {
|
|
75
|
+
components,
|
|
53
76
|
context
|
|
54
77
|
});
|
|
55
|
-
// Build steps - collect all errors before stopping
|
|
56
78
|
tryBuildStep(testSchema, 'testSchema', {
|
|
57
79
|
components,
|
|
58
80
|
context
|
|
59
81
|
});
|
|
82
|
+
// Schema errors mean structurally invalid data - stop before processing further
|
|
83
|
+
if (context.errors.length > 0) {
|
|
84
|
+
// Log all errors together before summary to ensure proper ordering
|
|
85
|
+
context.errors.forEach((errorMsg)=>context.logger.error(errorMsg));
|
|
86
|
+
const error = new Error(`Build failed with ${context.errors.length} error(s).`);
|
|
87
|
+
error.isFormatted = true;
|
|
88
|
+
error.hideStack = true;
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
60
91
|
tryBuildStep(buildApp, 'buildApp', {
|
|
61
92
|
components,
|
|
62
93
|
context
|
|
@@ -73,6 +104,7 @@ async function build(options) {
|
|
|
73
104
|
components,
|
|
74
105
|
context
|
|
75
106
|
});
|
|
107
|
+
// addKeys runs again to add keys to any new objects created by earlier build steps
|
|
76
108
|
tryBuildStep(addKeys, 'addKeys', {
|
|
77
109
|
components,
|
|
78
110
|
context
|
|
@@ -109,9 +141,16 @@ async function build(options) {
|
|
|
109
141
|
components,
|
|
110
142
|
context
|
|
111
143
|
});
|
|
144
|
+
// Final addKeys pass to ensure all objects (including those created by build steps) have ~k
|
|
145
|
+
tryBuildStep(addKeys, 'addKeys', {
|
|
146
|
+
components,
|
|
147
|
+
context
|
|
148
|
+
});
|
|
112
149
|
// Check if there are any collected errors before writing
|
|
113
150
|
if (context.errors.length > 0) {
|
|
114
|
-
|
|
151
|
+
// Log all errors together before summary to ensure proper ordering
|
|
152
|
+
context.errors.forEach((errorMsg)=>context.logger.error(errorMsg));
|
|
153
|
+
const error = new Error(`Build failed with ${context.errors.length} error(s).`);
|
|
115
154
|
// Mark this error as already formatted so stack trace isn't shown
|
|
116
155
|
error.isFormatted = true;
|
|
117
156
|
error.hideStack = true;
|
package/dist/lowdefySchema.js
CHANGED
|
@@ -12,6 +12,9 @@ export default {
|
|
|
12
12
|
'type'
|
|
13
13
|
],
|
|
14
14
|
properties: {
|
|
15
|
+
'~ignoreBuildCheck': {},
|
|
16
|
+
'~r': {},
|
|
17
|
+
'~l': {},
|
|
15
18
|
async: {
|
|
16
19
|
type: 'boolean',
|
|
17
20
|
errorMessage: {
|
|
@@ -46,6 +49,9 @@ export default {
|
|
|
46
49
|
type: 'object',
|
|
47
50
|
additionalProperties: false,
|
|
48
51
|
properties: {
|
|
52
|
+
'~ignoreBuildCheck': {},
|
|
53
|
+
'~r': {},
|
|
54
|
+
'~l': {},
|
|
49
55
|
html: {
|
|
50
56
|
type: 'object',
|
|
51
57
|
errorMessage: {
|
|
@@ -75,6 +81,9 @@ export default {
|
|
|
75
81
|
type: 'App "auth" should be an object.'
|
|
76
82
|
},
|
|
77
83
|
properties: {
|
|
84
|
+
'~ignoreBuildCheck': {},
|
|
85
|
+
'~r': {},
|
|
86
|
+
'~l': {},
|
|
78
87
|
advanced: {
|
|
79
88
|
type: 'object',
|
|
80
89
|
properties: {
|
|
@@ -121,6 +130,9 @@ export default {
|
|
|
121
130
|
type: 'App "config.auth.api" should be an object.'
|
|
122
131
|
},
|
|
123
132
|
properties: {
|
|
133
|
+
'~ignoreBuildCheck': {},
|
|
134
|
+
'~r': {},
|
|
135
|
+
'~l': {},
|
|
124
136
|
protected: {
|
|
125
137
|
type: [
|
|
126
138
|
'array',
|
|
@@ -176,6 +188,9 @@ export default {
|
|
|
176
188
|
type: 'object',
|
|
177
189
|
additionalProperties: false,
|
|
178
190
|
properties: {
|
|
191
|
+
'~ignoreBuildCheck': {},
|
|
192
|
+
'~r': {},
|
|
193
|
+
'~l': {},
|
|
179
194
|
signIn: {
|
|
180
195
|
type: 'string',
|
|
181
196
|
default: '/auth/signin'
|
|
@@ -282,6 +297,9 @@ export default {
|
|
|
282
297
|
type: 'App "config.auth.pages" should be an object.'
|
|
283
298
|
},
|
|
284
299
|
properties: {
|
|
300
|
+
'~ignoreBuildCheck': {},
|
|
301
|
+
'~r': {},
|
|
302
|
+
'~l': {},
|
|
285
303
|
protected: {
|
|
286
304
|
type: [
|
|
287
305
|
'array',
|
|
@@ -386,6 +404,9 @@ export default {
|
|
|
386
404
|
'type'
|
|
387
405
|
],
|
|
388
406
|
properties: {
|
|
407
|
+
'~ignoreBuildCheck': {},
|
|
408
|
+
'~r': {},
|
|
409
|
+
'~l': {},
|
|
389
410
|
id: {
|
|
390
411
|
type: 'string',
|
|
391
412
|
errorMessage: {
|
|
@@ -473,6 +494,9 @@ export default {
|
|
|
473
494
|
type: 'object',
|
|
474
495
|
additionalProperties: false,
|
|
475
496
|
properties: {
|
|
497
|
+
'~ignoreBuildCheck': {},
|
|
498
|
+
'~r': {},
|
|
499
|
+
'~l': {},
|
|
476
500
|
try: {
|
|
477
501
|
type: 'array',
|
|
478
502
|
items: {
|
|
@@ -489,6 +513,9 @@ export default {
|
|
|
489
513
|
type: 'object',
|
|
490
514
|
additionalProperties: false,
|
|
491
515
|
properties: {
|
|
516
|
+
'~ignoreBuildCheck': {},
|
|
517
|
+
'~r': {},
|
|
518
|
+
'~l': {},
|
|
492
519
|
immediate: {
|
|
493
520
|
type: 'boolean',
|
|
494
521
|
errorMessage: {
|
|
@@ -554,6 +581,9 @@ export default {
|
|
|
554
581
|
'type'
|
|
555
582
|
],
|
|
556
583
|
properties: {
|
|
584
|
+
'~ignoreBuildCheck': {},
|
|
585
|
+
'~r': {},
|
|
586
|
+
'~l': {},
|
|
557
587
|
id: {
|
|
558
588
|
type: 'string',
|
|
559
589
|
errorMessage: {
|
|
@@ -592,6 +622,9 @@ export default {
|
|
|
592
622
|
'type'
|
|
593
623
|
],
|
|
594
624
|
properties: {
|
|
625
|
+
'~ignoreBuildCheck': {},
|
|
626
|
+
'~r': {},
|
|
627
|
+
'~l': {},
|
|
595
628
|
id: {
|
|
596
629
|
type: 'string',
|
|
597
630
|
errorMessage: {
|
|
@@ -626,6 +659,9 @@ export default {
|
|
|
626
659
|
'id'
|
|
627
660
|
],
|
|
628
661
|
properties: {
|
|
662
|
+
'~ignoreBuildCheck': {},
|
|
663
|
+
'~r': {},
|
|
664
|
+
'~l': {},
|
|
629
665
|
id: {
|
|
630
666
|
type: 'string',
|
|
631
667
|
errorMessage: {
|
|
@@ -663,6 +699,9 @@ export default {
|
|
|
663
699
|
'type'
|
|
664
700
|
],
|
|
665
701
|
properties: {
|
|
702
|
+
'~ignoreBuildCheck': {},
|
|
703
|
+
'~r': {},
|
|
704
|
+
'~l': {},
|
|
666
705
|
id: {
|
|
667
706
|
type: 'string',
|
|
668
707
|
errorMessage: {
|
|
@@ -717,6 +756,9 @@ export default {
|
|
|
717
756
|
'type'
|
|
718
757
|
],
|
|
719
758
|
properties: {
|
|
759
|
+
'~ignoreBuildCheck': {},
|
|
760
|
+
'~r': {},
|
|
761
|
+
'~l': {},
|
|
720
762
|
id: {
|
|
721
763
|
type: 'string',
|
|
722
764
|
errorMessage: {
|
|
@@ -776,6 +818,9 @@ export default {
|
|
|
776
818
|
'version'
|
|
777
819
|
],
|
|
778
820
|
properties: {
|
|
821
|
+
'~ignoreBuildCheck': {},
|
|
822
|
+
'~r': {},
|
|
823
|
+
'~l': {},
|
|
779
824
|
name: {
|
|
780
825
|
type: 'string',
|
|
781
826
|
errorMessage: {
|
|
@@ -812,6 +857,9 @@ export default {
|
|
|
812
857
|
'connectionId'
|
|
813
858
|
],
|
|
814
859
|
properties: {
|
|
860
|
+
'~ignoreBuildCheck': {},
|
|
861
|
+
'~r': {},
|
|
862
|
+
'~l': {},
|
|
815
863
|
id: {
|
|
816
864
|
type: 'string',
|
|
817
865
|
errorMessage: {
|
|
@@ -858,6 +906,9 @@ export default {
|
|
|
858
906
|
'lowdefy'
|
|
859
907
|
],
|
|
860
908
|
properties: {
|
|
909
|
+
'~ignoreBuildCheck': {},
|
|
910
|
+
'~r': {},
|
|
911
|
+
'~l': {},
|
|
861
912
|
name: {
|
|
862
913
|
type: 'string',
|
|
863
914
|
errorMessage: {
|
|
@@ -901,6 +952,9 @@ export default {
|
|
|
901
952
|
},
|
|
902
953
|
additionalProperties: false,
|
|
903
954
|
properties: {
|
|
955
|
+
'~ignoreBuildCheck': {},
|
|
956
|
+
'~r': {},
|
|
957
|
+
'~l': {},
|
|
904
958
|
basePath: {
|
|
905
959
|
type: 'string',
|
|
906
960
|
description: 'App base path to apply to all routes. Base path must start with "/".',
|
|
@@ -975,6 +1029,9 @@ export default {
|
|
|
975
1029
|
type: 'App "logger" should be an object.'
|
|
976
1030
|
},
|
|
977
1031
|
properties: {
|
|
1032
|
+
'~ignoreBuildCheck': {},
|
|
1033
|
+
'~r': {},
|
|
1034
|
+
'~l': {},
|
|
978
1035
|
sentry: {
|
|
979
1036
|
type: 'object',
|
|
980
1037
|
additionalProperties: false,
|
|
@@ -982,6 +1039,9 @@ export default {
|
|
|
982
1039
|
type: 'App "logger.sentry" should be an object.'
|
|
983
1040
|
},
|
|
984
1041
|
properties: {
|
|
1042
|
+
'~ignoreBuildCheck': {},
|
|
1043
|
+
'~r': {},
|
|
1044
|
+
'~l': {},
|
|
985
1045
|
client: {
|
|
986
1046
|
type: 'boolean',
|
|
987
1047
|
errorMessage: {
|
|
@@ -0,0 +1,110 @@
|
|
|
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
|
+
import YAML, { isMap, isSeq, isPair, isScalar } from 'yaml';
|
|
17
|
+
function getLineNumber(content, offset) {
|
|
18
|
+
if (offset == null || offset < 0) return null;
|
|
19
|
+
return content.substring(0, offset).split('\n').length;
|
|
20
|
+
}
|
|
21
|
+
function addLineNumbersAndRefs(node, content, refCounter) {
|
|
22
|
+
if (isMap(node)) {
|
|
23
|
+
const obj = {};
|
|
24
|
+
const refId = String(refCounter.next++);
|
|
25
|
+
obj['~r'] = refId;
|
|
26
|
+
if (node.range) {
|
|
27
|
+
Object.defineProperty(obj, '~l', {
|
|
28
|
+
value: getLineNumber(content, node.range[0]),
|
|
29
|
+
enumerable: false,
|
|
30
|
+
writable: true,
|
|
31
|
+
configurable: true
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
for (const pair of node.items){
|
|
35
|
+
if (isPair(pair) && isScalar(pair.key)) {
|
|
36
|
+
const key = pair.key.value;
|
|
37
|
+
const value = pair.value;
|
|
38
|
+
const keyLineNumber = pair.key.range ? getLineNumber(content, pair.key.range[0]) : null;
|
|
39
|
+
if (isMap(value)) {
|
|
40
|
+
const mapResult = addLineNumbersAndRefs(value, content, refCounter);
|
|
41
|
+
if (keyLineNumber) {
|
|
42
|
+
Object.defineProperty(mapResult, '~l', {
|
|
43
|
+
value: keyLineNumber,
|
|
44
|
+
enumerable: false,
|
|
45
|
+
writable: true,
|
|
46
|
+
configurable: true
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
obj[key] = mapResult;
|
|
50
|
+
} else if (isSeq(value)) {
|
|
51
|
+
// Don't add ~l to arrays - only objects need line numbers for error reporting
|
|
52
|
+
obj[key] = addLineNumbersAndRefs(value, content, refCounter);
|
|
53
|
+
} else if (isScalar(value)) {
|
|
54
|
+
obj[key] = value.value;
|
|
55
|
+
} else {
|
|
56
|
+
obj[key] = value?.toJSON?.() ?? value;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return obj;
|
|
61
|
+
}
|
|
62
|
+
if (isSeq(node)) {
|
|
63
|
+
const arr = [];
|
|
64
|
+
// Note: We don't add ~l to arrays to keep serialized output simpler.
|
|
65
|
+
// Line numbers on arrays aren't needed for error reporting - objects are the error sources.
|
|
66
|
+
for (const item of node.items){
|
|
67
|
+
if (isMap(item)) {
|
|
68
|
+
arr.push(addLineNumbersAndRefs(item, content, refCounter));
|
|
69
|
+
} else if (isSeq(item)) {
|
|
70
|
+
arr.push(addLineNumbersAndRefs(item, content, refCounter));
|
|
71
|
+
} else if (isScalar(item)) {
|
|
72
|
+
arr.push(item.value);
|
|
73
|
+
} else {
|
|
74
|
+
arr.push(item?.toJSON?.() ?? item);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return arr;
|
|
78
|
+
}
|
|
79
|
+
if (isScalar(node)) {
|
|
80
|
+
return node.value;
|
|
81
|
+
}
|
|
82
|
+
return node?.toJSON?.() ?? node;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Parse YAML string for testing, adding ~l (line numbers) and ~r (ref IDs)
|
|
86
|
+
* to simulate real buildRefs output.
|
|
87
|
+
*
|
|
88
|
+
* @param {string} yamlContent - YAML string to parse (use template literals for multiline)
|
|
89
|
+
* @returns {object} Parsed object with ~l and ~r properties
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* const components = parseTestYaml(`
|
|
93
|
+
* pages:
|
|
94
|
+
* - id: home
|
|
95
|
+
* type: Box
|
|
96
|
+
* blocks:
|
|
97
|
+
* - id: title
|
|
98
|
+
* type: Title
|
|
99
|
+
* `);
|
|
100
|
+
*/ function parseTestYaml(yamlContent) {
|
|
101
|
+
const doc = YAML.parseDocument(yamlContent);
|
|
102
|
+
if (doc.errors && doc.errors.length > 0) {
|
|
103
|
+
throw new Error(doc.errors[0].message);
|
|
104
|
+
}
|
|
105
|
+
const refCounter = {
|
|
106
|
+
next: 1
|
|
107
|
+
};
|
|
108
|
+
return addLineNumbersAndRefs(doc.contents, yamlContent, refCounter);
|
|
109
|
+
}
|
|
110
|
+
export default parseTestYaml;
|
|
@@ -0,0 +1,270 @@
|
|
|
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 { jest } from '@jest/globals';
|
|
16
|
+
import path from 'path';
|
|
17
|
+
/**
|
|
18
|
+
* Custom types map for testing - includes common types used in fixtures.
|
|
19
|
+
* Contains all basic blocks, loaders, common actions, operators, and connections.
|
|
20
|
+
*/ const testTypesMap = {
|
|
21
|
+
actions: {
|
|
22
|
+
Link: {
|
|
23
|
+
package: '@lowdefy/actions-core'
|
|
24
|
+
},
|
|
25
|
+
SetState: {
|
|
26
|
+
package: '@lowdefy/actions-core'
|
|
27
|
+
},
|
|
28
|
+
Request: {
|
|
29
|
+
package: '@lowdefy/actions-core'
|
|
30
|
+
},
|
|
31
|
+
Reset: {
|
|
32
|
+
package: '@lowdefy/actions-core'
|
|
33
|
+
},
|
|
34
|
+
Throw: {
|
|
35
|
+
package: '@lowdefy/actions-core'
|
|
36
|
+
},
|
|
37
|
+
Log: {
|
|
38
|
+
package: '@lowdefy/actions-core'
|
|
39
|
+
},
|
|
40
|
+
Return: {
|
|
41
|
+
package: '@lowdefy/api'
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
blocks: {
|
|
45
|
+
Anchor: {
|
|
46
|
+
package: '@lowdefy/blocks-basic'
|
|
47
|
+
},
|
|
48
|
+
Box: {
|
|
49
|
+
package: '@lowdefy/blocks-basic'
|
|
50
|
+
},
|
|
51
|
+
Button: {
|
|
52
|
+
package: '@lowdefy/blocks-basic'
|
|
53
|
+
},
|
|
54
|
+
DangerousHtml: {
|
|
55
|
+
package: '@lowdefy/blocks-basic'
|
|
56
|
+
},
|
|
57
|
+
Html: {
|
|
58
|
+
package: '@lowdefy/blocks-basic'
|
|
59
|
+
},
|
|
60
|
+
Icon: {
|
|
61
|
+
package: '@lowdefy/blocks-basic'
|
|
62
|
+
},
|
|
63
|
+
Img: {
|
|
64
|
+
package: '@lowdefy/blocks-basic'
|
|
65
|
+
},
|
|
66
|
+
List: {
|
|
67
|
+
package: '@lowdefy/blocks-basic'
|
|
68
|
+
},
|
|
69
|
+
Message: {
|
|
70
|
+
package: '@lowdefy/blocks-antd'
|
|
71
|
+
},
|
|
72
|
+
Paragraph: {
|
|
73
|
+
package: '@lowdefy/blocks-basic'
|
|
74
|
+
},
|
|
75
|
+
ProgressBar: {
|
|
76
|
+
package: '@lowdefy/blocks-loaders'
|
|
77
|
+
},
|
|
78
|
+
Result: {
|
|
79
|
+
package: '@lowdefy/blocks-antd'
|
|
80
|
+
},
|
|
81
|
+
Skeleton: {
|
|
82
|
+
package: '@lowdefy/blocks-loaders'
|
|
83
|
+
},
|
|
84
|
+
SkeletonAvatar: {
|
|
85
|
+
package: '@lowdefy/blocks-loaders'
|
|
86
|
+
},
|
|
87
|
+
SkeletonButton: {
|
|
88
|
+
package: '@lowdefy/blocks-loaders'
|
|
89
|
+
},
|
|
90
|
+
SkeletonInput: {
|
|
91
|
+
package: '@lowdefy/blocks-loaders'
|
|
92
|
+
},
|
|
93
|
+
SkeletonParagraph: {
|
|
94
|
+
package: '@lowdefy/blocks-loaders'
|
|
95
|
+
},
|
|
96
|
+
Span: {
|
|
97
|
+
package: '@lowdefy/blocks-basic'
|
|
98
|
+
},
|
|
99
|
+
Spinner: {
|
|
100
|
+
package: '@lowdefy/blocks-loaders'
|
|
101
|
+
},
|
|
102
|
+
TextInput: {
|
|
103
|
+
package: '@lowdefy/blocks-antd'
|
|
104
|
+
},
|
|
105
|
+
Throw: {
|
|
106
|
+
package: '@lowdefy/blocks-basic'
|
|
107
|
+
},
|
|
108
|
+
Title: {
|
|
109
|
+
package: '@lowdefy/blocks-basic'
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
connections: {
|
|
113
|
+
AxiosHttp: {
|
|
114
|
+
package: '@lowdefy/connection-axios-http'
|
|
115
|
+
},
|
|
116
|
+
MongoDBCollection: {
|
|
117
|
+
package: '@lowdefy/connection-mongodb'
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
requests: {
|
|
121
|
+
AxiosHttp: {
|
|
122
|
+
package: '@lowdefy/connection-axios-http'
|
|
123
|
+
},
|
|
124
|
+
MongoDBInsertOne: {
|
|
125
|
+
package: '@lowdefy/connection-mongodb'
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
auth: {
|
|
129
|
+
adapters: {},
|
|
130
|
+
callbacks: {},
|
|
131
|
+
events: {},
|
|
132
|
+
providers: {
|
|
133
|
+
GoogleProvider: {
|
|
134
|
+
package: 'next-auth'
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
operators: {
|
|
139
|
+
client: {
|
|
140
|
+
_state: {
|
|
141
|
+
package: '@lowdefy/operators-js'
|
|
142
|
+
},
|
|
143
|
+
_if: {
|
|
144
|
+
package: '@lowdefy/operators-js'
|
|
145
|
+
},
|
|
146
|
+
_eq: {
|
|
147
|
+
package: '@lowdefy/operators-js'
|
|
148
|
+
},
|
|
149
|
+
_not: {
|
|
150
|
+
package: '@lowdefy/operators-js'
|
|
151
|
+
},
|
|
152
|
+
_type: {
|
|
153
|
+
package: '@lowdefy/operators-js'
|
|
154
|
+
},
|
|
155
|
+
_payload: {
|
|
156
|
+
package: '@lowdefy/operators-js'
|
|
157
|
+
},
|
|
158
|
+
_step: {
|
|
159
|
+
package: '@lowdefy/operators-js'
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
server: {
|
|
163
|
+
_payload: {
|
|
164
|
+
package: '@lowdefy/operators-js'
|
|
165
|
+
},
|
|
166
|
+
_step: {
|
|
167
|
+
package: '@lowdefy/operators-js'
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
controls: {
|
|
172
|
+
Endpoint: {
|
|
173
|
+
package: '@lowdefy/api'
|
|
174
|
+
},
|
|
175
|
+
Log: {
|
|
176
|
+
package: '@lowdefy/api'
|
|
177
|
+
},
|
|
178
|
+
Return: {
|
|
179
|
+
package: '@lowdefy/api'
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
/**
|
|
184
|
+
* Creates a runBuild helper function for testing build errors.
|
|
185
|
+
*
|
|
186
|
+
* @param {Function} build - The build function (imported after mocking writeBuildArtifact)
|
|
187
|
+
* @param {string} fixturesDir - Absolute path to the fixtures directory
|
|
188
|
+
* @returns {Function} runBuild helper function
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* // In test file:
|
|
192
|
+
* jest.unstable_mockModule('./utils/writeBuildArtifact.js', () => ({
|
|
193
|
+
* default: () => jest.fn(),
|
|
194
|
+
* }));
|
|
195
|
+
* const { default: build } = await import('./index.js');
|
|
196
|
+
* const runBuild = createRunBuild(build, path.join(__dirname, 'build-errors'));
|
|
197
|
+
*
|
|
198
|
+
* // Then in tests:
|
|
199
|
+
* const result = await runBuild('A1-invalid-connection-type', 'prod');
|
|
200
|
+
* expect(result.errors).toContain('...');
|
|
201
|
+
*/ function createRunBuild(build, fixturesDir) {
|
|
202
|
+
/**
|
|
203
|
+
* Runs build with a specific fixture directory and stage.
|
|
204
|
+
* Returns captured errors, warnings, and the thrown error (if any).
|
|
205
|
+
*
|
|
206
|
+
* @param {string} fixtureDir - Name of the fixture directory (e.g., 'A1-invalid-connection-type')
|
|
207
|
+
* @param {string} [stage='prod'] - Build stage ('dev' or 'prod')
|
|
208
|
+
* @returns {Promise<{errors: string[], warnings: string[], thrownError: Error|null, logger: Object}>}
|
|
209
|
+
*/ return async function runBuild(fixtureDir, stage = 'prod') {
|
|
210
|
+
const configDir = path.join(fixturesDir, fixtureDir);
|
|
211
|
+
const errors = [];
|
|
212
|
+
const warnings = [];
|
|
213
|
+
const logger = {
|
|
214
|
+
info: jest.fn(),
|
|
215
|
+
log: jest.fn(),
|
|
216
|
+
warn: jest.fn((msg)=>warnings.push(msg)),
|
|
217
|
+
error: jest.fn((msg)=>errors.push(msg)),
|
|
218
|
+
succeed: jest.fn()
|
|
219
|
+
};
|
|
220
|
+
let thrownError = null;
|
|
221
|
+
try {
|
|
222
|
+
await build({
|
|
223
|
+
customTypesMap: testTypesMap,
|
|
224
|
+
directories: {
|
|
225
|
+
config: configDir,
|
|
226
|
+
build: path.join(configDir, '.lowdefy'),
|
|
227
|
+
server: path.join(configDir, '.lowdefy', 'server')
|
|
228
|
+
},
|
|
229
|
+
logger,
|
|
230
|
+
stage
|
|
231
|
+
});
|
|
232
|
+
} catch (err) {
|
|
233
|
+
thrownError = err;
|
|
234
|
+
// Extract errors embedded in the thrown message (format: "✖ [Config Error] ...")
|
|
235
|
+
// This handles the case where errors are bundled in the thrown message to avoid interleaving
|
|
236
|
+
// Each error is multi-line: message line + indented location lines
|
|
237
|
+
if (err.message) {
|
|
238
|
+
const lines = err.message.split('\n');
|
|
239
|
+
let currentError = null;
|
|
240
|
+
for (const line of lines){
|
|
241
|
+
if (line.startsWith('✖ [Config Error]')) {
|
|
242
|
+
// Start of a new error - save previous if exists
|
|
243
|
+
if (currentError !== null) {
|
|
244
|
+
errors.push(currentError);
|
|
245
|
+
}
|
|
246
|
+
currentError = line.slice(2); // Remove "✖ " prefix
|
|
247
|
+
} else if (currentError !== null && line.startsWith(' ')) {
|
|
248
|
+
// Continuation line (indented) - append to current error
|
|
249
|
+
currentError += '\n' + line;
|
|
250
|
+
} else if (currentError !== null) {
|
|
251
|
+
// Non-continuation line - save current error and reset
|
|
252
|
+
errors.push(currentError);
|
|
253
|
+
currentError = null;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
// Don't forget the last error
|
|
257
|
+
if (currentError !== null) {
|
|
258
|
+
errors.push(currentError);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return {
|
|
263
|
+
errors,
|
|
264
|
+
warnings,
|
|
265
|
+
thrownError,
|
|
266
|
+
logger
|
|
267
|
+
};
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
export { testTypesMap, createRunBuild };
|