@boltic/cli 1.0.7 → 1.0.8
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/README.md +0 -9
- package/commands/integration.js +7 -256
- package/helper/validation.js +19 -1
- package/package.json +1 -1
- package/templates/component-schemas.js +24 -0
package/README.md
CHANGED
|
@@ -519,15 +519,6 @@ npm install -g @boltic/cli@latest
|
|
|
519
519
|
boltic --version
|
|
520
520
|
```
|
|
521
521
|
|
|
522
|
-
**Development mode troubleshooting**:
|
|
523
|
-
|
|
524
|
-
```bash
|
|
525
|
-
# For contributors using development installation
|
|
526
|
-
npm install # Update dependencies
|
|
527
|
-
npm link # Re-link CLI
|
|
528
|
-
npm test # Run test suite
|
|
529
|
-
```
|
|
530
|
-
|
|
531
522
|
#### 9. Emergency Recovery
|
|
532
523
|
|
|
533
524
|
**If all else fails**:
|
package/commands/integration.js
CHANGED
|
@@ -54,10 +54,6 @@ const commands = {
|
|
|
54
54
|
description: "Show detailed information about an integration",
|
|
55
55
|
action: handleStatus,
|
|
56
56
|
},
|
|
57
|
-
test: {
|
|
58
|
-
description: "Run tests for the integration with coverage",
|
|
59
|
-
action: handleTest,
|
|
60
|
-
},
|
|
61
57
|
help: {
|
|
62
58
|
description: "Show help for integration commands",
|
|
63
59
|
action: showHelp,
|
|
@@ -1064,6 +1060,13 @@ async function handleStatus() {
|
|
|
1064
1060
|
console.log(integration.documentation);
|
|
1065
1061
|
}
|
|
1066
1062
|
} catch (error) {
|
|
1063
|
+
if (
|
|
1064
|
+
error.message &&
|
|
1065
|
+
error.message.includes("User force closed the prompt")
|
|
1066
|
+
) {
|
|
1067
|
+
console.log(chalk.yellow("\n⚠️ Operation cancelled by user"));
|
|
1068
|
+
return;
|
|
1069
|
+
}
|
|
1067
1070
|
console.error(
|
|
1068
1071
|
chalk.red("\n❌ Error fetching integration status:"),
|
|
1069
1072
|
error.message || "Unknown error"
|
|
@@ -1071,258 +1074,6 @@ async function handleStatus() {
|
|
|
1071
1074
|
}
|
|
1072
1075
|
}
|
|
1073
1076
|
|
|
1074
|
-
async function handleTest(args) {
|
|
1075
|
-
// Parse command line arguments
|
|
1076
|
-
let currentDir = process.cwd();
|
|
1077
|
-
let jestConfigFile = null;
|
|
1078
|
-
const pathIndex = args.indexOf("--path");
|
|
1079
|
-
const configIndex = args.indexOf("--config");
|
|
1080
|
-
|
|
1081
|
-
if (pathIndex !== -1 && args[pathIndex + 1]) {
|
|
1082
|
-
currentDir = args[pathIndex + 1];
|
|
1083
|
-
// Validate the provided path
|
|
1084
|
-
if (!fs.existsSync(currentDir)) {
|
|
1085
|
-
console.error(
|
|
1086
|
-
chalk.red(
|
|
1087
|
-
`Error: The specified path does not exist: ${currentDir}`
|
|
1088
|
-
)
|
|
1089
|
-
);
|
|
1090
|
-
return;
|
|
1091
|
-
}
|
|
1092
|
-
}
|
|
1093
|
-
|
|
1094
|
-
if (configIndex !== -1 && args[configIndex + 1]) {
|
|
1095
|
-
jestConfigFile = args[configIndex + 1];
|
|
1096
|
-
// Validate the config file path
|
|
1097
|
-
const configPath = path.isAbsolute(jestConfigFile)
|
|
1098
|
-
? jestConfigFile
|
|
1099
|
-
: path.join(currentDir, jestConfigFile);
|
|
1100
|
-
|
|
1101
|
-
if (!fs.existsSync(configPath)) {
|
|
1102
|
-
console.error(
|
|
1103
|
-
chalk.red(
|
|
1104
|
-
`Error: Jest config file does not exist: ${configPath}`
|
|
1105
|
-
)
|
|
1106
|
-
);
|
|
1107
|
-
return;
|
|
1108
|
-
}
|
|
1109
|
-
}
|
|
1110
|
-
|
|
1111
|
-
const { spawn } = await import("child_process");
|
|
1112
|
-
|
|
1113
|
-
console.log(chalk.cyan.bold("\n🧪 Running integration tests...\n"));
|
|
1114
|
-
|
|
1115
|
-
// Look for test directory and test files
|
|
1116
|
-
const testDirs = ["test", "tests", "__tests__"];
|
|
1117
|
-
let testDir = null;
|
|
1118
|
-
let testFiles = [];
|
|
1119
|
-
|
|
1120
|
-
// Check for test directories
|
|
1121
|
-
for (const dir of testDirs) {
|
|
1122
|
-
const testPath = path.join(currentDir, dir);
|
|
1123
|
-
if (fs.existsSync(testPath)) {
|
|
1124
|
-
testDir = dir;
|
|
1125
|
-
// Find all test files in the directory
|
|
1126
|
-
const files = fs.readdirSync(testPath);
|
|
1127
|
-
testFiles = files.filter(
|
|
1128
|
-
(file) =>
|
|
1129
|
-
file.endsWith(".test.js") ||
|
|
1130
|
-
file.endsWith(".spec.js") ||
|
|
1131
|
-
file.endsWith(".test.ts") ||
|
|
1132
|
-
file.endsWith(".spec.ts")
|
|
1133
|
-
);
|
|
1134
|
-
break;
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
|
|
1138
|
-
// If no test directory found, look for test files in current directory
|
|
1139
|
-
if (!testDir) {
|
|
1140
|
-
const currentDirFiles = fs.readdirSync(currentDir);
|
|
1141
|
-
testFiles = currentDirFiles.filter(
|
|
1142
|
-
(file) =>
|
|
1143
|
-
file.endsWith(".test.js") ||
|
|
1144
|
-
file.endsWith(".spec.js") ||
|
|
1145
|
-
file.endsWith(".test.ts") ||
|
|
1146
|
-
file.endsWith(".spec.ts")
|
|
1147
|
-
);
|
|
1148
|
-
|
|
1149
|
-
if (testFiles.length === 0) {
|
|
1150
|
-
console.log(
|
|
1151
|
-
chalk.yellow(
|
|
1152
|
-
"⚠️ No test files found. Looked for: test, tests, __tests__ directories and *.test.js, *.spec.js, *.test.ts, *.spec.ts files"
|
|
1153
|
-
)
|
|
1154
|
-
);
|
|
1155
|
-
return;
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
|
|
1159
|
-
if (testFiles.length === 0 && testDir) {
|
|
1160
|
-
console.log(
|
|
1161
|
-
chalk.yellow(
|
|
1162
|
-
`⚠️ No test files found in ${testDir} directory. Looking for: *.test.js, *.spec.js, *.test.ts, *.spec.ts files`
|
|
1163
|
-
)
|
|
1164
|
-
);
|
|
1165
|
-
return;
|
|
1166
|
-
}
|
|
1167
|
-
|
|
1168
|
-
console.log(chalk.dim(`📁 Found test directory: ${testDir || currentDir}`));
|
|
1169
|
-
console.log(
|
|
1170
|
-
chalk.dim(
|
|
1171
|
-
`📋 Found ${testFiles.length} test file(s): ${testFiles.join(", ")}`
|
|
1172
|
-
)
|
|
1173
|
-
);
|
|
1174
|
-
|
|
1175
|
-
// Check for Jest configuration
|
|
1176
|
-
let jestConfigPath;
|
|
1177
|
-
if (jestConfigFile) {
|
|
1178
|
-
jestConfigPath = path.isAbsolute(jestConfigFile)
|
|
1179
|
-
? jestConfigFile
|
|
1180
|
-
: path.join(currentDir, jestConfigFile);
|
|
1181
|
-
} else {
|
|
1182
|
-
// Look for default config files
|
|
1183
|
-
const defaultConfigs = [
|
|
1184
|
-
"jest.config.cjs",
|
|
1185
|
-
"jest.config.js",
|
|
1186
|
-
"jest.config.json",
|
|
1187
|
-
];
|
|
1188
|
-
for (const configFile of defaultConfigs) {
|
|
1189
|
-
const configPath = path.join(currentDir, configFile);
|
|
1190
|
-
if (fs.existsSync(configPath)) {
|
|
1191
|
-
jestConfigPath = configPath;
|
|
1192
|
-
break;
|
|
1193
|
-
}
|
|
1194
|
-
}
|
|
1195
|
-
}
|
|
1196
|
-
|
|
1197
|
-
const jestConfigExists = !!jestConfigPath;
|
|
1198
|
-
const configFileName = jestConfigPath
|
|
1199
|
-
? path.basename(jestConfigPath)
|
|
1200
|
-
: null;
|
|
1201
|
-
|
|
1202
|
-
console.log(
|
|
1203
|
-
chalk.dim(
|
|
1204
|
-
`⚙️ Jest configuration: ${jestConfigExists ? `Found ${configFileName}` : "Using default configuration"}`
|
|
1205
|
-
)
|
|
1206
|
-
);
|
|
1207
|
-
|
|
1208
|
-
// Prepare Jest arguments
|
|
1209
|
-
const jestArgs = ["jest"];
|
|
1210
|
-
|
|
1211
|
-
// Add basic Jest flags
|
|
1212
|
-
jestArgs.push("--coverage");
|
|
1213
|
-
jestArgs.push("--verbose");
|
|
1214
|
-
jestArgs.push("--colors");
|
|
1215
|
-
jestArgs.push("--passWithNoTests");
|
|
1216
|
-
|
|
1217
|
-
// Add config file if exists, otherwise use simple patterns
|
|
1218
|
-
if (jestConfigExists) {
|
|
1219
|
-
jestArgs.push("--config", jestConfigPath);
|
|
1220
|
-
} else {
|
|
1221
|
-
// Use simple test matching patterns
|
|
1222
|
-
if (testDir) {
|
|
1223
|
-
jestArgs.push(
|
|
1224
|
-
"--testMatch",
|
|
1225
|
-
`**/${testDir}/**/*.{test,spec}.{js,ts}`
|
|
1226
|
-
);
|
|
1227
|
-
} else {
|
|
1228
|
-
jestArgs.push("--testMatch", "**/*.{test,spec}.{js,ts}");
|
|
1229
|
-
}
|
|
1230
|
-
jestArgs.push("--collectCoverageFrom", "lib/**/*.{js,ts}");
|
|
1231
|
-
jestArgs.push("--collectCoverageFrom", "src/**/*.{js,ts}");
|
|
1232
|
-
jestArgs.push("--collectCoverageFrom", "*.{js,ts}");
|
|
1233
|
-
jestArgs.push("--coveragePathIgnorePatterns", "/node_modules/");
|
|
1234
|
-
jestArgs.push("--coveragePathIgnorePatterns", "/tests/");
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
// Add any additional Jest arguments passed by user
|
|
1238
|
-
const additionalArgs = args.filter((arg, index) => {
|
|
1239
|
-
// Skip our custom flags and their values
|
|
1240
|
-
if (arg === "--path" || arg === "--config") return false;
|
|
1241
|
-
if (args[index - 1] === "--path" || args[index - 1] === "--config")
|
|
1242
|
-
return false;
|
|
1243
|
-
return true;
|
|
1244
|
-
});
|
|
1245
|
-
|
|
1246
|
-
if (additionalArgs.length > 0) {
|
|
1247
|
-
jestArgs.push(...additionalArgs);
|
|
1248
|
-
console.log(
|
|
1249
|
-
chalk.dim(
|
|
1250
|
-
`🔧 Additional Jest arguments: ${additionalArgs.join(" ")}`
|
|
1251
|
-
)
|
|
1252
|
-
);
|
|
1253
|
-
}
|
|
1254
|
-
|
|
1255
|
-
console.log(chalk.dim(`🚀 Running command: npx ${jestArgs.join(" ")}`));
|
|
1256
|
-
console.log(chalk.cyan("─".repeat(50)));
|
|
1257
|
-
|
|
1258
|
-
// Run Jest with coverage
|
|
1259
|
-
return new Promise((resolve, reject) => {
|
|
1260
|
-
const jestProcess = spawn("npx", jestArgs, {
|
|
1261
|
-
stdio: "inherit",
|
|
1262
|
-
shell: true,
|
|
1263
|
-
cwd: currentDir,
|
|
1264
|
-
});
|
|
1265
|
-
|
|
1266
|
-
jestProcess.on("close", (code) => {
|
|
1267
|
-
console.log(chalk.cyan("─".repeat(50)));
|
|
1268
|
-
|
|
1269
|
-
if (code === 0) {
|
|
1270
|
-
console.log(chalk.green.bold("\n✅ All tests passed!"));
|
|
1271
|
-
|
|
1272
|
-
// Check for coverage directory
|
|
1273
|
-
const coverageDir = path.join(currentDir, "coverage");
|
|
1274
|
-
if (fs.existsSync(coverageDir)) {
|
|
1275
|
-
console.log(chalk.cyan("\n📊 Coverage Report Generated:"));
|
|
1276
|
-
console.log(chalk.dim(` Directory: ${coverageDir}`));
|
|
1277
|
-
|
|
1278
|
-
// Check for HTML report
|
|
1279
|
-
const htmlReportPath = path.join(
|
|
1280
|
-
coverageDir,
|
|
1281
|
-
"lcov-report",
|
|
1282
|
-
"index.html"
|
|
1283
|
-
);
|
|
1284
|
-
if (fs.existsSync(htmlReportPath)) {
|
|
1285
|
-
console.log(
|
|
1286
|
-
chalk.dim(` HTML Report: ${htmlReportPath}`)
|
|
1287
|
-
);
|
|
1288
|
-
}
|
|
1289
|
-
|
|
1290
|
-
// Check for text report
|
|
1291
|
-
const textReportPath = path.join(coverageDir, "lcov.info");
|
|
1292
|
-
if (fs.existsSync(textReportPath)) {
|
|
1293
|
-
console.log(
|
|
1294
|
-
chalk.dim(` LCOV Report: ${textReportPath}`)
|
|
1295
|
-
);
|
|
1296
|
-
}
|
|
1297
|
-
}
|
|
1298
|
-
|
|
1299
|
-
// Show test summary
|
|
1300
|
-
console.log(chalk.cyan("\n📋 Test Summary:"));
|
|
1301
|
-
console.log(chalk.dim(` Test files: ${testFiles.length}`));
|
|
1302
|
-
console.log(
|
|
1303
|
-
chalk.dim(` Test directory: ${testDir || currentDir}`)
|
|
1304
|
-
);
|
|
1305
|
-
console.log(chalk.green(" Status: PASSED"));
|
|
1306
|
-
} else {
|
|
1307
|
-
console.log(chalk.red.bold("\n❌ Some tests failed."));
|
|
1308
|
-
console.log(chalk.red(` Exit code: ${code}`));
|
|
1309
|
-
}
|
|
1310
|
-
|
|
1311
|
-
console.log(
|
|
1312
|
-
chalk.cyan(
|
|
1313
|
-
"\n💡 Tip: Check the coverage directory for detailed coverage reports"
|
|
1314
|
-
)
|
|
1315
|
-
);
|
|
1316
|
-
resolve(code);
|
|
1317
|
-
});
|
|
1318
|
-
|
|
1319
|
-
jestProcess.on("error", (error) => {
|
|
1320
|
-
console.error(chalk.red("❌ Error running tests:"), error.message);
|
|
1321
|
-
reject(error);
|
|
1322
|
-
});
|
|
1323
|
-
});
|
|
1324
|
-
}
|
|
1325
|
-
|
|
1326
1077
|
export default {
|
|
1327
1078
|
execute,
|
|
1328
1079
|
};
|
package/helper/validation.js
CHANGED
|
@@ -150,6 +150,17 @@ const validateSchemaKeys = (
|
|
|
150
150
|
Object.keys(schemaObj).forEach((key) => {
|
|
151
151
|
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
152
152
|
|
|
153
|
+
// Special handling for config.body - skip validation for select, autocomplete, and multiselect
|
|
154
|
+
if (
|
|
155
|
+
fullKey === "config.body" &&
|
|
156
|
+
(displayType === "select" ||
|
|
157
|
+
displayType === "autocomplete" ||
|
|
158
|
+
displayType === "multiselect")
|
|
159
|
+
) {
|
|
160
|
+
// For these display types, config.body can contain any keys, so we skip validation
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
153
164
|
if (!allowedKeys.has(fullKey)) {
|
|
154
165
|
errors.add(
|
|
155
166
|
`"${schemaName}" has an invalid key "${fullKey}" for displayType "${displayType}"${fileLabel}.`
|
|
@@ -159,7 +170,14 @@ const validateSchemaKeys = (
|
|
|
159
170
|
if (
|
|
160
171
|
typeof schemaObj[key] === "object" &&
|
|
161
172
|
schemaObj[key] !== null &&
|
|
162
|
-
!Array.isArray(schemaObj[key])
|
|
173
|
+
!Array.isArray(schemaObj[key]) &&
|
|
174
|
+
// Skip recursion for config.body of select/autocomplete/multiselect
|
|
175
|
+
!(
|
|
176
|
+
fullKey === "config.body" &&
|
|
177
|
+
(displayType === "select" ||
|
|
178
|
+
displayType === "autocomplete" ||
|
|
179
|
+
displayType === "multiselect")
|
|
180
|
+
)
|
|
163
181
|
) {
|
|
164
182
|
validateSchemaKeys(
|
|
165
183
|
schemaObj[key],
|
package/package.json
CHANGED
|
@@ -914,6 +914,29 @@ const button = {
|
|
|
914
914
|
},
|
|
915
915
|
};
|
|
916
916
|
|
|
917
|
+
const datetime = {
|
|
918
|
+
name: "datetime-picker",
|
|
919
|
+
meta: {
|
|
920
|
+
displayName: "Enter Date with Start Time",
|
|
921
|
+
description: "Please enter date and start time",
|
|
922
|
+
displayType: "datetime",
|
|
923
|
+
value: "2024-02-14",
|
|
924
|
+
validation: {
|
|
925
|
+
required: false,
|
|
926
|
+
},
|
|
927
|
+
readOnly: false,
|
|
928
|
+
htmlProps: {
|
|
929
|
+
format: "YYYY-MM-DD HH:mm:ss",
|
|
930
|
+
disabled: false,
|
|
931
|
+
timeSteps: {
|
|
932
|
+
hours: 1,
|
|
933
|
+
minutes: 5,
|
|
934
|
+
seconds: 5,
|
|
935
|
+
},
|
|
936
|
+
},
|
|
937
|
+
},
|
|
938
|
+
};
|
|
939
|
+
|
|
917
940
|
export {
|
|
918
941
|
accordion,
|
|
919
942
|
array,
|
|
@@ -922,6 +945,7 @@ export {
|
|
|
922
945
|
checkbox,
|
|
923
946
|
code,
|
|
924
947
|
date,
|
|
948
|
+
datetime,
|
|
925
949
|
divider,
|
|
926
950
|
email,
|
|
927
951
|
file,
|