alwaysai
Version:
The alwaysAI command-line interface (CLI)
149 lines • 7.57 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.testSuiteFuncs = exports.validatePackageComponent = exports.modelValidatePackage = void 0;
const alwayscli_1 = require("@alwaysai/alwayscli");
const fs_1 = require("fs");
const path_1 = require("path");
const model_id_1 = require("../../core/model/model-id");
const model_package_json_file_1 = require("../../core/model/model-package-json-file");
const echo_1 = require("../../util/echo");
const logger_1 = require("../../util/logger");
const logSymbols = require("log-symbols");
const constants_1 = require("../../constants");
const util_1 = require("../../util");
exports.modelValidatePackage = (0, alwayscli_1.CliLeaf)({
name: 'validate-package',
description: 'Validate integrity of the alwaysai.model.json file in the current directory.',
async action() {
if ((await validatePackageComponent()) === false) {
throw new alwayscli_1.CliTerseError('Failed to validate model package. See above logs for details');
}
}
});
async function validatePackageComponent(dir) {
let success = false;
// If no directory for modelConfig is provided, then check in current directory.
const modelConfigDir = dir ? dir : process.cwd();
(0, echo_1.echo)(`Validating the model package file...`);
if (!(0, model_package_json_file_1.ModelPackageJsonFile)(modelConfigDir).exists()) {
throw new alwayscli_1.CliTerseError(`${logSymbols.error} Could not find the model package file.`);
}
const modelFile = (0, model_package_json_file_1.ModelPackageJsonFile)(modelConfigDir);
let modelConfig = undefined;
try {
modelConfig = modelFile.read();
(0, echo_1.echo)(`${logSymbols.success} Successfully validated configuration data types.`);
}
catch (err) {
logger_1.logger.error(`Read model JSON failed: ${(0, util_1.stringifyError)(err)}`);
const errors = JSON.stringify(modelFile.getErrors(), null, 2);
if (err.name === 'SyntaxError') {
(0, echo_1.echo)(`${logSymbols.warning} Could not validate the configuration file. Please check the JSON syntax of the configuration file.`);
}
else if (errors !== null) {
(0, echo_1.echo)(`${logSymbols.warning} Could not validate the configuration. Possible issues with the configuration file fields: \n`);
// User friendly error handling:
const skipArray = ['if', 'oneOf'];
logger_1.logger.error(errors);
JSON.parse(errors).forEach((error) => {
if (!skipArray.some((v) => error.keyword.includes(v))) {
switch (error.keyword) {
case 'maxItems':
case 'minItems':
case 'type':
case 'required':
(0, echo_1.echo)(`${logSymbols.error} ${error.instancePath} ${error.message}`);
break;
case 'unevaluatedProperties':
(0, echo_1.echo)(`${logSymbols.error} ${error.instancePath} ${error.message}: ${error.params['unevaluatedProperty']}`);
break;
case 'enum':
(0, echo_1.echo)(`${logSymbols.error} ${error.instancePath} ${error.message}: ${error.params['allowedValues']}`);
break;
case 'additionalProperties':
(0, echo_1.echo)(`${logSymbols.error} ${error.instancePath} ${error.message}: ${error.params['additionalProperty']}`);
break;
// Currently, the only field that has pattern validation is the id field, therefore this message is only for that field. IMO ambiguity on which field would have incorrect regex pattern is unneeded, and if in the future we add more regex patterns to the validation, we can change this error message to fit that.
case 'pattern':
(0, echo_1.echo)(`${logSymbols.error} ${error.instancePath} cannot contain special characters, and must be in the form of publisher/name format.`);
break;
default:
(0, echo_1.echo)(error);
break;
}
}
});
}
else {
throw new alwayscli_1.CliTerseError(`Unexpected model validation error occurred! ${constants_1.PLEASE_REPORT_THIS_ERROR_MESSAGE}\n${err}`);
}
// Skip further checks if model config doesn't pass initial validation
return false;
}
if (modelConfig === undefined) {
// This should never occur
throw new alwayscli_1.CliTerseError(`Model configuration was not loaded! ${constants_1.PLEASE_REPORT_THIS_ERROR_MESSAGE}`);
}
const idCheck = await checkIdVariable(modelConfig.id);
const variableCheck = await checkVariableFilepath(modelConfig);
if (idCheck && variableCheck) {
(0, echo_1.echo)(`${logSymbols.success} Validation successful.`);
success = true;
}
return success;
}
exports.validatePackageComponent = validatePackageComponent;
async function checkIdVariable(id) {
try {
model_id_1.ModelId.parse(id);
(0, echo_1.echo)(`${logSymbols.success} Successfully validated the Model ID.`);
return true;
}
catch (err) {
(0, echo_1.echo)(`${logSymbols.warning} ${(0, util_1.stringifyError)(err)}`);
return false;
}
}
async function checkVariableFilepath(modelJson) {
let success = true;
const cwd = process.cwd();
// The variables in the model json file that have a verifiable filepath.
const filepathVariables = {
config_file: modelJson.model_parameters.config_file,
label_file: modelJson.model_parameters.label_file,
color_file: modelJson.model_parameters.color_file,
model_file: modelJson.model_parameters.model_file
};
for (const key in filepathVariables) {
const value = filepathVariables[key];
// Skip keys not found in the file or set to null
if (value === undefined || value === null) {
continue;
}
if (value.includes('..') || value === '') {
success = false;
(0, echo_1.echo)(`${logSymbols.warning} "${value}" does not seem to be a valid file path to the ${key}. Please use relative filepath.`);
continue;
}
else if ((0, fs_1.existsSync)((0, path_1.join)(cwd, value))) {
// otherwise check if it exists within the current working directory
(0, echo_1.echo)(`${logSymbols.success} Successfully checked the "${key}" file path.`);
}
else {
// otherwise, check if it exists anywhere in the fs and give warning
success = false;
if ((0, fs_1.existsSync)(value)) {
(0, echo_1.echo)(`${logSymbols.warning} "${value}" is not in the current working directory. Please make sure all model files are within model directory.`);
}
else {
// otherwise, it doesn't exist or is invalid, so give warning
(0, echo_1.echo)(`${logSymbols.warning} "${value}" does not seem to be a valid file path to the ${key}.`);
}
}
}
return success;
}
exports.testSuiteFuncs = {
validatePackageComponent
};
//# sourceMappingURL=validate-package.js.map