UNPKG

bit-bin

Version:

<a href="https://opensource.org/licenses/Apache-2.0"><img alt="apache" src="https://img.shields.io/badge/License-Apache%202.0-blue.svg"></a> <a href="https://github.com/teambit/bit/blob/master/CONTRIBUTING.md"><img alt="prs" src="https://img.shields.io/b

442 lines (328 loc) 15.2 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = validateVersionInstance; function _ramda() { const data = _interopRequireDefault(require("ramda")); _ramda = function () { return data; }; return data; } function _packageJsonValidator() { const data = require("package-json-validator"); _packageJsonValidator = function () { return data; }; return data; } function _validateNpmPackageName() { const data = _interopRequireDefault(require("validate-npm-package-name")); _validateNpmPackageName = function () { return data; }; return data; } function _validateType() { const data = _interopRequireDefault(require("../utils/validate-type")); _validateType = function () { return data; }; return data; } function _bitId() { const data = require("../bit-id"); _bitId = function () { return data; }; return data; } function _versionInvalid() { const data = _interopRequireDefault(require("./exceptions/version-invalid")); _versionInvalid = function () { return data; }; return data; } function _utils() { const data = require("../utils"); _utils = function () { return data; }; return data; } function _dependencies() { const data = require("../consumer/component/dependencies"); _dependencies = function () { return data; }; return data; } function _packageJsonFile() { const data = _interopRequireDefault(require("../consumer/component/package-json-file")); _packageJsonFile = function () { return data; }; return data; } function _consumerOverrides() { const data = require("../consumer/config/consumer-overrides"); _consumerOverrides = function () { return data; }; return data; } function _componentOverrides() { const data = require("../consumer/config/component-overrides"); _componentOverrides = function () { return data; }; return data; } function _dependencies2() { const data = require("../consumer/component/dependencies/dependencies"); _dependencies2 = function () { return data; }; return data; } function _constants() { const data = require("../constants"); _constants = function () { return data; }; return data; } function _generalError() { const data = _interopRequireDefault(require("../error/general-error")); _generalError = function () { return data; }; return data; } /** * make sure a Version instance is correct. throw an exceptions if it is not. */ function validateVersionInstance(version) { const message = 'unable to save Version object'; const validateBitId = (bitId, field, validateVersion = true, validateScope = true) => { if (validateVersion && !bitId.hasVersion()) { throw new (_versionInvalid().default)(`${message}, the ${field} ${bitId.toString()} does not have a version`); } if (validateScope && !bitId.scope) { throw new (_versionInvalid().default)(`${message}, the ${field} ${bitId.toString()} does not have a scope`); } }; const validateBitIdStr = (bitIdStr, field, validateVersion = true, validateScope = true) => { (0, _validateType().default)(message, bitIdStr, field, 'string'); let bitId; try { bitId = _bitId().BitId.parse(bitIdStr, true); } catch (err) { throw new (_versionInvalid().default)(`${message}, the ${field} has an invalid Bit id`); } validateBitId(bitId, field, validateVersion, validateScope); }; const _validateEnv = env => { if (!env) return; if (typeof env === 'string') { // Do not validate version - for backward compatibility validateBitIdStr(env, 'environment-id', false); return; } (0, _validateType().default)(message, env, 'env', 'object'); if (!env.name) { throw new (_versionInvalid().default)(`${message}, the environment is missing the name attribute`); } validateBitIdStr(env.name, 'env.name'); if (env.files) { const compilerName = env.name || ''; env.files.forEach(file => { if (!file.name) { throw new (_versionInvalid().default)(`${message}, the environment ${compilerName} has a file which missing the name attribute`); } }); } }; /** * Validate that the package name and version are valid * @param {*} packageName * @param {*} packageVersion */ const _validatePackageDependency = (packageVersion, packageName) => { const packageNameValidateResult = (0, _validateNpmPackageName().default)(packageName); if (!packageNameValidateResult.validForNewPackages && !packageNameValidateResult.validForOldPackages) { const errors = packageNameValidateResult.errors || []; throw new (_versionInvalid().default)(`${packageName} is invalid package name, errors: ${errors.join()}`); } // don't use semver.valid and semver.validRange to validate the package version because it // can be also a URL, Git URL or Github URL. see here: https://docs.npmjs.com/files/package.json#dependencies (0, _validateType().default)(message, packageVersion, `version of "${packageName}"`, 'string'); }; const _validatePackageDependencies = packageDependencies => { (0, _validateType().default)(message, packageDependencies, 'packageDependencies', 'object'); _ramda().default.forEachObjIndexed(_validatePackageDependency, packageDependencies); }; const _validateEnvPackages = (envPackages, fieldName) => { (0, _validateType().default)(message, envPackages, fieldName, 'object'); Object.keys(envPackages).forEach(dependencyType => { if (!_constants().DEPENDENCIES_FIELDS.includes(dependencyType)) { throw new (_versionInvalid().default)(`${message}, the property ${dependencyType} inside ${fieldName} is invalid, allowed values are ${_constants().DEPENDENCIES_FIELDS.join(', ')}`); } (0, _validateType().default)(message, envPackages[dependencyType], `${fieldName}.${dependencyType}`, 'object'); Object.keys(envPackages[dependencyType]).forEach(pkg => { (0, _validateType().default)(message, envPackages[dependencyType][pkg], `${fieldName}.${dependencyType}.${pkg}`, 'string'); }); }); }; const validateFile = (file, field) => { (0, _validateType().default)(message, file, field, 'object'); if (!(0, _utils().isValidPath)(file.relativePath)) { throw new (_versionInvalid().default)(`${message}, the ${field} ${file.relativePath} is invalid`); } if (!file.name && field !== 'artifact') { throw new (_versionInvalid().default)(`${message}, the ${field} ${file.relativePath} is missing the name attribute`); } if (!file.file) throw new (_versionInvalid().default)(`${message}, the ${field} ${file.relativePath} is missing the hash`); if (file.name) (0, _validateType().default)(message, file.name, `${field}.name`, 'string'); (0, _validateType().default)(message, file.file, `${field}.file`, 'object'); (0, _validateType().default)(message, file.file.hash, `${field}.file.hash`, 'string'); }; const _validateExtension = extension => { if (extension.extensionId) { validateBitId(extension.extensionId, `extensions.${extension.extensionId.toString()}`, true, false); } extension.artifacts.map(artifact => validateFile(artifact, 'artifact')); }; const _validateExtensions = extensions => { if (extensions) { extensions.map(_validateExtension); } }; if (!version.mainFile) throw new (_versionInvalid().default)(`${message}, the mainFile is missing`); if (!(0, _utils().isValidPath)(version.mainFile)) { throw new (_versionInvalid().default)(`${message}, the mainFile ${version.mainFile} is invalid`); } if (!version.files || !version.files.length) throw new (_versionInvalid().default)(`${message}, the files are missing`); let foundMainFile = false; (0, _validateType().default)(message, version.files, 'files', 'array'); const filesPaths = []; version.files.forEach(file => { validateFile(file, 'file'); filesPaths.push(file.relativePath); if (file.relativePath === version.mainFile) foundMainFile = true; }); if (!foundMainFile) { throw new (_versionInvalid().default)(`${message}, unable to find the mainFile ${version.mainFile} in the following files list: ${filesPaths.join(', ')}`); } const duplicateFiles = filesPaths.filter(file => filesPaths.filter(f => file.toLowerCase() === f.toLowerCase()).length > 1); if (duplicateFiles.length) { throw new (_versionInvalid().default)(`${message} the following files are duplicated ${duplicateFiles.join(', ')}`); } _validateEnv(version.compiler); _validateEnv(version.tester); _validatePackageDependencies(version.packageDependencies); _validatePackageDependencies(version.devPackageDependencies); _validatePackageDependencies(version.peerPackageDependencies); _validateEnvPackages(version.compilerPackageDependencies, 'compilerPackageDependencies'); _validateEnvPackages(version.testerPackageDependencies, 'testerPackageDependencies'); _validateExtensions(version.extensions); if (version.dists && version.dists.length) { (0, _validateType().default)(message, version.dists, 'dist', 'array'); version.dists.forEach(file => { validateFile(file, 'dist-file'); }); } else if (version.mainDistFile) { throw new (_versionInvalid().default)(`${message} the mainDistFile cannot be set when the dists are empty`); } if (version.mainDistFile && !(0, _utils().isValidPath)(version.mainDistFile)) { throw new (_versionInvalid().default)(`${message}, the mainDistFile ${version.mainDistFile} is invalid`); } _dependencies2().DEPENDENCIES_TYPES.forEach(dependenciesType => { if (!(version[dependenciesType] instanceof _dependencies().Dependencies)) { throw new (_versionInvalid().default)(`${message}, ${dependenciesType} must be an instance of Dependencies, got ${typeof version[dependenciesType]}`); } }); version.dependencies.validate(); version.devDependencies.validate(); if (!version.dependencies.isEmpty() && !version.flattenedDependencies.length) { throw new (_versionInvalid().default)(`${message}, it has dependencies but its flattenedDependencies is empty`); } if (!version.devDependencies.isEmpty() && !version.flattenedDevDependencies.length) { throw new (_versionInvalid().default)(`${message}, it has devDependencies but its flattenedDevDependencies is empty`); } const validateFlattenedDependencies = dependencies => { (0, _validateType().default)(message, dependencies, 'dependencies', 'array'); dependencies.forEach(dependency => { if (!(dependency instanceof _bitId().BitId)) { throw new (_versionInvalid().default)(`${message}, a flattenedDependency expected to be BitId, got ${typeof dependency}`); } if (!dependency.hasVersion()) { throw new (_versionInvalid().default)(`${message}, the flattenedDependency ${dependency.toString()} does not have a version`); } }); }; validateFlattenedDependencies(version.flattenedDependencies); validateFlattenedDependencies(version.flattenedDevDependencies); // extensions can be duplicate with other dependencies type. e.g. "test" can have "compile" as a // dependency and extensionDependency. we can't remove it from extDep, otherwise, the ext won't // be running const allDependenciesIds = version.getDependenciesIdsExcludeExtensions(); const depsDuplications = allDependenciesIds.findDuplicationsIgnoreVersion(); if (!_ramda().default.isEmpty(depsDuplications)) { const duplicationStr = Object.keys(depsDuplications).map(id => `"${id}" shows as the following: ${depsDuplications[id].map(depId => depId.toString()).join(', ')} `).join('\n'); throw new (_generalError().default)(`some dependencies are duplicated, see details below. if you added a dependency to "overrides" configuration with a plus sign, make sure to add it with a minus sign in the other dependency type for example, { dependencies: { "bar/foo": "+" }, devDependencies: { "bar/foo": "-" } } ${duplicationStr}`); // todo: once decided how to address duplicate dependencies, remove the line above and uncomment the line below // throw new VersionInvalid(`${message}, some dependencies are duplicated:\n${duplicationStr}`); } if (!version.log) throw new (_versionInvalid().default)(`${message}, the log object is missing`); (0, _validateType().default)(message, version.log, 'log', 'object'); if (version.bindingPrefix) { (0, _validateType().default)(message, version.bindingPrefix, 'bindingPrefix', 'string'); } const npmSpecs = _packageJsonValidator().PJV.getSpecMap('npm'); const validatePackageJsonField = (fieldName, fieldValue) => { if (!npmSpecs[fieldName]) { // it's not a standard package.json field, can't validate return null; } const validateResult = _packageJsonValidator().PJV.validateType(fieldName, npmSpecs[fieldName], fieldValue); if (!validateResult.length) return null; return validateResult.join(', '); }; const validateOverrides = (fieldValue, fieldName) => { const field = `overrides.${fieldName}`; if (_constants().DEPENDENCIES_FIELDS.includes(fieldName)) { (0, _validateType().default)(message, fieldValue, field, 'object'); Object.keys(fieldValue).forEach(key => { (0, _validateType().default)(message, key, `property name of ${field}`, 'string'); (0, _validateType().default)(message, fieldValue[key], `version of "${field}.${key}"`, 'string'); }); } else if (!_consumerOverrides().nonPackageJsonFields.includes(fieldName)) { const result = validatePackageJsonField(fieldName, fieldValue); if (result) { throw new (_versionInvalid().default)(`${message}, "${field}" is a package.json field but is not compliant with npm requirements. ${result}`); } } }; Object.keys(version.overrides).forEach(field => { if (_componentOverrides().componentOverridesForbiddenFields.includes(field)) { throw new (_versionInvalid().default)(`${message}, the "overrides" has a forbidden key "${field}"`); } validateOverrides(version.overrides[field], field); }); (0, _validateType().default)(message, version.packageJsonChangedProps, 'packageJsonChangedProps', 'object'); const forbiddenPackageJsonProps = _packageJsonFile().default.propsNonUserChangeable(); Object.keys(version.packageJsonChangedProps).forEach(prop => { (0, _validateType().default)(message, prop, 'property name of packageJson', 'string'); if (forbiddenPackageJsonProps.includes(prop)) { throw new (_versionInvalid().default)(`${message}, the packageJsonChangedProps should not override the prop ${prop}`); } const result = validatePackageJsonField(prop, version.packageJsonChangedProps[prop]); if (result) { throw new (_versionInvalid().default)(`${message}, the generated package.json field "${prop}" is not compliant with npm requirements. ${result}`); } }); }