@lowdefy/build 4.5.1 → 4.6.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.
- package/dist/build/addDefaultPages/404.js +1 -1
- package/dist/build/addDefaultPages/addDefaultPages.js +10 -4
- package/dist/build/addKeys.js +85 -29
- package/dist/build/buildApi/buildApi.js +27 -8
- package/dist/build/buildApi/buildEndpoint.js +7 -1
- package/dist/build/buildApi/buildRoutine/buildControl.js +1 -1
- package/dist/build/buildApi/buildRoutine/buildRoutine.js +1 -1
- package/dist/build/buildApi/buildRoutine/buildStep.js +1 -1
- package/dist/build/buildApi/buildRoutine/controlTypes.js +34 -11
- package/dist/build/buildApi/buildRoutine/countControl.js +1 -1
- package/dist/build/buildApi/buildRoutine/countStepTypes.js +2 -2
- package/dist/build/buildApi/buildRoutine/setStepId.js +1 -1
- package/dist/build/buildApi/buildRoutine/validateStep.js +30 -9
- package/dist/build/buildApi/validateEndpoint.js +36 -7
- package/dist/build/buildApi/validateStepReferences.js +65 -0
- package/dist/build/buildApp.js +1 -1
- package/dist/build/buildAuth/buildApiAuth.js +7 -3
- package/dist/build/buildAuth/buildAuth.js +7 -4
- package/dist/build/buildAuth/buildAuthPlugins.js +42 -13
- package/dist/build/buildAuth/buildPageAuth.js +14 -3
- package/dist/build/buildAuth/getApiRoles.js +1 -1
- package/dist/build/buildAuth/getPageRoles.js +1 -1
- package/dist/build/buildAuth/getProtectedApi.js +1 -1
- package/dist/build/buildAuth/getProtectedPages.js +1 -1
- package/dist/build/buildAuth/validateAuthConfig.js +39 -5
- package/dist/build/buildAuth/validateMutualExclusivity.js +13 -5
- package/dist/build/buildConnections.js +23 -24
- package/dist/build/buildImports/buildIconImports.js +1 -1
- package/dist/build/buildImports/buildImports.js +1 -1
- package/dist/build/buildImports/buildImportsDev.js +1 -1
- package/dist/build/buildImports/buildImportsProd.js +1 -1
- package/dist/build/buildImports/buildStyleImports.js +1 -1
- package/dist/build/buildImports/defaultIconsDev.js +1 -1
- package/dist/build/buildImports/defaultIconsProd.js +1 -1
- package/dist/build/buildJs/generateJsFile.js +1 -1
- package/dist/build/buildJs/jsMapParser.js +1 -1
- package/dist/build/buildJs/writeJs.js +1 -1
- package/dist/build/buildLogger.js +41 -0
- package/dist/build/buildMenu.js +36 -12
- package/dist/build/buildPages/buildBlock/buildBlock.js +1 -1
- package/dist/build/buildPages/buildBlock/buildEvents.js +79 -9
- package/dist/build/buildPages/buildBlock/buildRequests.js +38 -8
- package/dist/build/buildPages/buildBlock/buildSubBlocks.js +6 -2
- package/dist/build/buildPages/buildBlock/countBlockOperators.js +1 -1
- package/dist/build/buildPages/buildBlock/countBlockTypes.js +2 -2
- package/dist/build/buildPages/buildBlock/moveSkeletonBlocksToArea.js +6 -2
- package/dist/build/buildPages/buildBlock/moveSubBlocksToArea.js +6 -2
- package/dist/build/buildPages/buildBlock/setBlockId.js +1 -1
- package/dist/build/buildPages/buildBlock/validateBlock.js +25 -7
- package/dist/build/buildPages/buildPage.js +35 -6
- package/dist/build/buildPages/validateLinkReferences.js +33 -0
- package/dist/build/buildPages/validatePayloadReferences.js +59 -0
- package/dist/build/buildPages/validateRequestReferences.js +33 -0
- package/dist/build/buildPages/validateServerStateReferences.js +41 -0
- package/dist/build/buildPages/validateStateReferences.js +79 -0
- package/dist/build/buildRefs/buildRefs.js +20 -3
- package/dist/build/buildRefs/createRefReviver.js +28 -0
- package/dist/build/buildRefs/evaluateBuildOperators.js +26 -7
- package/dist/build/buildRefs/evaluateStaticOperators.js +56 -0
- package/dist/build/buildRefs/getConfigFile.js +25 -6
- package/dist/build/buildRefs/getKey.js +1 -1
- package/dist/build/buildRefs/getRefContent.js +1 -1
- package/dist/build/buildRefs/getRefPath.js +1 -1
- package/dist/build/buildRefs/getRefsFromFile.js +9 -4
- package/dist/build/buildRefs/getUserJavascriptFunction.js +18 -4
- package/dist/build/buildRefs/makeRefDefinition.js +10 -5
- package/dist/build/buildRefs/parseNunjucks.js +1 -1
- package/dist/build/buildRefs/parseRefContent.js +100 -6
- package/dist/build/buildRefs/populateRefs.js +75 -13
- package/dist/build/buildRefs/recursiveBuild.js +66 -18
- package/dist/build/buildRefs/runRefResolver.js +11 -3
- package/dist/build/buildRefs/runTransformer.js +7 -3
- package/dist/build/buildTypes.js +22 -7
- package/dist/build/cleanBuildDirectory.js +1 -1
- package/dist/build/collectDynamicIdentifiers.js +35 -0
- package/dist/build/collectTypeNames.js +36 -0
- package/dist/build/copyPublicFolder.js +1 -1
- package/dist/build/{buildJs → full}/buildJs.js +3 -3
- package/dist/build/full/buildPages.js +87 -0
- package/dist/build/{buildPages → full}/buildTestPage.js +15 -3
- package/dist/build/{updateServerPackageJson.js → full/updateServerPackageJson.js} +1 -1
- package/dist/build/{writePages.js → full/writePages.js} +1 -1
- package/dist/build/{writeRequests.js → full/writeRequests.js} +11 -3
- package/dist/build/{writeTypes.js → full/writeTypes.js} +1 -1
- package/dist/build/jit/addInstalledTypes.js +51 -0
- package/dist/build/jit/buildJsShallow.js +41 -0
- package/dist/build/jit/buildPageJit.js +252 -0
- package/dist/build/jit/buildShallowPages.js +90 -0
- package/dist/build/jit/createPageRegistry.js +80 -0
- package/dist/build/jit/detectMissingPluginPackages.js +62 -0
- package/dist/build/jit/getRefPositions.js +38 -0
- package/dist/build/jit/isPageContentPath.js +24 -0
- package/dist/build/jit/pageContentKeys.js +26 -0
- package/dist/build/jit/shallowBuild.js +245 -0
- package/dist/build/jit/stripPageContent.js +23 -0
- package/dist/build/jit/updateServerPackageJsonJit.js +33 -0
- package/dist/build/jit/validatePageTypes.js +73 -0
- package/dist/build/jit/writePageJit.js +44 -0
- package/dist/build/jit/writePageRegistry.js +23 -0
- package/dist/build/jit/writeSourcelessPages.js +23 -0
- package/dist/build/testSchema.js +45 -7
- package/dist/build/validateConfig.js +2 -2
- package/dist/build/validateOperatorsDynamic.js +28 -0
- package/dist/build/writeApi.js +1 -1
- package/dist/build/writeApp.js +1 -1
- package/dist/build/writeAuth.js +1 -1
- package/dist/build/writeConfig.js +1 -1
- package/dist/build/writeConnections.js +1 -1
- package/dist/build/writeGlobal.js +1 -1
- package/dist/build/writeLogger.js +19 -0
- package/dist/build/writeMaps.js +1 -1
- package/dist/build/writeMenus.js +1 -1
- package/dist/build/writePluginImports/generateImportFile.js +1 -1
- package/dist/build/writePluginImports/writeActionImports.js +1 -1
- package/dist/build/writePluginImports/writeActionSchemaMap.js +42 -0
- package/dist/build/writePluginImports/writeAuthImports.js +1 -1
- package/dist/build/writePluginImports/writeBlockImports.js +1 -1
- package/dist/build/writePluginImports/writeBlockSchemaMap.js +42 -0
- package/dist/build/writePluginImports/writeConnectionImports.js +1 -1
- package/dist/build/writePluginImports/writeIconImports.js +1 -1
- package/dist/build/writePluginImports/writeOperatorImports.js +1 -1
- package/dist/build/writePluginImports/writeOperatorSchemaMap.js +49 -0
- package/dist/build/writePluginImports/writePluginImports.js +16 -1
- package/dist/build/writePluginImports/writeStyleImports.js +1 -1
- package/dist/createContext.js +16 -4
- package/dist/defaultTypesMap.js +477 -455
- package/dist/index.js +188 -127
- package/dist/indexDev.js +18 -0
- package/dist/lowdefySchema.js +589 -0
- package/dist/scripts/generateDefaultTypes.js +2 -1
- package/dist/scripts/run.js +1 -1
- package/dist/{test → test-utils}/buildRefs/testBuildRefsAsyncFunction.js +1 -1
- package/dist/{test → test-utils}/buildRefs/testBuildRefsErrorResolver.js +1 -1
- package/dist/{test → test-utils}/buildRefs/testBuildRefsNullResolver.js +1 -1
- package/dist/{test → test-utils}/buildRefs/testBuildRefsParsingResolver.js +1 -1
- package/dist/{test → test-utils}/buildRefs/testBuildRefsResolver.js +1 -1
- package/dist/{test → test-utils}/buildRefs/testBuildRefsTransform.js +1 -1
- package/dist/{test → test-utils}/buildRefs/testBuildRefsTransformIdentity.js +1 -1
- package/dist/test-utils/buildRefs/testJitPageResolver.js +24 -0
- package/dist/test-utils/createTestLogger.js +36 -0
- package/dist/test-utils/parseTestYaml.js +126 -0
- package/dist/test-utils/runBuild.js +228 -0
- package/dist/test-utils/runBuildForSnapshots.js +704 -0
- package/dist/{test → test-utils}/testContext.js +12 -2
- package/dist/utils/collectExceptions.js +34 -0
- package/dist/utils/countOperators.js +31 -12
- package/dist/utils/createBuildHandleError.js +38 -0
- package/dist/utils/createCheckDuplicateId.js +15 -9
- package/dist/utils/createCounter.js +16 -3
- package/dist/utils/createHandleWarning.js +41 -0
- package/dist/utils/createPluginTypesMap.js +1 -1
- package/dist/utils/extractOperatorKey.js +36 -0
- package/dist/utils/findConfigKey.js +37 -0
- package/dist/utils/findSimilarString.js +53 -0
- package/dist/utils/logCollectedErrors.js +30 -0
- package/dist/utils/makeId.js +13 -8
- package/dist/utils/preserveMetaProperties.js +27 -0
- package/dist/utils/readConfigFile.js +1 -1
- package/dist/utils/setNonEnumerableProperty.js +23 -0
- package/dist/utils/traverseConfig.js +43 -0
- package/dist/utils/tryBuildStep.js +46 -0
- package/dist/utils/writeBuildArtifact.js +1 -1
- package/package.json +46 -41
- package/dist/build/buildPages/buildPages.js +0 -31
- package/dist/utils/formatErrorMessage.js +0 -56
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -13,30 +13,90 @@
|
|
|
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
|
+
import { ConfigError } from '@lowdefy/errors';
|
|
16
17
|
import createCheckDuplicateId from '../../../utils/createCheckDuplicateId.js';
|
|
17
|
-
function checkAction(action, { blockId, checkDuplicateActionId, eventId, pageId, typeCounters }) {
|
|
18
|
+
function checkAction(action, { blockId, checkDuplicateActionId, eventId, linkActionRefs, pageId, requestActionRefs, typeCounters }) {
|
|
19
|
+
const configKey = action['~k'];
|
|
18
20
|
if (type.isUndefined(action.id)) {
|
|
19
|
-
throw new
|
|
21
|
+
throw new ConfigError(`Action id missing on event "${eventId}" on block "${blockId}" on page "${pageId}".`, {
|
|
22
|
+
configKey
|
|
23
|
+
});
|
|
20
24
|
}
|
|
21
25
|
if (!type.isString(action.id)) {
|
|
22
|
-
throw new
|
|
26
|
+
throw new ConfigError(`Action id is not a string on event "${eventId}" on block "${blockId}" on page "${pageId}".`, {
|
|
27
|
+
received: action.id,
|
|
28
|
+
configKey
|
|
29
|
+
});
|
|
23
30
|
}
|
|
24
31
|
checkDuplicateActionId({
|
|
25
32
|
id: action.id,
|
|
33
|
+
configKey,
|
|
26
34
|
eventId,
|
|
27
35
|
blockId,
|
|
28
36
|
pageId
|
|
29
37
|
});
|
|
30
38
|
if (!type.isString(action.type)) {
|
|
31
|
-
throw new
|
|
39
|
+
throw new ConfigError(`Action type is not a string on action "${action.id}" on event "${eventId}" on block "${blockId}" on page "${pageId}".`, {
|
|
40
|
+
received: action.type,
|
|
41
|
+
configKey
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
typeCounters.actions.increment(action.type, configKey);
|
|
45
|
+
// Collect static Request action references for validation
|
|
46
|
+
if (action.type === 'Request' && !type.isNone(action.params)) {
|
|
47
|
+
const params = action.params;
|
|
48
|
+
if (type.isString(params)) {
|
|
49
|
+
requestActionRefs.push({
|
|
50
|
+
requestId: params,
|
|
51
|
+
action,
|
|
52
|
+
blockId,
|
|
53
|
+
eventId
|
|
54
|
+
});
|
|
55
|
+
} else if (type.isArray(params)) {
|
|
56
|
+
params.forEach((param)=>{
|
|
57
|
+
if (type.isString(param)) {
|
|
58
|
+
requestActionRefs.push({
|
|
59
|
+
requestId: param,
|
|
60
|
+
action,
|
|
61
|
+
blockId,
|
|
62
|
+
eventId
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Collect static Link action references for validation
|
|
69
|
+
if (action.type === 'Link' && !type.isNone(action.params)) {
|
|
70
|
+
const params = action.params;
|
|
71
|
+
// Link params can be a string (pageId) or object with pageId property
|
|
72
|
+
if (type.isString(params)) {
|
|
73
|
+
linkActionRefs.push({
|
|
74
|
+
pageId: params,
|
|
75
|
+
action,
|
|
76
|
+
blockId,
|
|
77
|
+
eventId,
|
|
78
|
+
sourcePageId: pageId
|
|
79
|
+
});
|
|
80
|
+
} else if (type.isObject(params) && type.isString(params.pageId)) {
|
|
81
|
+
linkActionRefs.push({
|
|
82
|
+
pageId: params.pageId,
|
|
83
|
+
action,
|
|
84
|
+
blockId,
|
|
85
|
+
eventId,
|
|
86
|
+
sourcePageId: pageId
|
|
87
|
+
});
|
|
88
|
+
}
|
|
32
89
|
}
|
|
33
|
-
typeCounters.actions.increment(action.type);
|
|
34
90
|
}
|
|
35
91
|
function buildEvents(block, pageContext) {
|
|
36
92
|
if (block.events) {
|
|
37
93
|
Object.keys(block.events).map((key)=>{
|
|
94
|
+
const eventConfigKey = block.events[key]?.['~k'] || block['~k'];
|
|
38
95
|
if (!type.isArray(block.events[key]) && !type.isObject(block.events[key]) || type.isObject(block.events[key]) && type.isNone(block.events[key].try)) {
|
|
39
|
-
throw new
|
|
96
|
+
throw new ConfigError(`Actions must be an array at "${block.blockId}" in event "${key}" on page "${pageContext.pageId}".`, {
|
|
97
|
+
received: block.events[key]?.try,
|
|
98
|
+
configKey: eventConfigKey
|
|
99
|
+
});
|
|
40
100
|
}
|
|
41
101
|
if (type.isArray(block.events[key])) {
|
|
42
102
|
block.events[key] = {
|
|
@@ -45,13 +105,19 @@ function buildEvents(block, pageContext) {
|
|
|
45
105
|
};
|
|
46
106
|
}
|
|
47
107
|
if (!type.isArray(block.events[key].try)) {
|
|
48
|
-
throw new
|
|
108
|
+
throw new ConfigError(`Try actions must be an array at "${block.blockId}" in event "${key}.try" on page "${pageContext.pageId}".`, {
|
|
109
|
+
received: block.events[key].try,
|
|
110
|
+
configKey: eventConfigKey
|
|
111
|
+
});
|
|
49
112
|
}
|
|
50
113
|
if (type.isNone(block.events[key].catch)) {
|
|
51
114
|
block.events[key].catch = [];
|
|
52
115
|
}
|
|
53
116
|
if (!type.isArray(block.events[key].catch)) {
|
|
54
|
-
throw new
|
|
117
|
+
throw new ConfigError(`Catch actions must be an array at "${block.blockId}" in event "${key}.catch" on page "${pageContext.pageId}".`, {
|
|
118
|
+
received: block.events[key].catch,
|
|
119
|
+
configKey: eventConfigKey
|
|
120
|
+
});
|
|
55
121
|
}
|
|
56
122
|
const checkDuplicateActionId = createCheckDuplicateId({
|
|
57
123
|
message: 'Duplicate actionId "{{ id }}" on event "{{ eventId }}" on block "{{ blockId }}" on page "{{ pageId }}".'
|
|
@@ -61,6 +127,8 @@ function buildEvents(block, pageContext) {
|
|
|
61
127
|
blockId: block.blockId,
|
|
62
128
|
typeCounters: pageContext.typeCounters,
|
|
63
129
|
pageId: pageContext.pageId,
|
|
130
|
+
linkActionRefs: pageContext.linkActionRefs,
|
|
131
|
+
requestActionRefs: pageContext.requestActionRefs,
|
|
64
132
|
checkDuplicateActionId
|
|
65
133
|
}));
|
|
66
134
|
block.events[key].catch.map((action)=>checkAction(action, {
|
|
@@ -68,6 +136,8 @@ function buildEvents(block, pageContext) {
|
|
|
68
136
|
blockId: block.blockId,
|
|
69
137
|
typeCounters: pageContext.typeCounters,
|
|
70
138
|
pageId: pageContext.pageId,
|
|
139
|
+
linkActionRefs: pageContext.linkActionRefs,
|
|
140
|
+
requestActionRefs: pageContext.requestActionRefs,
|
|
71
141
|
checkDuplicateActionId
|
|
72
142
|
}));
|
|
73
143
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -13,28 +13,58 @@
|
|
|
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
|
+
import { ConfigError } from '@lowdefy/errors';
|
|
16
17
|
function buildRequest(request, pageContext) {
|
|
17
|
-
const { auth, checkDuplicateRequestId, pageId, typeCounters } = pageContext;
|
|
18
|
+
const { auth, checkDuplicateRequestId, context, pageId, typeCounters } = pageContext;
|
|
19
|
+
const configKey = request['~k'];
|
|
18
20
|
if (type.isUndefined(request.id)) {
|
|
19
|
-
throw new
|
|
21
|
+
throw new ConfigError(`Request id missing at page "${pageId}".`, {
|
|
22
|
+
configKey
|
|
23
|
+
});
|
|
20
24
|
}
|
|
21
25
|
if (!type.isString(request.id)) {
|
|
22
|
-
throw new
|
|
26
|
+
throw new ConfigError(`Request id is not a string at page "${pageId}".`, {
|
|
27
|
+
received: request.id,
|
|
28
|
+
configKey
|
|
29
|
+
});
|
|
23
30
|
}
|
|
24
31
|
checkDuplicateRequestId({
|
|
25
32
|
id: request.id,
|
|
33
|
+
configKey,
|
|
26
34
|
pageId
|
|
27
35
|
});
|
|
28
36
|
if (request.id.includes('.')) {
|
|
29
|
-
throw new
|
|
37
|
+
throw new ConfigError(`Request id "${request.id}" at page "${pageId}" should not include a period (".").`, {
|
|
38
|
+
configKey
|
|
39
|
+
});
|
|
30
40
|
}
|
|
31
41
|
if (!type.isString(request.type)) {
|
|
32
|
-
throw new
|
|
42
|
+
throw new ConfigError(`Request type is not a string at request "${request.id}" at page "${pageId}".`, {
|
|
43
|
+
received: request.type,
|
|
44
|
+
configKey
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
typeCounters.requests.increment(request.type, configKey);
|
|
48
|
+
// Validate connectionId references an existing connection
|
|
49
|
+
if (!type.isNone(request.connectionId)) {
|
|
50
|
+
if (!type.isString(request.connectionId)) {
|
|
51
|
+
throw new ConfigError(`Request "${request.id}" at page "${pageId}" connectionId is not a string.`, {
|
|
52
|
+
received: request.connectionId,
|
|
53
|
+
configKey
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
if (!context.connectionIds.has(request.connectionId)) {
|
|
57
|
+
throw new ConfigError(`Request "${request.id}" at page "${pageId}" references non-existent connection "${request.connectionId}".`, {
|
|
58
|
+
configKey,
|
|
59
|
+
checkSlug: 'connection-refs'
|
|
60
|
+
});
|
|
61
|
+
}
|
|
33
62
|
}
|
|
34
|
-
typeCounters.requests.increment(request.type);
|
|
35
63
|
if (type.isUndefined(request.payload)) request.payload = {};
|
|
36
64
|
if (!type.isObject(request.payload)) {
|
|
37
|
-
throw new
|
|
65
|
+
throw new ConfigError(`Request "${request.id}" at page "${pageId}" payload should be an object.`, {
|
|
66
|
+
configKey
|
|
67
|
+
});
|
|
38
68
|
}
|
|
39
69
|
request.auth = auth;
|
|
40
70
|
request.requestId = request.id;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -13,6 +13,7 @@
|
|
|
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
|
+
import { ConfigError } from '@lowdefy/errors';
|
|
16
17
|
import buildBlock from './buildBlock.js';
|
|
17
18
|
function buildSubBlocks(block, pageContext) {
|
|
18
19
|
if (type.isObject(block.areas)) {
|
|
@@ -21,7 +22,10 @@ function buildSubBlocks(block, pageContext) {
|
|
|
21
22
|
block.areas[key].blocks = [];
|
|
22
23
|
}
|
|
23
24
|
if (!type.isArray(block.areas[key].blocks)) {
|
|
24
|
-
throw new
|
|
25
|
+
throw new ConfigError(`Expected blocks to be an array at ${block.blockId} in area ${key} on page ${pageContext.pageId}.`, {
|
|
26
|
+
received: block.areas[key].blocks,
|
|
27
|
+
configKey: block.areas[key]['~k'] ?? block['~k']
|
|
28
|
+
});
|
|
25
29
|
}
|
|
26
30
|
block.areas[key].blocks.map((blk)=>buildBlock(blk, pageContext));
|
|
27
31
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -13,6 +13,6 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ function countBlockTypes(block, { typeCounters }) {
|
|
16
|
-
typeCounters.blocks.increment(block.type);
|
|
16
|
+
typeCounters.blocks.increment(block.type, block['~k']);
|
|
17
17
|
}
|
|
18
18
|
export default countBlockTypes;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -13,10 +13,14 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import { set, type } from '@lowdefy/helpers';
|
|
16
|
+
import { ConfigError } from '@lowdefy/errors';
|
|
16
17
|
function recMoveSkeletonBlocksToArea(block, blockId, pageId) {
|
|
17
18
|
if (!type.isNone(block.blocks)) {
|
|
18
19
|
if (!type.isArray(block.blocks)) {
|
|
19
|
-
throw new
|
|
20
|
+
throw new ConfigError(`Skeleton blocks at ${blockId} on page ${pageId} is not an array.`, {
|
|
21
|
+
received: block.blocks,
|
|
22
|
+
configKey: block['~k']
|
|
23
|
+
});
|
|
20
24
|
}
|
|
21
25
|
set(block, 'areas.content.blocks', block.blocks);
|
|
22
26
|
delete block.blocks;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -13,10 +13,14 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import { set, type } from '@lowdefy/helpers';
|
|
16
|
+
import { ConfigError } from '@lowdefy/errors';
|
|
16
17
|
function moveSubBlocksToArea(block, pageContext) {
|
|
17
18
|
if (!type.isNone(block.blocks)) {
|
|
18
19
|
if (!type.isArray(block.blocks)) {
|
|
19
|
-
throw new
|
|
20
|
+
throw new ConfigError(`Blocks at ${block.blockId} on page ${pageContext.pageId} is not an array.`, {
|
|
21
|
+
received: block.blocks,
|
|
22
|
+
configKey: block['~k']
|
|
23
|
+
});
|
|
20
24
|
}
|
|
21
25
|
set(block, 'areas.content.blocks', block.blocks);
|
|
22
26
|
delete block.blocks;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -13,25 +13,43 @@
|
|
|
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
|
+
import { ConfigError } from '@lowdefy/errors';
|
|
16
17
|
function validateBlock(block, { pageId }) {
|
|
18
|
+
const configKey = block?.['~k'];
|
|
17
19
|
if (!type.isObject(block)) {
|
|
18
|
-
throw new
|
|
20
|
+
throw new ConfigError(`Expected block to be an object on page "${pageId}".`, {
|
|
21
|
+
received: block,
|
|
22
|
+
configKey
|
|
23
|
+
});
|
|
19
24
|
}
|
|
20
25
|
if (type.isUndefined(block.id)) {
|
|
21
|
-
throw new
|
|
26
|
+
throw new ConfigError(`Block id missing at page "${pageId}".`, {
|
|
27
|
+
configKey
|
|
28
|
+
});
|
|
22
29
|
}
|
|
23
30
|
if (!type.isString(block.id)) {
|
|
24
|
-
throw new
|
|
31
|
+
throw new ConfigError(`Block id is not a string at page "${pageId}".`, {
|
|
32
|
+
received: block.id,
|
|
33
|
+
configKey
|
|
34
|
+
});
|
|
25
35
|
}
|
|
26
36
|
if (type.isNone(block.type)) {
|
|
27
|
-
throw new
|
|
37
|
+
throw new ConfigError(`Block type is not defined at "${block.id}" on page "${pageId}".`, {
|
|
38
|
+
configKey
|
|
39
|
+
});
|
|
28
40
|
}
|
|
29
41
|
if (!type.isString(block.type)) {
|
|
30
|
-
throw new
|
|
42
|
+
throw new ConfigError(`Block type is not a string at "${block.id}" on page "${pageId}".`, {
|
|
43
|
+
received: block.type,
|
|
44
|
+
configKey
|
|
45
|
+
});
|
|
31
46
|
}
|
|
32
47
|
if (!type.isNone(block.requests)) {
|
|
33
48
|
if (!type.isArray(block.requests)) {
|
|
34
|
-
throw new
|
|
49
|
+
throw new ConfigError(`Requests is not an array at "${block.id}" on page "${pageId}".`, {
|
|
50
|
+
received: block.requests,
|
|
51
|
+
configKey
|
|
52
|
+
});
|
|
35
53
|
}
|
|
36
54
|
}
|
|
37
55
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable no-param-reassign */ /*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -13,33 +13,62 @@
|
|
|
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
|
+
import { ConfigError } from '@lowdefy/errors';
|
|
16
17
|
import buildBlock from './buildBlock/buildBlock.js';
|
|
18
|
+
import collectExceptions from '../../utils/collectExceptions.js';
|
|
17
19
|
import createCheckDuplicateId from '../../utils/createCheckDuplicateId.js';
|
|
18
20
|
import createCounter from '../../utils/createCounter.js';
|
|
21
|
+
import validateRequestReferences from './validateRequestReferences.js';
|
|
19
22
|
function buildPage({ page, index, context, checkDuplicatePageId }) {
|
|
23
|
+
const configKey = page['~k'];
|
|
20
24
|
if (type.isUndefined(page.id)) {
|
|
21
|
-
|
|
25
|
+
collectExceptions(context, new ConfigError(`Page id missing at page ${index}.`, {
|
|
26
|
+
configKey
|
|
27
|
+
}));
|
|
28
|
+
return {
|
|
29
|
+
failed: true
|
|
30
|
+
};
|
|
22
31
|
}
|
|
23
32
|
if (!type.isString(page.id)) {
|
|
24
|
-
|
|
33
|
+
collectExceptions(context, new ConfigError(`Page id is not a string at page ${index}.`, {
|
|
34
|
+
received: page.id,
|
|
35
|
+
configKey
|
|
36
|
+
}));
|
|
37
|
+
return {
|
|
38
|
+
failed: true
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (checkDuplicatePageId) {
|
|
42
|
+
checkDuplicatePageId({
|
|
43
|
+
id: page.id,
|
|
44
|
+
configKey
|
|
45
|
+
});
|
|
25
46
|
}
|
|
26
|
-
checkDuplicatePageId({
|
|
27
|
-
id: page.id
|
|
28
|
-
});
|
|
29
47
|
page.pageId = page.id;
|
|
30
48
|
const requests = [];
|
|
49
|
+
const requestActionRefs = [];
|
|
31
50
|
buildBlock(page, {
|
|
32
51
|
auth: page.auth,
|
|
33
52
|
blockIdCounter: createCounter(),
|
|
34
53
|
checkDuplicateRequestId: createCheckDuplicateId({
|
|
35
54
|
message: 'Duplicate requestId "{{ id }}" on page "{{ pageId }}".'
|
|
36
55
|
}),
|
|
56
|
+
context,
|
|
37
57
|
pageId: page.pageId,
|
|
38
58
|
requests,
|
|
59
|
+
requestActionRefs,
|
|
60
|
+
linkActionRefs: context.linkActionRefs,
|
|
39
61
|
typeCounters: context.typeCounters
|
|
40
62
|
});
|
|
41
63
|
// set page.id since buildBlock sets id as well.
|
|
42
64
|
page.id = `page:${page.pageId}`;
|
|
65
|
+
// Validate that all Request actions reference defined requests
|
|
66
|
+
validateRequestReferences({
|
|
67
|
+
requestActionRefs,
|
|
68
|
+
requests,
|
|
69
|
+
pageId: page.pageId,
|
|
70
|
+
context
|
|
71
|
+
});
|
|
43
72
|
page.requests = requests;
|
|
44
73
|
}
|
|
45
74
|
export default buildPage;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 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 { ConfigWarning } from '@lowdefy/errors';
|
|
16
|
+
function validateLinkReferences({ linkActionRefs, pageIds, context }) {
|
|
17
|
+
const pageIdSet = new Set(pageIds);
|
|
18
|
+
linkActionRefs.forEach(({ pageId, action, sourcePageId })=>{
|
|
19
|
+
// Only skip validation if skip is explicitly true
|
|
20
|
+
// Pages must exist in app even if Link is conditional
|
|
21
|
+
if (action.skip === true) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (!pageIdSet.has(pageId)) {
|
|
25
|
+
context.handleWarning(new ConfigWarning(`Page "${pageId}" not found. Link on page "${sourcePageId}" references non-existent page.`, {
|
|
26
|
+
configKey: action['~k'],
|
|
27
|
+
prodError: true,
|
|
28
|
+
checkSlug: 'link-refs'
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
export default validateLinkReferences;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 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 { ConfigWarning } from '@lowdefy/errors';
|
|
16
|
+
import { type } from '@lowdefy/helpers';
|
|
17
|
+
import traverseConfig from '../../utils/traverseConfig.js';
|
|
18
|
+
function validatePayloadReferences({ page, context }) {
|
|
19
|
+
const requests = page.requests || [];
|
|
20
|
+
requests.forEach((request)=>{
|
|
21
|
+
// Collect payload keys defined in the request
|
|
22
|
+
const payloadKeys = Object.keys(request.payload || {});
|
|
23
|
+
// Skip if no payload defined (nothing to reference)
|
|
24
|
+
if (payloadKeys.length === 0) return;
|
|
25
|
+
// Find _payload references in request.properties
|
|
26
|
+
const payloadRefs = new Map(); // dedup key -> { configKey, fullValue }
|
|
27
|
+
traverseConfig({
|
|
28
|
+
config: request.properties,
|
|
29
|
+
visitor: (obj)=>{
|
|
30
|
+
if (obj._payload !== undefined) {
|
|
31
|
+
const fullValue = type.isString(obj._payload) ? obj._payload : type.isObject(obj._payload) ? obj._payload.key || obj._payload.path : null;
|
|
32
|
+
if (!fullValue) return;
|
|
33
|
+
const dedupKey = fullValue.split(/[.[]/)[0];
|
|
34
|
+
if (!dedupKey || payloadRefs.has(dedupKey)) return;
|
|
35
|
+
payloadRefs.set(dedupKey, {
|
|
36
|
+
configKey: obj['~k'],
|
|
37
|
+
fullValue
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
// Warn for undefined payload references
|
|
43
|
+
payloadRefs.forEach(({ configKey, fullValue }, dedupKey)=>{
|
|
44
|
+
// Check if the full reference value matches any payload key.
|
|
45
|
+
// A payload key matches if the reference equals it exactly,
|
|
46
|
+
// or accesses a sub-path of it (key followed by '.' or '[').
|
|
47
|
+
// This handles dotted payload keys like "qc_state.chemical_analysis".
|
|
48
|
+
const isValid = payloadKeys.some((key)=>fullValue === key || fullValue.startsWith(key + '.') || fullValue.startsWith(key + '['));
|
|
49
|
+
if (isValid) return;
|
|
50
|
+
const message = `_payload references "${dedupKey}" in request "${request.requestId}" on page "${page.pageId}", ` + `but no key "${dedupKey}" exists in the request payload definition. ` + `Payload keys are defined in the request's "payload" property. ` + `Check for typos or add the key to the payload definition.`;
|
|
51
|
+
context.handleWarning(new ConfigWarning(message, {
|
|
52
|
+
configKey,
|
|
53
|
+
prodError: true,
|
|
54
|
+
checkSlug: 'payload-refs'
|
|
55
|
+
}));
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
export default validatePayloadReferences;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 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 { ConfigWarning } from '@lowdefy/errors';
|
|
16
|
+
import { type } from '@lowdefy/helpers';
|
|
17
|
+
function validateRequestReferences({ requestActionRefs, requests, pageId, context }) {
|
|
18
|
+
const requestIds = new Set(requests.map((req)=>req.requestId));
|
|
19
|
+
requestActionRefs.forEach(({ requestId, action })=>{
|
|
20
|
+
// Skip validation if action has skip condition (true or operator object)
|
|
21
|
+
if (action.skip === true || type.isObject(action.skip)) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (!requestIds.has(requestId)) {
|
|
25
|
+
context.handleWarning(new ConfigWarning(`Request "${requestId}" not defined on page "${pageId}".`, {
|
|
26
|
+
configKey: action['~k'],
|
|
27
|
+
prodError: true,
|
|
28
|
+
checkSlug: 'request-refs'
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
export default validateRequestReferences;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 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 { ConfigWarning } from '@lowdefy/errors';
|
|
16
|
+
import traverseConfig from '../../utils/traverseConfig.js';
|
|
17
|
+
function validateServerStateReferences({ page, context }) {
|
|
18
|
+
(page.requests ?? []).forEach((request)=>{
|
|
19
|
+
if (!request.properties) return;
|
|
20
|
+
let found = false;
|
|
21
|
+
let configKey = request['~k'];
|
|
22
|
+
traverseConfig({
|
|
23
|
+
config: request.properties,
|
|
24
|
+
visitor: (obj)=>{
|
|
25
|
+
if (found) return;
|
|
26
|
+
if (obj._state !== undefined) {
|
|
27
|
+
found = true;
|
|
28
|
+
configKey = obj['~k'] ?? configKey;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
if (!found) return;
|
|
33
|
+
const message = `_state is not available in request properties. ` + `Found _state in request "${request.requestId}" on page "${page.pageId}". ` + `Request properties are evaluated on the server where state is not available. ` + `To use a state value in a request, add it to the request "payload" using _state, ` + `then reference it in request properties using _payload.`;
|
|
34
|
+
context.handleWarning(new ConfigWarning(message, {
|
|
35
|
+
configKey,
|
|
36
|
+
prodError: true,
|
|
37
|
+
checkSlug: 'state-refs'
|
|
38
|
+
}));
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
export default validateServerStateReferences;
|