@lowdefy/build 4.5.2 → 4.7.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 (163) hide show
  1. package/dist/build/addDefaultPages/404.js +1 -1
  2. package/dist/build/addDefaultPages/addDefaultPages.js +10 -4
  3. package/dist/build/addKeys.js +85 -29
  4. package/dist/build/buildApi/buildApi.js +27 -8
  5. package/dist/build/buildApi/buildEndpoint.js +7 -1
  6. package/dist/build/buildApi/buildRoutine/buildControl.js +1 -1
  7. package/dist/build/buildApi/buildRoutine/buildRoutine.js +1 -1
  8. package/dist/build/buildApi/buildRoutine/buildStep.js +1 -1
  9. package/dist/build/buildApi/buildRoutine/controlTypes.js +34 -11
  10. package/dist/build/buildApi/buildRoutine/countControl.js +1 -1
  11. package/dist/build/buildApi/buildRoutine/countStepTypes.js +2 -2
  12. package/dist/build/buildApi/buildRoutine/setStepId.js +1 -1
  13. package/dist/build/buildApi/buildRoutine/validateStep.js +30 -9
  14. package/dist/build/buildApi/validateEndpoint.js +36 -7
  15. package/dist/build/buildApi/validateStepReferences.js +65 -0
  16. package/dist/build/buildApp.js +1 -1
  17. package/dist/build/buildAuth/buildApiAuth.js +7 -3
  18. package/dist/build/buildAuth/buildAuth.js +7 -4
  19. package/dist/build/buildAuth/buildAuthPlugins.js +42 -13
  20. package/dist/build/buildAuth/buildPageAuth.js +14 -3
  21. package/dist/build/buildAuth/getApiRoles.js +1 -1
  22. package/dist/build/buildAuth/getPageRoles.js +1 -1
  23. package/dist/build/buildAuth/getProtectedApi.js +1 -1
  24. package/dist/build/buildAuth/getProtectedPages.js +1 -1
  25. package/dist/build/buildAuth/validateAuthConfig.js +39 -5
  26. package/dist/build/buildAuth/validateMutualExclusivity.js +13 -5
  27. package/dist/build/buildConnections.js +23 -24
  28. package/dist/build/buildImports/buildIconImports.js +1 -1
  29. package/dist/build/buildImports/buildImports.js +1 -1
  30. package/dist/build/buildImports/buildImportsDev.js +1 -1
  31. package/dist/build/buildImports/buildImportsProd.js +1 -1
  32. package/dist/build/buildImports/buildStyleImports.js +1 -1
  33. package/dist/build/buildImports/defaultIconsDev.js +1 -1
  34. package/dist/build/buildImports/defaultIconsProd.js +1 -1
  35. package/dist/build/buildJs/generateJsFile.js +1 -1
  36. package/dist/build/buildJs/jsMapParser.js +1 -1
  37. package/dist/build/buildJs/writeJs.js +1 -1
  38. package/dist/build/buildLogger.js +41 -0
  39. package/dist/build/buildMenu.js +36 -12
  40. package/dist/build/buildPages/buildBlock/buildBlock.js +1 -1
  41. package/dist/build/buildPages/buildBlock/buildEvents.js +79 -9
  42. package/dist/build/buildPages/buildBlock/buildRequests.js +38 -8
  43. package/dist/build/buildPages/buildBlock/buildSubBlocks.js +6 -2
  44. package/dist/build/buildPages/buildBlock/countBlockOperators.js +1 -1
  45. package/dist/build/buildPages/buildBlock/countBlockTypes.js +2 -2
  46. package/dist/build/buildPages/buildBlock/moveSkeletonBlocksToArea.js +6 -2
  47. package/dist/build/buildPages/buildBlock/moveSubBlocksToArea.js +6 -2
  48. package/dist/build/buildPages/buildBlock/setBlockId.js +1 -1
  49. package/dist/build/buildPages/buildBlock/validateBlock.js +25 -7
  50. package/dist/build/buildPages/buildPage.js +35 -6
  51. package/dist/build/buildPages/validateLinkReferences.js +33 -0
  52. package/dist/build/buildPages/validatePayloadReferences.js +59 -0
  53. package/dist/build/buildPages/validateRequestReferences.js +33 -0
  54. package/dist/build/buildPages/validateServerStateReferences.js +41 -0
  55. package/dist/build/buildPages/validateStateReferences.js +79 -0
  56. package/dist/build/buildRefs/buildRefs.js +40 -7
  57. package/dist/build/buildRefs/evaluateStaticOperators.js +52 -0
  58. package/dist/build/buildRefs/getConfigFile.js +25 -6
  59. package/dist/build/buildRefs/getKey.js +1 -1
  60. package/dist/build/buildRefs/getRefContent.js +1 -1
  61. package/dist/build/buildRefs/getRefPath.js +1 -1
  62. package/dist/build/buildRefs/getUserJavascriptFunction.js +18 -4
  63. package/dist/build/buildRefs/makeRefDefinition.js +10 -5
  64. package/dist/build/buildRefs/parseNunjucks.js +1 -1
  65. package/dist/build/buildRefs/parseRefContent.js +108 -7
  66. package/dist/build/buildRefs/runRefResolver.js +11 -3
  67. package/dist/build/buildRefs/runTransformer.js +7 -3
  68. package/dist/build/buildRefs/walker.js +340 -0
  69. package/dist/build/buildTypes.js +22 -7
  70. package/dist/build/cleanBuildDirectory.js +1 -1
  71. package/dist/build/collectDynamicIdentifiers.js +35 -0
  72. package/dist/build/collectTypeNames.js +36 -0
  73. package/dist/build/copyPublicFolder.js +1 -1
  74. package/dist/build/{buildJs → full}/buildJs.js +3 -3
  75. package/dist/build/full/buildPages.js +87 -0
  76. package/dist/build/{buildPages → full}/buildTestPage.js +15 -3
  77. package/dist/build/{updateServerPackageJson.js → full/updateServerPackageJson.js} +1 -1
  78. package/dist/build/{writePages.js → full/writePages.js} +1 -1
  79. package/dist/build/{writeRequests.js → full/writeRequests.js} +11 -3
  80. package/dist/build/{writeTypes.js → full/writeTypes.js} +1 -1
  81. package/dist/build/jit/addInstalledTypes.js +51 -0
  82. package/dist/build/jit/buildJsShallow.js +41 -0
  83. package/dist/build/jit/buildPageJit.js +271 -0
  84. package/dist/build/jit/buildShallowPages.js +90 -0
  85. package/dist/build/jit/createPageRegistry.js +85 -0
  86. package/dist/build/jit/detectMissingPluginPackages.js +62 -0
  87. package/dist/build/jit/isPageContentPath.js +24 -0
  88. package/dist/build/jit/pageContentKeys.js +26 -0
  89. package/dist/build/jit/shallowBuild.js +242 -0
  90. package/dist/build/jit/updateServerPackageJsonJit.js +33 -0
  91. package/dist/build/jit/validatePageTypes.js +73 -0
  92. package/dist/build/jit/writePageJit.js +44 -0
  93. package/dist/build/jit/writePageRegistry.js +23 -0
  94. package/dist/build/jit/writeSourcelessPages.js +23 -0
  95. package/dist/build/testSchema.js +45 -7
  96. package/dist/build/validateConfig.js +2 -2
  97. package/dist/build/validateOperatorsDynamic.js +28 -0
  98. package/dist/build/writeApi.js +1 -1
  99. package/dist/build/writeApp.js +1 -1
  100. package/dist/build/writeAuth.js +1 -1
  101. package/dist/build/writeConfig.js +1 -1
  102. package/dist/build/writeConnections.js +1 -1
  103. package/dist/build/writeGlobal.js +1 -1
  104. package/dist/build/writeLogger.js +19 -0
  105. package/dist/build/writeMaps.js +1 -1
  106. package/dist/build/writeMenus.js +1 -1
  107. package/dist/build/writePluginImports/generateImportFile.js +1 -1
  108. package/dist/build/writePluginImports/writeActionImports.js +1 -1
  109. package/dist/build/writePluginImports/writeActionSchemaMap.js +42 -0
  110. package/dist/build/writePluginImports/writeAuthImports.js +1 -1
  111. package/dist/build/writePluginImports/writeBlockImports.js +1 -1
  112. package/dist/build/writePluginImports/writeBlockSchemaMap.js +42 -0
  113. package/dist/build/writePluginImports/writeConnectionImports.js +1 -1
  114. package/dist/build/writePluginImports/writeIconImports.js +1 -1
  115. package/dist/build/writePluginImports/writeOperatorImports.js +1 -1
  116. package/dist/build/writePluginImports/writeOperatorSchemaMap.js +49 -0
  117. package/dist/build/writePluginImports/writePluginImports.js +16 -1
  118. package/dist/build/writePluginImports/writeStyleImports.js +1 -1
  119. package/dist/createContext.js +16 -4
  120. package/dist/defaultTypesMap.js +479 -457
  121. package/dist/index.js +190 -127
  122. package/dist/indexDev.js +19 -0
  123. package/dist/lowdefySchema.js +588 -0
  124. package/dist/scripts/generateDefaultTypes.js +2 -1
  125. package/dist/scripts/run.js +1 -1
  126. package/dist/{test → test-utils}/buildRefs/testBuildRefsAsyncFunction.js +1 -1
  127. package/dist/{test → test-utils}/buildRefs/testBuildRefsErrorResolver.js +1 -1
  128. package/dist/{test → test-utils}/buildRefs/testBuildRefsNullResolver.js +1 -1
  129. package/dist/{test → test-utils}/buildRefs/testBuildRefsParsingResolver.js +1 -1
  130. package/dist/{test → test-utils}/buildRefs/testBuildRefsResolver.js +1 -1
  131. package/dist/{test → test-utils}/buildRefs/testBuildRefsTransform.js +1 -1
  132. package/dist/{test → test-utils}/buildRefs/testBuildRefsTransformIdentity.js +1 -1
  133. package/dist/test-utils/buildRefs/testJitPageResolver.js +24 -0
  134. package/dist/test-utils/createTestLogger.js +36 -0
  135. package/dist/test-utils/parseTestYaml.js +126 -0
  136. package/dist/test-utils/runBuild.js +228 -0
  137. package/dist/test-utils/runBuildForSnapshots.js +704 -0
  138. package/dist/{test → test-utils}/testContext.js +12 -2
  139. package/dist/utils/collectExceptions.js +34 -0
  140. package/dist/utils/countOperators.js +31 -12
  141. package/dist/utils/createBuildHandleError.js +38 -0
  142. package/dist/utils/createCheckDuplicateId.js +15 -9
  143. package/dist/utils/createCounter.js +16 -3
  144. package/dist/utils/createHandleWarning.js +41 -0
  145. package/dist/utils/createPluginTypesMap.js +1 -1
  146. package/dist/utils/extractOperatorKey.js +36 -0
  147. package/dist/utils/findConfigKey.js +37 -0
  148. package/dist/utils/findSimilarString.js +53 -0
  149. package/dist/utils/logCollectedErrors.js +30 -0
  150. package/dist/utils/makeId.js +16 -8
  151. package/dist/utils/preserveMetaProperties.js +27 -0
  152. package/dist/utils/readConfigFile.js +1 -1
  153. package/dist/utils/setNonEnumerableProperty.js +23 -0
  154. package/dist/utils/traverseConfig.js +43 -0
  155. package/dist/utils/tryBuildStep.js +46 -0
  156. package/dist/utils/writeBuildArtifact.js +1 -1
  157. package/package.json +46 -41
  158. package/dist/build/buildPages/buildPages.js +0 -31
  159. package/dist/build/buildRefs/evaluateBuildOperators.js +0 -34
  160. package/dist/build/buildRefs/getRefsFromFile.js +0 -37
  161. package/dist/build/buildRefs/populateRefs.js +0 -43
  162. package/dist/build/buildRefs/recursiveBuild.js +0 -85
  163. package/dist/utils/formatErrorMessage.js +0 -56
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2020-2024 Lowdefy, Inc
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.
@@ -47,12 +47,22 @@ 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,
54
55
  ...logger
55
56
  };
57
+ // handleWarning works like a simplified version of the production handleWarning
58
+ context.handleWarning = (warning)=>{
59
+ if (warning.prodError && context.stage === 'prod') {
60
+ throw new Error(warning.message);
61
+ }
62
+ context.logger.warn(warning.message);
63
+ };
64
+ // handleError delegates to logger.error
65
+ context.handleError = context.logger.error;
56
66
  return context;
57
67
  }
58
68
  export default testContext;
@@ -0,0 +1,34 @@
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 { shouldSuppressBuildCheck } from '@lowdefy/errors';
16
+ /**
17
+ * Collects an exception (ConfigError or ConfigWarning) instead of throwing immediately.
18
+ * Allows the build to continue and collect all exceptions before stopping.
19
+ *
20
+ * @param {Object} context - Build context
21
+ * @param {ConfigError|ConfigWarning} exception - Exception instance (already created with all properties)
22
+ */ function collectExceptions(context, exception) {
23
+ // Skip suppressed exceptions (from ~ignoreBuildChecks)
24
+ if (shouldSuppressBuildCheck(exception, context.keyMap)) {
25
+ return;
26
+ }
27
+ if (!context.errors) {
28
+ // If no error collection array, throw immediately (fallback for tests)
29
+ throw exception;
30
+ }
31
+ // Collect exception object - logging happens at checkpoints in index.js
32
+ context.errors.push(exception);
33
+ }
34
+ export default collectExceptions;
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2020-2024 Lowdefy, Inc
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,18 +13,37 @@
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
+ // Keys that look like operators (single key starting with _) but are not.
17
+ const KNOWN_NON_OPERATORS = new Set([
18
+ '_id'
19
+ ]);
20
+ function walkAndCount(value, counter, parentConfigKey) {
21
+ if (type.isArray(value)) {
22
+ value.forEach((item)=>walkAndCount(item, counter, parentConfigKey));
23
+ return;
24
+ }
25
+ if (!type.isObject(value)) {
26
+ return;
27
+ }
28
+ const configKey = value['~k'] || parentConfigKey;
29
+ const keys = Object.keys(value);
30
+ // Check if this object is an operator (single key starting with _, ignoring ~ prefixed keys)
31
+ // This allows ~ignoreBuildCheck to be on the same object as an operator
32
+ const nonTildeKeys = keys.filter((k)=>!k.startsWith('~'));
33
+ if (nonTildeKeys.length === 1) {
34
+ const key = nonTildeKeys[0];
35
+ const [op] = key.split('.');
36
+ const operator = op.replace(/^(_+)/gm, '_');
37
+ if (operator.length > 1 && operator[0] === '_' && !KNOWN_NON_OPERATORS.has(operator)) {
38
+ counter.increment(operator, configKey);
25
39
  }
26
- return value;
27
40
  }
28
- JSON.parse(JSON.stringify(obj), getOperatorsReviver);
41
+ // Recurse into all values
42
+ keys.forEach((key)=>{
43
+ walkAndCount(value[key], counter, configKey);
44
+ });
45
+ }
46
+ function countOperators(obj, { counter }) {
47
+ walkAndCount(obj, counter, null);
29
48
  }
30
49
  export default countOperators;
@@ -0,0 +1,38 @@
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 { resolveErrorLocation } from '@lowdefy/errors';
16
+ function createBuildHandleError({ context }) {
17
+ return function handleError(error) {
18
+ try {
19
+ const location = resolveErrorLocation(error, {
20
+ keyMap: context.keyMap,
21
+ refMap: context.refMap,
22
+ configDirectory: context.directories?.config
23
+ });
24
+ if (location) {
25
+ error.source = location.source;
26
+ error.config = location.config;
27
+ }
28
+ context.logger.error(error);
29
+ } catch {
30
+ try {
31
+ context.logger.error(error);
32
+ } catch {
33
+ console.error(error);
34
+ }
35
+ }
36
+ };
37
+ }
38
+ export default createBuildHandleError;
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2020-2024 Lowdefy, Inc
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,17 +13,23 @@
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
+ import { ConfigError } from '@lowdefy/errors';
16
17
  function createCheckDuplicateId({ message }) {
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
+ const errorMessage = template({
23
+ id,
24
+ blockId,
25
+ eventId,
26
+ menuId,
27
+ pageId
28
+ });
29
+ throw new ConfigError(errorMessage, {
30
+ configKey
31
+ });
32
+ }
27
33
  ids.add(id.toLowerCase());
28
34
  }
29
35
  return checkDuplicateId;
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2020-2024 Lowdefy, Inc
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.
@@ -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,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 { resolveErrorLocation, shouldSuppressBuildCheck } from '@lowdefy/errors';
16
+ import collectExceptions from './collectExceptions.js';
17
+ function createHandleWarning({ context }) {
18
+ return function handleWarning(warning) {
19
+ if (shouldSuppressBuildCheck(warning, context.keyMap)) {
20
+ return;
21
+ }
22
+ if (warning.prodError && context.stage === 'prod') {
23
+ collectExceptions(context, warning);
24
+ return;
25
+ }
26
+ const location = resolveErrorLocation(warning, {
27
+ keyMap: context.keyMap,
28
+ refMap: context.refMap,
29
+ configDirectory: context.directories?.config
30
+ });
31
+ if (location) {
32
+ warning.source = location.source;
33
+ warning.config = location.config;
34
+ }
35
+ const dedupKey = warning.source ?? warning.message;
36
+ if (context.seenSourceLines?.has(dedupKey)) return;
37
+ context.seenSourceLines?.add(dedupKey);
38
+ context.logger.warn(warning);
39
+ };
40
+ }
41
+ export default createHandleWarning;
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2020-2024 Lowdefy, Inc
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.
@@ -0,0 +1,36 @@
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 { 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,37 @@
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 { type } from '@lowdefy/helpers';
16
+ /**
17
+ * Finds the configKey (~k) for an object at a given instance path.
18
+ * Navigates through the components following the path and returns
19
+ * the deepest ~k value found.
20
+ *
21
+ * @param {Object} params
22
+ * @param {Object} params.components - The components object with ~k markers
23
+ * @param {string[]} params.instancePath - Array of path segments (e.g., ['pages', '0', 'blocks', '0'])
24
+ * @returns {string|undefined} The configKey (~k) value or undefined if not found
25
+ */ function findConfigKey({ components, instancePath }) {
26
+ let current = components;
27
+ let configKey = components['~k'];
28
+ for (const part of instancePath){
29
+ if (type.isNone(current)) break;
30
+ current = type.isArray(current) ? current[parseInt(part, 10)] : current[part];
31
+ if (current?.['~k']) {
32
+ configKey = current['~k'];
33
+ }
34
+ }
35
+ return configKey;
36
+ }
37
+ export default findConfigKey;
@@ -0,0 +1,53 @@
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
+ */ 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,30 @@
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 { BuildError, LowdefyInternalError } from '@lowdefy/errors';
16
+ function logCollectedErrors(context) {
17
+ if (context.errors.length === 0) return;
18
+ context.errors.forEach((err)=>{
19
+ if (err.isLowdefyError) {
20
+ context.handleError(err);
21
+ } else {
22
+ const lowdefyErr = new LowdefyInternalError(err.message, {
23
+ cause: err
24
+ });
25
+ context.handleError(lowdefyErr);
26
+ }
27
+ });
28
+ throw new BuildError(`Build failed with ${context.errors.length} error(s). See above for details.`);
29
+ }
30
+ export default logCollectedErrors;
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2020-2024 Lowdefy, Inc
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.
@@ -12,12 +12,20 @@
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
- */ let id_counter = 0;
16
- function makeId(reset) {
17
- if (reset) {
18
- id_counter = 0;
15
+ */ let MakeId = class MakeId {
16
+ next() {
17
+ this.counter++;
18
+ return this.counter.toString(36);
19
19
  }
20
- id_counter++;
21
- return id_counter.toString(36);
22
- }
20
+ reset() {
21
+ this.counter = 0;
22
+ }
23
+ setCounter(value) {
24
+ this.counter = value;
25
+ }
26
+ constructor(){
27
+ this.counter = 0;
28
+ }
29
+ };
30
+ const makeId = new MakeId();
23
31
  export default makeId;
@@ -0,0 +1,27 @@
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 setNonEnumerableProperty from './setNonEnumerableProperty.js';
16
+ function preserveMetaProperties(target, source, props = [
17
+ '~r',
18
+ '~l',
19
+ '~k'
20
+ ]) {
21
+ for (const prop of props){
22
+ if (source[prop] !== undefined) {
23
+ setNonEnumerableProperty(target, prop, source[prop]);
24
+ }
25
+ }
26
+ }
27
+ export default preserveMetaProperties;
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2020-2024 Lowdefy, Inc
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.
@@ -0,0 +1,23 @@
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
+ */ function setNonEnumerableProperty(obj, prop, value) {
16
+ Object.defineProperty(obj, prop, {
17
+ value,
18
+ enumerable: false,
19
+ writable: true,
20
+ configurable: true
21
+ });
22
+ }
23
+ export default setNonEnumerableProperty;
@@ -0,0 +1,43 @@
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 { type } from '@lowdefy/helpers';
16
+ /**
17
+ * Generic depth-first traversal of Lowdefy config objects.
18
+ * Visits every object and array in the tree, calling the visitor function for each.
19
+ *
20
+ * @param {Object} options
21
+ * @param {any} options.config - The config object to traverse
22
+ * @param {Function} options.visitor - Called for each object: visitor(obj) => void
23
+ */ function traverseConfig({ config, visitor }) {
24
+ if (!type.isObject(config) && !type.isArray(config)) return;
25
+ if (type.isObject(config)) {
26
+ visitor(config);
27
+ for (const value of Object.values(config)){
28
+ traverseConfig({
29
+ config: value,
30
+ visitor
31
+ });
32
+ }
33
+ }
34
+ if (type.isArray(config)) {
35
+ for (const item of config){
36
+ traverseConfig({
37
+ config: item,
38
+ visitor
39
+ });
40
+ }
41
+ }
42
+ }
43
+ export default traverseConfig;
@@ -0,0 +1,46 @@
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 { ConfigError, shouldSuppressBuildCheck } from '@lowdefy/errors';
16
+ /**
17
+ * Wraps a build step to collect errors instead of stopping immediately.
18
+ * Errors are collected in context.errors[], allowing the build to continue
19
+ * and report all errors at once. Errors are logged together at checkpoints
20
+ * in index.js to ensure proper ordering before the summary message.
21
+ *
22
+ * ConfigErrors suppressed via ~ignoreBuildChecks are ignored.
23
+ *
24
+ * @param {Function} stepFn - Build step function to execute
25
+ * @param {string} stepName - Name of the build step (for debugging)
26
+ * @param {Object} params - Parameters object
27
+ * @param {Object} params.components - Build components
28
+ * @param {Object} params.context - Build context with errors array
29
+ * @returns {*} Result of the build step function
30
+ */ function tryBuildStep(stepFn, stepName, { components, context }) {
31
+ try {
32
+ return stepFn({
33
+ components,
34
+ context
35
+ });
36
+ } catch (error) {
37
+ // Skip suppressed ConfigErrors (via ~ignoreBuildChecks)
38
+ if (error instanceof ConfigError && shouldSuppressBuildCheck(error, context.keyMap)) {
39
+ return;
40
+ }
41
+ // Collect error object - logging happens at checkpoints in index.js
42
+ // ConfigError instances have source and message properties
43
+ context.errors.push(error);
44
+ }
45
+ }
46
+ export default tryBuildStep;
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2020-2024 Lowdefy, Inc
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.