@lowdefy/node-utils 0.0.0-experimental-20260126225618 → 0.0.0-experimental-20260202133532

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/index.js CHANGED
@@ -13,14 +13,10 @@
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  */ import cleanDirectory from './cleanDirectory.js';
16
- import ConfigError from './ConfigError.js';
17
- import ConfigMessage, { VALID_CHECK_SLUGS } from './ConfigMessage.js';
18
- import ConfigWarning from './ConfigWarning.js';
19
16
  import copyFileOrDirectory from './copyFileOrDirectory.js';
20
17
  import getFileExtension, { getFileSubExtension } from './getFileExtension.js';
21
18
  import getSecretsFromEnv from './getSecretsFromEnv.js';
22
- import resolveConfigLocation from './resolveConfigLocation.js';
23
19
  import spawnProcess from './spawnProcess.js';
24
20
  import readFile from './readFile.js';
25
21
  import writeFile from './writeFile.js';
26
- export { cleanDirectory, ConfigError, ConfigMessage, ConfigWarning, copyFileOrDirectory, getFileExtension, getFileSubExtension, getSecretsFromEnv, resolveConfigLocation, spawnProcess, readFile, VALID_CHECK_SLUGS, writeFile };
22
+ export { cleanDirectory, copyFileOrDirectory, getFileExtension, getFileSubExtension, getSecretsFromEnv, spawnProcess, readFile, writeFile };
package/dist/readFile.js CHANGED
@@ -19,7 +19,7 @@ import { type } from '@lowdefy/helpers';
19
19
  const readFilePromise = promisify(fs.readFile);
20
20
  async function readFile(filePath) {
21
21
  if (!type.isString(filePath)) {
22
- throw new Error(`Could not read file, file path should be a string, received ${JSON.stringify(filePath)}.`);
22
+ throw new Error('Could not read file, file path should be a string.');
23
23
  }
24
24
  try {
25
25
  // By specifying encoding, readFile returns a string instead of a buffer.
package/dist/writeFile.js CHANGED
@@ -20,7 +20,7 @@ const mkdirPromise = promisify(fs.mkdir);
20
20
  const writeFilePromise = promisify(fs.writeFile);
21
21
  async function writeFile(filePath, content) {
22
22
  if (!type.isString(filePath)) {
23
- throw new Error(`Could not write file, file path should be a string, received ${JSON.stringify(filePath)}.`);
23
+ throw new Error('Could not write file, file path should be a string.');
24
24
  }
25
25
  try {
26
26
  await writeFilePromise(path.resolve(filePath), content);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lowdefy/node-utils",
3
- "version": "0.0.0-experimental-20260126225618",
3
+ "version": "0.0.0-experimental-20260202133532",
4
4
  "license": "Apache-2.0",
5
5
  "description": "",
6
6
  "homepage": "https://lowdefy.com",
@@ -34,7 +34,8 @@
34
34
  "dist/*"
35
35
  ],
36
36
  "dependencies": {
37
- "@lowdefy/helpers": "0.0.0-experimental-20260126225618",
37
+ "@lowdefy/errors": "0.0.0-experimental-20260202133532",
38
+ "@lowdefy/helpers": "0.0.0-experimental-20260202133532",
38
39
  "fs-extra": "11.1.1"
39
40
  },
40
41
  "devDependencies": {
@@ -1,80 +0,0 @@
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 ConfigMessage from './ConfigMessage.js';
16
- /**
17
- * Custom error class for configuration errors.
18
- *
19
- * @example
20
- * // Standard usage with message
21
- * throw new ConfigError({
22
- * message: 'Connection id missing.',
23
- * configKey: block['~k'],
24
- * context,
25
- * });
26
- *
27
- * @example
28
- * // YAML parse error - pass error object instead of message
29
- * throw new ConfigError({
30
- * error: yamlParseError,
31
- * filePath: 'lowdefy.yaml',
32
- * configDirectory,
33
- * });
34
- */ let ConfigError = class ConfigError extends Error {
35
- /**
36
- * Format an error message with [Config Error] prefix.
37
- * @param {Object} params - Same as ConfigMessage.format() but without prefix
38
- * @returns {string} Formatted error message or empty string if suppressed
39
- */ static format(params) {
40
- return ConfigMessage.format({
41
- ...params,
42
- prefix: '[Config Error]'
43
- });
44
- }
45
- /**
46
- * Creates a ConfigError instance.
47
- * @param {Object} params
48
- * @param {string} [params.message] - The error message (or use params.error for YAML errors)
49
- * @param {Error} [params.error] - Original error (for YAML parse errors - extracts line number)
50
- * @param {string} [params.configKey] - Config key (~k) for keyMap lookup
51
- * @param {Object} [params.operatorLocation] - { ref, line } for direct refMap lookup
52
- * @param {string} [params.filePath] - Direct file path (for raw mode)
53
- * @param {number|string} [params.lineNumber] - Direct line number (for raw mode)
54
- * @param {Object} [params.context] - Build context with keyMap, refMap, directories
55
- * @param {string} [params.configDirectory] - Config directory (for raw mode without context)
56
- */ constructor({ message, error, configKey, operatorLocation, filePath, lineNumber, context, configDirectory, checkSlug }){
57
- // Handle YAML parse errors - extract line number from error message
58
- let finalMessage = message;
59
- let finalLineNumber = lineNumber;
60
- if (error instanceof Error) {
61
- finalMessage = `Could not parse YAML. ${error.message}`;
62
- const lineMatch = error.message.match(/at line (\d+)/);
63
- finalLineNumber = lineMatch ? lineMatch[1] : null;
64
- }
65
- const formattedMessage = ConfigError.format({
66
- message: finalMessage,
67
- configKey,
68
- operatorLocation,
69
- filePath,
70
- lineNumber: finalLineNumber,
71
- context,
72
- configDirectory,
73
- checkSlug
74
- });
75
- super(formattedMessage);
76
- this.name = 'ConfigError';
77
- this.suppressed = formattedMessage === '';
78
- }
79
- };
80
- export default ConfigError;
@@ -1,157 +0,0 @@
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 path from 'path';
16
- import resolveConfigLocation from './resolveConfigLocation.js';
17
- /**
18
- * Valid check slugs for ~ignoreBuildChecks.
19
- * Keys are the slug names, values are descriptions for error messages.
20
- * These suppress BUILD-TIME validation only - runtime errors still occur.
21
- */ export const VALID_CHECK_SLUGS = {
22
- 'state-refs': 'Undefined _state reference warnings',
23
- 'payload-refs': 'Undefined _payload reference warnings',
24
- 'step-refs': 'Undefined _step reference warnings',
25
- 'link-refs': 'Invalid Link action page reference warnings',
26
- 'request-refs': 'Invalid Request action reference warnings',
27
- 'connection-refs': 'Nonexistent connection ID references',
28
- 'types': 'All type validation (blocks, operators, actions, requests, connections)',
29
- 'schema': 'JSON schema validation errors'
30
- };
31
- /**
32
- * Base class for config message formatting.
33
- * Provides shared utilities for ConfigError and ConfigWarning.
34
- */ let ConfigMessage = class ConfigMessage {
35
- /**
36
- * Checks if a message should be suppressed based on ~ignoreBuildChecks.
37
- * Walks up the parent chain looking for suppressions that cover this check.
38
- * This walk happens ONLY when an error/warning is about to be logged.
39
- *
40
- * @param {Object} params
41
- * @param {string} params.configKey - Config key (~k) of the error location
42
- * @param {Object} params.keyMap - The keyMap from build context
43
- * @param {string} [params.checkSlug] - The specific check being performed (e.g., 'state-refs')
44
- * @returns {boolean} True if message should be suppressed
45
- */ static shouldSuppress({ configKey, keyMap, checkSlug }) {
46
- if (!configKey || !keyMap) return false;
47
- let currentKey = configKey;
48
- let depth = 0;
49
- const MAX_DEPTH = 100; // Guard against circular parents
50
- while(currentKey && depth < MAX_DEPTH){
51
- const entry = keyMap[currentKey];
52
- if (!entry) break;
53
- const ignoredChecks = entry['~ignoreBuildChecks'];
54
- if (ignoredChecks === true) {
55
- return true;
56
- }
57
- if (Array.isArray(ignoredChecks) && checkSlug && ignoredChecks.includes(checkSlug)) {
58
- return true;
59
- }
60
- currentKey = entry['~k_parent'];
61
- depth++;
62
- }
63
- return false;
64
- }
65
- /**
66
- * Resolves location directly from operatorLocation (ref + line) without keyMap.
67
- * Used during early build stages (buildRefs) when keyMap doesn't exist yet.
68
- * @private
69
- */ static _resolveOperatorLocation({ operatorLocation, refMap, configDirectory }) {
70
- const refEntry = refMap?.[operatorLocation.ref];
71
- const filePath = refEntry?.path ?? 'lowdefy.yaml';
72
- const lineNumber = operatorLocation.line;
73
- const source = lineNumber ? `${filePath}:${lineNumber}` : filePath;
74
- let link = '';
75
- if (configDirectory) {
76
- link = path.join(configDirectory, filePath) + (lineNumber ? `:${lineNumber}` : '');
77
- }
78
- return {
79
- source,
80
- link
81
- };
82
- }
83
- /**
84
- * Resolves location from raw filePath and lineNumber.
85
- * Used for YAML parse errors and other cases without config context.
86
- * @private
87
- */ static _resolveRawLocation({ filePath, lineNumber, configDirectory }) {
88
- const source = lineNumber ? `${filePath}:${lineNumber}` : filePath;
89
- let link = '';
90
- if (configDirectory) {
91
- link = path.join(configDirectory, filePath) + (lineNumber ? `:${lineNumber}` : '');
92
- }
93
- return {
94
- source,
95
- link
96
- };
97
- }
98
- /**
99
- * Core formatting method for config messages.
100
- *
101
- * Supports three modes:
102
- * 1. configKey mode: Uses keyMap to resolve location (standard case after addKeys)
103
- * 2. operatorLocation mode: Uses refMap directly (early build stages like buildRefs)
104
- * 3. Raw mode: Uses filePath/lineNumber directly (YAML parse errors)
105
- *
106
- * @param {Object} params
107
- * @param {string} params.prefix - Message prefix like '[Config Error]' or '[Config Warning]'
108
- * @param {string} params.message - The error/warning message
109
- * @param {string} [params.configKey] - Config key (~k) for keyMap lookup
110
- * @param {Object} [params.operatorLocation] - { ref, line } for direct refMap lookup
111
- * @param {string} [params.filePath] - Direct file path (for raw mode)
112
- * @param {number|string} [params.lineNumber] - Direct line number (for raw mode)
113
- * @param {Object} [params.context] - Build context with keyMap, refMap, directories
114
- * @param {string} [params.configDirectory] - Config directory (for raw mode without context)
115
- * @param {string} [params.checkSlug] - The specific check being performed (e.g., 'state-refs')
116
- * @returns {string} Formatted message or empty string if suppressed
117
- */ static format({ prefix, message, configKey, operatorLocation, filePath, lineNumber, context, configDirectory, checkSlug }) {
118
- // Check for ~ignoreBuildChecks suppression
119
- if (ConfigMessage.shouldSuppress({
120
- configKey,
121
- keyMap: context?.keyMap,
122
- checkSlug
123
- })) {
124
- return '';
125
- }
126
- let location = null;
127
- const configDir = configDirectory ?? context?.directories?.config;
128
- if (configKey && context?.keyMap) {
129
- // Mode 1: Use configKey -> keyMap -> refMap path (standard case after addKeys)
130
- location = resolveConfigLocation({
131
- configKey,
132
- keyMap: context.keyMap,
133
- refMap: context.refMap,
134
- configDirectory: configDir
135
- });
136
- } else if (operatorLocation && context?.refMap) {
137
- // Mode 2: Use operatorLocation directly with refMap (early build stages)
138
- location = ConfigMessage._resolveOperatorLocation({
139
- operatorLocation,
140
- refMap: context.refMap,
141
- configDirectory: configDir
142
- });
143
- } else if (filePath) {
144
- // Mode 3: Use raw filePath/lineNumber (YAML parse errors, etc.)
145
- location = ConfigMessage._resolveRawLocation({
146
- filePath,
147
- lineNumber,
148
- configDirectory: configDir
149
- });
150
- }
151
- if (!location) {
152
- return `${prefix} ${message}`;
153
- }
154
- return `${location.source}\n${prefix} ${message}`;
155
- }
156
- };
157
- export default ConfigMessage;
@@ -1,47 +0,0 @@
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 ConfigError from './ConfigError.js';
16
- import ConfigMessage from './ConfigMessage.js';
17
- /**
18
- * Utility class for configuration warnings.
19
- *
20
- * @example
21
- * const formatted = ConfigWarning.format({ message, configKey, context });
22
- * if (formatted) logger.warn(formatted);
23
- *
24
- * @example
25
- * // Throws ConfigError in prod mode when prodError is true
26
- * ConfigWarning.format({ message, configKey, context, prodError: true });
27
- */ let ConfigWarning = class ConfigWarning {
28
- /**
29
- * Format a warning message with [Config Warning] prefix.
30
- * In prod mode with prodError: true, throws ConfigError instead.
31
- *
32
- * @param {Object} params - Same as ConfigMessage.format() plus prodError
33
- * @param {boolean} [params.prodError] - If true, throw ConfigError in prod mode
34
- * @returns {string} Formatted warning message or empty string if suppressed
35
- * @throws {ConfigError} When prodError is true and context.stage is 'prod'
36
- */ static format({ prodError, ...params }) {
37
- // In prod, throw error instead of warning if prodError flag is set
38
- if (prodError && params.context?.stage === 'prod') {
39
- throw new ConfigError(params);
40
- }
41
- return ConfigMessage.format({
42
- ...params,
43
- prefix: '[Config Warning]'
44
- });
45
- }
46
- };
47
- export default ConfigWarning;
@@ -1,63 +0,0 @@
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 path from 'path';
16
- /**
17
- * Resolves a config key (~k) to source and config location.
18
- *
19
- * @param {Object} params
20
- * @param {string} params.configKey - The ~k value from the config object
21
- * @param {Object} params.keyMap - The keyMap from build output
22
- * @param {Object} params.refMap - The refMap from build output
23
- * @param {string} [params.configDirectory] - Absolute path to config directory for clickable links
24
- * @returns {Object|null} Location object with source, config, and link, or null if not resolvable
25
- *
26
- * @example
27
- * const location = resolveConfigLocation({
28
- * configKey: 'abc123',
29
- * keyMap: { 'abc123': { key: 'root.pages[0:home].blocks[0:header]', '~r': 'ref1', '~l': 5 } },
30
- * refMap: { 'ref1': { path: 'pages/home.yaml' } },
31
- * configDirectory: '/Users/dev/myapp'
32
- * });
33
- * // Returns: {
34
- * // source: 'pages/home.yaml:5',
35
- * // config: 'root.pages[0:home].blocks[0:header]',
36
- * // link: '/Users/dev/myapp/pages/home.yaml:5'
37
- * // }
38
- */ function resolveConfigLocation({ configKey, keyMap, refMap, configDirectory }) {
39
- if (!configKey || !keyMap || !keyMap[configKey]) {
40
- return null;
41
- }
42
- const keyEntry = keyMap[configKey];
43
- const refId = keyEntry['~r'];
44
- const lineNumber = keyEntry['~l'];
45
- const refEntry = refMap?.[refId];
46
- const filePath = refEntry?.path || 'lowdefy.yaml';
47
- // source: filepath:line (e.g., "lowdefy.yaml:16")
48
- const source = lineNumber ? `${filePath}:${lineNumber}` : filePath;
49
- // config: the config path (e.g., "root.pages[0:home].blocks[0:header]")
50
- const config = keyEntry.key;
51
- // Absolute path for clickable links in VSCode terminal
52
- let link = null;
53
- if (configDirectory) {
54
- const absolutePath = path.resolve(configDirectory, filePath);
55
- link = lineNumber ? `${absolutePath}:${lineNumber}` : absolutePath;
56
- }
57
- return {
58
- source,
59
- config,
60
- link
61
- };
62
- }
63
- export default resolveConfigLocation;