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
1,300 lines (995 loc) • 46.4 kB
JavaScript
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
function _bluebird() {
const data = require("bluebird");
_bluebird = function () {
return data;
};
return data;
}
function _defineProperty2() {
const data = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
_defineProperty2 = function () {
return data;
};
return data;
}
function path() {
const data = _interopRequireWildcard(require("path"));
path = function () {
return data;
};
return data;
}
function _fsExtra() {
const data = _interopRequireDefault(require("fs-extra"));
_fsExtra = function () {
return data;
};
return data;
}
function _ramda() {
const data = _interopRequireDefault(require("ramda"));
_ramda = function () {
return data;
};
return data;
}
function _stringFormat() {
const data = _interopRequireDefault(require("string-format"));
_stringFormat = function () {
return data;
};
return data;
}
function _lodash() {
const data = _interopRequireDefault(require("lodash.assignwith"));
_lodash = function () {
return data;
};
return data;
}
function _lodash2() {
const data = _interopRequireDefault(require("lodash.groupby"));
_lodash2 = function () {
return data;
};
return data;
}
function _lodash3() {
const data = _interopRequireDefault(require("lodash.unionby"));
_lodash3 = function () {
return data;
};
return data;
}
function _ignore() {
const data = _interopRequireDefault(require("ignore"));
_ignore = function () {
return data;
};
return data;
}
function _arrayDifference() {
const data = _interopRequireDefault(require("array-difference"));
_arrayDifference = function () {
return data;
};
return data;
}
function _analytics() {
const data = require("../../../analytics/analytics");
_analytics = function () {
return data;
};
return data;
}
function _utils() {
const data = require("../../../utils");
_utils = function () {
return data;
};
return data;
}
function _bitId() {
const data = require("../../../bit-id");
_bitId = function () {
return data;
};
return data;
}
function _constants() {
const data = require("../../../constants");
_constants = function () {
return data;
};
return data;
}
function _logger() {
const data = _interopRequireDefault(require("../../../logger/logger"));
_logger = function () {
return data;
};
return data;
}
function _exceptions() {
const data = require("./exceptions");
_exceptions = function () {
return data;
};
return data;
}
function _componentMap() {
const data = _interopRequireDefault(require("../../bit-map/component-map"));
_componentMap = function () {
return data;
};
return data;
}
function _path2() {
const data = require("../../../utils/path");
_path2 = function () {
return data;
};
return data;
}
function _generalError() {
const data = _interopRequireDefault(require("../../../error/general-error"));
_generalError = function () {
return data;
};
return data;
}
function _versionShouldBeRemoved() {
const data = _interopRequireDefault(require("./exceptions/version-should-be-removed"));
_versionShouldBeRemoved = function () {
return data;
};
return data;
}
function _linkContent() {
const data = require("../../../links/link-content");
_linkContent = function () {
return data;
};
return data;
}
function _missingMainFile() {
const data = _interopRequireDefault(require("../../bit-map/exceptions/missing-main-file"));
_missingMainFile = function () {
return data;
};
return data;
}
function _missingMainFileMultipleComponents() {
const data = _interopRequireDefault(require("./exceptions/missing-main-file-multiple-components"));
_missingMainFileMultipleComponents = function () {
return data;
};
return data;
}
function _pathOutsideConsumer() {
const data = _interopRequireDefault(require("./exceptions/path-outside-consumer"));
_pathOutsideConsumer = function () {
return data;
};
return data;
}
function _determineMainFile() {
const data = _interopRequireDefault(require("./determine-main-file"));
_determineMainFile = function () {
return data;
};
return data;
}
function _showDoctorError() {
const data = _interopRequireDefault(require("../../../error/show-doctor-error"));
_showDoctorError = function () {
return data;
};
return data;
}
function _addingIndividualFiles() {
const data = require("./exceptions/adding-individual-files");
_addingIndividualFiles = function () {
return data;
};
return data;
}
const REGEX_DSL_PATTERN = /{([^}]+)}/g;
class AddComponents {
// id entered by the user
// (default = false) replace the files array or only add files.
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
constructor(context, addProps) {
(0, _defineProperty2().default)(this, "consumer", void 0);
(0, _defineProperty2().default)(this, "bitMap", void 0);
(0, _defineProperty2().default)(this, "componentPaths", void 0);
(0, _defineProperty2().default)(this, "id", void 0);
(0, _defineProperty2().default)(this, "main", void 0);
(0, _defineProperty2().default)(this, "namespace", void 0);
(0, _defineProperty2().default)(this, "tests", void 0);
(0, _defineProperty2().default)(this, "exclude", void 0);
(0, _defineProperty2().default)(this, "override", void 0);
(0, _defineProperty2().default)(this, "trackDirFeature", void 0);
(0, _defineProperty2().default)(this, "warnings", void 0);
(0, _defineProperty2().default)(this, "ignoreList", void 0);
(0, _defineProperty2().default)(this, "gitIgnore", void 0);
(0, _defineProperty2().default)(this, "origin", void 0);
(0, _defineProperty2().default)(this, "alternateCwd", void 0);
(0, _defineProperty2().default)(this, "addedComponents", void 0);
this.alternateCwd = context.alternateCwd;
this.consumer = context.consumer;
this.bitMap = this.consumer.bitMap;
this.componentPaths = this.joinConsumerPathIfNeeded(addProps.componentPaths);
this.id = addProps.id;
this.main = addProps.main;
this.namespace = addProps.namespace;
this.tests = addProps.tests ? this.joinConsumerPathIfNeeded(addProps.tests) : [];
this.exclude = addProps.exclude ? this.joinConsumerPathIfNeeded(addProps.exclude) : [];
this.override = addProps.override;
this.trackDirFeature = addProps.trackDirFeature;
this.origin = addProps.origin || _constants().COMPONENT_ORIGINS.AUTHORED;
this.warnings = {
alreadyUsed: {},
emptyDirectory: [],
existInScope: []
};
this.addedComponents = [];
}
joinConsumerPathIfNeeded(paths) {
if (paths.length > 0) {
if (this.alternateCwd !== undefined && this.alternateCwd !== null) {
const alternate = this.alternateCwd;
return paths.map(file => path().join(alternate, file));
}
return paths;
}
return [];
}
/**
* @param {string[]} files - array of file-paths from which it should search for the dsl patterns.
* @param {*} filesWithPotentialDsl - array of file-path which may have DSL patterns
*
* @returns array of file-paths from 'files' parameter that match the patterns from 'filesWithPotentialDsl' parameter
*/
getFilesAccordingToDsl(files, filesWithPotentialDsl) {
var _this = this;
return (0, _bluebird().coroutine)(function* () {
const filesListAllMatches = filesWithPotentialDsl.map( /*#__PURE__*/function () {
var _ref = (0, _bluebird().coroutine)(function* (dsl) {
const filesListMatch = files.map( /*#__PURE__*/function () {
var _ref2 = (0, _bluebird().coroutine)(function* (file) {
const fileInfo = (0, _utils().calculateFileInfo)(file);
const generatedFile = (0, _stringFormat().default)(dsl, fileInfo);
const matches = yield (0, _utils().glob)(generatedFile);
const matchesAfterGitIgnore = _this.gitIgnore.filter(matches);
return matchesAfterGitIgnore.filter(match => _fsExtra().default.existsSync(match));
});
return function (_x2) {
return _ref2.apply(this, arguments);
};
}());
return Promise.all(filesListMatch);
});
return function (_x) {
return _ref.apply(this, arguments);
};
}());
const filesListFlatten = _ramda().default.flatten(yield Promise.all(filesListAllMatches));
const filesListUnique = _ramda().default.uniq(filesListFlatten);
return filesListUnique.map(file => {
// when files array has the test file with different letter case, use the one from the file array
const fileNormalized = (0, _utils().pathNormalizeToLinux)(file);
const fileWithCorrectCase = files.find(f => f.toLowerCase() === fileNormalized.toLowerCase()) || fileNormalized;
const relativeToConsumer = _this.consumer.getPathRelativeToConsumer(fileWithCorrectCase);
return (0, _utils().pathNormalizeToLinux)(relativeToConsumer);
});
})();
}
/**
* unsupported files, such as, binary files, don't have link-file. instead, they have a symlink
* inside the component dir, pointing to the dependency.
* this methods check whether a file is auto generated for the unsupported files.
*/
_isGeneratedForUnsupportedFiles(fileRelativePath, componentId, componentMap) {
var _this2 = this;
return (0, _bluebird().coroutine)(function* () {
if ((0, _linkContent().isSupportedExtension)(fileRelativePath)) return false;
const componentFromModel = yield _this2.consumer.loadComponentFromModelIfExist(componentId);
if (!componentFromModel) {
throw new (_showDoctorError().default)(`failed finding ${componentId.toString()} in the model although the component is imported, try running "bit import ${componentId.toString()} --objects" to get the component saved in the model`);
}
const dependencies = componentFromModel.getAllDependenciesCloned();
const sourcePaths = dependencies.getSourcesPaths();
const sourcePathsRelativeToConsumer = sourcePaths.map(sourcePath => (0, _utils().pathJoinLinux)(componentMap.rootDir, sourcePath));
return sourcePathsRelativeToConsumer.includes(fileRelativePath);
})();
}
/**
* for imported component, the package.json in the root directory is a bit-generated file and as
* such, it should be ignored
*/
_isPackageJsonOnRootDir(pathRelativeToConsumerRoot, componentMap) {
if (!componentMap.rootDir || componentMap.origin !== _constants().COMPONENT_ORIGINS.IMPORTED) {
throw new Error('_isPackageJsonOnRootDir should not get called on non imported components');
}
return path().join(componentMap.rootDir, _constants().PACKAGE_JSON) === path().normalize(pathRelativeToConsumerRoot);
}
/**
* imported components might have wrapDir, when they do, files should not be added outside of
* that wrapDir
*/
_isOutsideOfWrapDir(pathRelativeToConsumerRoot, componentMap) {
if (!componentMap.rootDir || componentMap.origin !== _constants().COMPONENT_ORIGINS.IMPORTED) {
throw new Error('_isOutsideOfWrapDir should not get called on non imported components');
}
if (!componentMap.wrapDir) return false;
const wrapDirRelativeToConsumerRoot = path().join(componentMap.rootDir, componentMap.wrapDir);
return !path().normalize(pathRelativeToConsumerRoot).startsWith(wrapDirRelativeToConsumerRoot);
}
/**
* Add or update existing (imported and new) component according to bitmap
* there are 3 options:
* 1. a user is adding a new component. there is no record for this component in bit.map
* 2. a user is updating an existing component. there is a record for this component in bit.map
* 3. some or all the files of this component were previously added as another component-id.
*/
addOrUpdateComponentInBitMap(component) {
var _this3 = this;
return (0, _bluebird().coroutine)(function* () {
const consumerPath = _this3.consumer.getPath();
const parsedBitId = component.componentId;
const componentFromScope = yield _this3._getComponentFromScopeIfExist(parsedBitId);
const files = component.files;
const foundComponentFromBitMap = _this3.bitMap.getComponentIfExist(component.componentId, {
ignoreScopeAndVersion: true
});
const componentFilesP = files.map( /*#__PURE__*/function () {
var _ref3 = (0, _bluebird().coroutine)(function* (file) {
// $FlowFixMe null is removed later on
const filePath = path().join(consumerPath, file.relativePath);
const isAutoGenerated = yield (0, _utils().isAutoGeneratedFile)(filePath);
if (isAutoGenerated) {
return null;
}
const caseSensitive = false;
const existingIdOfFile = _this3.bitMap.getComponentIdByPath(file.relativePath, caseSensitive);
const idOfFileIsDifferent = existingIdOfFile && !existingIdOfFile.isEqual(parsedBitId);
const existingComponentOfFile = existingIdOfFile ? _this3.bitMap.getComponent(existingIdOfFile) : undefined;
const isImported = foundComponentFromBitMap && foundComponentFromBitMap.origin === _constants().COMPONENT_ORIGINS.IMPORTED || existingComponentOfFile && existingComponentOfFile.origin === _constants().COMPONENT_ORIGINS.IMPORTED;
if (isImported) {
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
const idFromBitMap = foundComponentFromBitMap ? foundComponentFromBitMap.id : existingComponentOfFile.id; // throw error in case user didn't add id to imported component or the id is incorrect
if (!_this3.id) throw new (_exceptions().MissingComponentIdForImportedComponent)(idFromBitMap.toStringWithoutVersion());
if (idOfFileIsDifferent) {
const existingIdWithoutVersion = existingIdOfFile.toStringWithoutVersion(); // $FlowFixMe $this.id is not null at this point
throw new (_exceptions().IncorrectIdForImportedComponent)(existingIdWithoutVersion, _this3.id, file.relativePath);
} // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
if (_this3._isPackageJsonOnRootDir(file.relativePath, foundComponentFromBitMap)) return null; // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
if (_this3._isOutsideOfWrapDir(file.relativePath, foundComponentFromBitMap)) {
_logger().default.warn(`add-components: ignoring ${file.relativePath} as it is located outside of the wrapDir`);
return null;
}
const isGeneratedForUnsupportedFiles = yield _this3._isGeneratedForUnsupportedFiles(file.relativePath, component.componentId, // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
foundComponentFromBitMap);
if (isGeneratedForUnsupportedFiles) return null;
delete component.trackDir;
} else if (idOfFileIsDifferent) {
// not imported component file but exists in bitmap
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
if (_this3.warnings.alreadyUsed[existingIdOfFile]) {
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
_this3.warnings.alreadyUsed[existingIdOfFile].push(file.relativePath);
} else {
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
_this3.warnings.alreadyUsed[existingIdOfFile] = [file.relativePath];
} // $FlowFixMe null is removed later on
return null;
}
if (!foundComponentFromBitMap && componentFromScope) {
const newId = componentFromScope.toBitIdWithLatestVersion();
component.componentId = newId;
_this3.warnings.existInScope.push(newId);
}
return file;
});
return function (_x3) {
return _ref3.apply(this, arguments);
};
}()); // $FlowFixMe it can't be null due to the filter function
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
const componentFiles = (yield Promise.all(componentFilesP)).filter(file => file);
if (!componentFiles.length) return {
id: component.componentId.toString(),
files: []
};
if (foundComponentFromBitMap) {
_this3._updateFilesAccordingToExistingRootDir(foundComponentFromBitMap, componentFiles, component);
}
if (_this3.trackDirFeature) {
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
if (_this3.bitMap._areFilesArraysEqual(foundComponentFromBitMap.files, componentFiles)) {
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
return foundComponentFromBitMap;
}
}
if (!_this3.override && foundComponentFromBitMap) {
_this3._updateFilesWithCurrentLetterCases(foundComponentFromBitMap, componentFiles);
component.files = _this3._mergeFilesWithExistingComponentMapFiles(componentFiles, foundComponentFromBitMap.files);
} else {
component.files = componentFiles;
}
const {
componentId,
trackDir
} = component;
const mainFile = (0, _determineMainFile().default)(component, foundComponentFromBitMap);
const getRootDir = () => {
if (_this3.trackDirFeature) throw new Error('track dir should not calculate the rootDir');
if (foundComponentFromBitMap) return foundComponentFromBitMap.rootDir;
if (_this3.consumer.isLegacy) return '';
if (!trackDir) throw new Error(`addOrUpdateComponentInBitMap expect to have trackDir for non-legacy workspace`);
const fileNotInsideTrackDir = componentFiles.find(file => !(0, _utils().pathNormalizeToLinux)(file.relativePath).startsWith(`${(0, _utils().pathNormalizeToLinux)(trackDir)}/`));
if (fileNotInsideTrackDir) {
// we check for this error before. however, it's possible that a user have one trackDir
// and another dir for the tests.
throw new (_addingIndividualFiles().AddingIndividualFiles)(fileNotInsideTrackDir.relativePath);
}
return (0, _utils().pathNormalizeToLinux)(trackDir);
};
const getComponentMap = () => {
if (_this3.trackDirFeature) {
return _this3.bitMap.addFilesToComponent({
componentId,
files: component.files
});
}
const rootDir = getRootDir();
const componentMap = _this3.bitMap.addComponent({
componentId,
files: component.files,
mainFile,
trackDir: rootDir ? '' : trackDir,
// if rootDir exists, no need for trackDir.
origin: _constants().COMPONENT_ORIGINS.AUTHORED,
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
override: _this3.override
});
if (rootDir) componentMap.changeRootDirAndUpdateFilesAccordingly(rootDir);
return componentMap;
};
const componentMap = getComponentMap();
return {
id: componentId.toString(),
files: componentMap.files
};
})();
}
/**
* current componentFiles are relative to the workspace. we want them relative to the rootDir.
*/
_updateFilesAccordingToExistingRootDir(foundComponentFromBitMap, componentFiles, component) {
const existingRootDir = foundComponentFromBitMap.rootDir;
if (!existingRootDir) return; // nothing to do.
const areFilesInsideExistingRootDir = componentFiles.every(file => (0, _utils().pathNormalizeToLinux)(file.relativePath).startsWith(`${existingRootDir}/`));
if (foundComponentFromBitMap.origin === _constants().COMPONENT_ORIGINS.IMPORTED || areFilesInsideExistingRootDir) {
_componentMap().default.changeFilesPathAccordingToItsRootDir(existingRootDir, componentFiles);
return;
} // some (or all) added files are outside the existing rootDir, the rootDir needs to be changed
// if a directory was added and it's a parent of the existing rootDir, change the rootDir to
// the currently added rootDir.
const currentlyAddedDir = (0, _utils().pathNormalizeToLinux)(component.trackDir);
const currentlyAddedDirParentOfRootDir = currentlyAddedDir && existingRootDir.startsWith(`${currentlyAddedDir}/`);
if (currentlyAddedDirParentOfRootDir) {
foundComponentFromBitMap.changeRootDirAndUpdateFilesAccordingly(currentlyAddedDir);
_componentMap().default.changeFilesPathAccordingToItsRootDir(currentlyAddedDir, componentFiles);
return;
}
throw new (_generalError().default)(`unable to add individual files outside the root dir (${existingRootDir}) of ${component.componentId}.
you can add the directory these files are located at and it'll change the root dir of the component accordingly`); // we might want to change the behavior here to not throw an error and only change the rootDir to "."
// foundComponentFromBitMap.changeRootDirAndUpdateFilesAccordingly('.');
}
/**
* the risk with merging the currently added files with the existing bitMap files is overriding
* the `test` property. e.g. the component directory is re-added without adding the tests flag to
* track new files in that directory. in this case, we want to preserve the `test` property.
*/
_mergeFilesWithExistingComponentMapFiles(componentFiles, existingComponentMapFile) {
if (this.tests.length) {
// in case when the `--tests` flag was entered, we use the currently added files as the
// base and merge the existing file so then the `test` property of the currently added files
// won't be overridden
return _ramda().default.unionWith(_ramda().default.eqBy(_ramda().default.prop('relativePath')), componentFiles, existingComponentMapFile);
}
return _ramda().default.unionWith(_ramda().default.eqBy(_ramda().default.prop('relativePath')), existingComponentMapFile, componentFiles);
}
/**
* if an existing file is for example uppercase and the new file is lowercase it has different
* behavior according to the OS. some OS are case sensitive, some are not.
* it's safer to avoid saving both files and instead, replacing the old file with the new one.
* in case a file has replaced and it is also a mainFile, replace the mainFile as well
*/
_updateFilesWithCurrentLetterCases(currentComponentMap, newFiles) {
const currentFiles = currentComponentMap.files;
currentFiles.forEach(currentFile => {
const sameFile = newFiles.find(newFile => newFile.relativePath.toLowerCase() === currentFile.relativePath.toLowerCase());
if (sameFile && currentFile.relativePath !== sameFile.relativePath) {
if (currentComponentMap.mainFile === currentFile.relativePath) {
currentComponentMap.mainFile = sameFile.relativePath;
}
currentFile.relativePath = sameFile.relativePath;
}
});
}
_getComponentFromScopeIfExist(id) {
var _this4 = this;
return (0, _bluebird().coroutine)(function* () {
try {
return yield _this4.consumer.scope.getModelComponentIgnoreScope(id);
} catch (err) {
return null;
}
})();
} // remove excluded files from file list
removeExcludedFiles(componentsWithFiles) {
var _this5 = this;
return (0, _bluebird().coroutine)(function* () {
const files = _ramda().default.flatten(componentsWithFiles.map(x => x.files.map(i => i.relativePath)));
const resolvedExcludedFiles = yield _this5.getFilesAccordingToDsl(files, _this5.exclude);
componentsWithFiles.forEach(componentWithFiles => {
const mainFile = componentWithFiles.mainFile ? (0, _utils().pathNormalizeToLinux)(componentWithFiles.mainFile) : undefined; // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
if (resolvedExcludedFiles.includes(mainFile)) {
// if mainFile is excluded, exclude all files
componentWithFiles.files = [];
} else {
componentWithFiles.files = componentWithFiles.files.filter(key => !resolvedExcludedFiles.includes(key.relativePath));
}
});
})();
}
/**
* if the id is already saved in bitmap file, it might have more data (such as scope, version)
* use that id instead.
*/
_getIdAccordingToExistingComponent(currentId) {
const existingComponentId = this.bitMap.getExistingBitId(currentId, false);
const componentExists = Boolean(existingComponentId); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
if (componentExists && this.bitMap.getComponent(existingComponentId).origin === _constants().COMPONENT_ORIGINS.NESTED) {
throw new (_generalError().default)(`One of your dependencies (${existingComponentId}) has already the same namespace and name.
If you're trying to add a new component, please choose a new namespace or name.
If you're trying to update a dependency component, please re-import it individually`);
}
if (currentId.includes(_constants().VERSION_DELIMITER)) {
if (!existingComponentId || // this id is new, it shouldn't have a version
!existingComponentId.hasVersion() || // this component is new, it shouldn't have a version
// user shouldn't add files to a an existing component with different version
// $FlowFixMe this function gets called only when this.id is set
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
existingComponentId.version !== _bitId().BitId.getVersionOnlyFromString(this.id)) {
// $FlowFixMe this.id is defined here
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
throw new (_versionShouldBeRemoved().default)(this.id);
}
}
return existingComponentId || _bitId().BitId.parse(currentId, false);
}
_getIdAccordingToTrackDir(dir) {
const dirNormalizedToLinux = (0, _utils().pathNormalizeToLinux)(dir);
const trackDirs = this.bitMap.getAllTrackDirs();
if (!trackDirs) return null;
return trackDirs[dirNormalizedToLinux];
}
/**
* used for updating main file if exists or doesn't exists
*/
_addMainFileToFiles(files) {
let mainFile = this.main;
if (mainFile && mainFile.match(REGEX_DSL_PATTERN)) {
// it's a DSL
files.forEach(file => {
const fileInfo = (0, _utils().calculateFileInfo)(file.relativePath);
const generatedFile = (0, _stringFormat().default)(mainFile, fileInfo);
const foundFile = this._findMainFileInFiles(generatedFile, files);
if (foundFile) {
mainFile = foundFile.relativePath;
}
if (_fsExtra().default.existsSync(generatedFile) && !foundFile) {
const shouldIgnore = this.gitIgnore.ignores(generatedFile);
if (shouldIgnore) {
// check if file is in exclude list
throw new (_exceptions().ExcludedMainFile)(generatedFile);
}
files.push({
relativePath: (0, _utils().pathNormalizeToLinux)(generatedFile),
test: false,
name: path().basename(generatedFile)
});
mainFile = generatedFile;
}
});
}
if (!mainFile) return undefined;
if (this.alternateCwd) {
mainFile = path().join(this.alternateCwd, mainFile);
}
const mainFileRelativeToConsumer = this.consumer.getPathRelativeToConsumer(mainFile);
const mainPath = this.consumer.toAbsolutePath(mainFileRelativeToConsumer);
if (_fsExtra().default.existsSync(mainPath)) {
const shouldIgnore = this.gitIgnore.ignores(mainFileRelativeToConsumer);
if (shouldIgnore) throw new (_exceptions().ExcludedMainFile)(mainFileRelativeToConsumer);
if ((0, _utils().isDir)(mainPath)) {
throw new (_exceptions().MainFileIsDir)(mainPath);
}
const foundFile = this._findMainFileInFiles(mainFileRelativeToConsumer, files);
if (foundFile) {
return foundFile.relativePath;
}
files.push({
relativePath: (0, _utils().pathNormalizeToLinux)(mainFileRelativeToConsumer),
test: false,
name: path().basename(mainFileRelativeToConsumer)
});
return mainFileRelativeToConsumer;
}
return mainFile;
}
_findMainFileInFiles(mainFile, files) {
const normalizedMainFile = (0, _utils().pathNormalizeToLinux)(mainFile).toLowerCase();
return files.find(file => file.relativePath.toLowerCase() === normalizedMainFile);
}
_mergeTestFilesWithFiles(files) {
var _this6 = this;
return (0, _bluebird().coroutine)(function* () {
const testFiles = !_ramda().default.isEmpty(_this6.tests) ? yield _this6.getFilesAccordingToDsl(files.map(file => file.relativePath), _this6.tests) : [];
const resolvedTestFiles = testFiles.map(testFile => {
if ((0, _utils().isDir)(path().join(_this6.consumer.getPath(), testFile))) throw new (_exceptions().TestIsDirectory)(testFile);
return {
relativePath: testFile,
test: true,
name: path().basename(testFile)
};
});
return (0, _lodash3().default)(resolvedTestFiles, files, 'relativePath');
})();
}
/**
* given the component paths, prepare the id, mainFile and files to be added later on to bitmap
* the id of the component is either entered by the user or, if not entered, concluded by the path.
* e.g. bar/foo.js, the id would be bar/foo.
* in case bitmap has already the same id, the complete id is taken from bitmap (see _getIdAccordingToExistingComponent)
*/
addOneComponent(componentPathsStats) {
var _this7 = this;
return (0, _bluebird().coroutine)(function* () {
let finalBitId; // final id to use for bitmap file
let idFromPath;
if (_this7.id) {
finalBitId = _this7._getIdAccordingToExistingComponent(_this7.id);
}
const componentsWithFilesP = Object.keys(componentPathsStats).map( /*#__PURE__*/function () {
var _ref4 = (0, _bluebird().coroutine)(function* (componentPath) {
if (componentPathsStats[componentPath].isDir) {
const relativeComponentPath = _this7.consumer.getPathRelativeToConsumer(componentPath);
_this7._throwForOutsideConsumer(relativeComponentPath);
const matches = yield (0, _utils().glob)(path().join(relativeComponentPath, '**'), {
cwd: _this7.consumer.getPath(),
nodir: true
});
const filteredMatches = _this7.gitIgnore.filter(matches);
if (!filteredMatches.length) throw new (_exceptions().EmptyDirectory)();
let filteredMatchedFiles = filteredMatches.map(match => {
return {
relativePath: (0, _utils().pathNormalizeToLinux)(match),
test: false,
name: path().basename(match)
};
}); // merge test files with files
filteredMatchedFiles = yield _this7._mergeTestFilesWithFiles(filteredMatchedFiles);
const resolvedMainFile = _this7._addMainFileToFiles(filteredMatchedFiles);
const absoluteComponentPath = path().resolve(componentPath);
const splitPath = absoluteComponentPath.split(path().sep);
const lastDir = splitPath[splitPath.length - 1];
if (!finalBitId) {
const idOfTrackDir = _this7._getIdAccordingToTrackDir(componentPath);
if (idOfTrackDir) {
finalBitId = idOfTrackDir;
} else {
const nameSpaceOrDir = _this7.namespace || splitPath[splitPath.length - 2];
if (!_this7.namespace) {
idFromPath = {
namespace: _bitId().BitId.getValidIdChunk(nameSpaceOrDir),
name: _bitId().BitId.getValidIdChunk(lastDir)
};
}
finalBitId = _bitId().BitId.getValidBitId(nameSpaceOrDir, lastDir);
}
}
const getTrackDir = () => {
if (Object.keys(componentPathsStats).length === 1 && _this7.origin === _constants().COMPONENT_ORIGINS.AUTHORED) {
if (!_this7.exclude.length) {
return relativeComponentPath;
}
if (!_this7.consumer.isLegacy) {
throw new (_generalError().default)(`unable to exclude files when tracking a directory, as Bit won't be able to auto-track changes in this directory.
try to avoid excluding files and maybe put them in your .gitignore if it makes sense.`);
}
}
return undefined;
};
const trackDir = getTrackDir();
return {
componentId: finalBitId,
files: filteredMatchedFiles,
mainFile: resolvedMainFile,
trackDir,
idFromPath,
immediateDir: lastDir
};
} // is file
const absolutePath = path().resolve(componentPath);
const pathParsed = path().parse(absolutePath);
const relativeFilePath = _this7.consumer.getPathRelativeToConsumer(componentPath);
_this7._throwForOutsideConsumer(relativeFilePath);
if (!finalBitId) {
let dirName = pathParsed.dir;
if (!dirName) {
dirName = path().dirname(absolutePath);
}
const nameSpaceOrLastDir = _this7.namespace || _ramda().default.last(dirName.split(path().sep));
if (!_this7.namespace) {
idFromPath = {
namespace: _bitId().BitId.getValidIdChunk(nameSpaceOrLastDir),
name: _bitId().BitId.getValidIdChunk(pathParsed.name)
};
}
finalBitId = _bitId().BitId.getValidBitId(nameSpaceOrLastDir, pathParsed.name);
}
let files = [{
relativePath: (0, _utils().pathNormalizeToLinux)(relativeFilePath),
test: false,
name: path().basename(relativeFilePath)
}];
files = yield _this7._mergeTestFilesWithFiles(files);
const resolvedMainFile = _this7._addMainFileToFiles(files);
return {
componentId: finalBitId,
files,
mainFile: resolvedMainFile,
idFromPath
};
});
return function (_x4) {
return _ref4.apply(this, arguments);
};
}());
let componentsWithFiles = yield Promise.all(componentsWithFilesP); // remove files that are excluded
if (!_ramda().default.isEmpty(_this7.exclude)) yield _this7.removeExcludedFiles(componentsWithFiles); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
const componentId = finalBitId;
componentsWithFiles = componentsWithFiles.filter(componentWithFiles => componentWithFiles.files.length); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
if (componentsWithFiles.length === 0) return {
componentId,
files: []
};
if (componentsWithFiles.length === 1) return componentsWithFiles[0];
const files = componentsWithFiles.reduce((a, b) => {
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
return a.concat(b.files);
}, []);
const groupedComponents = (0, _lodash2().default)(files, 'relativePath');
const uniqComponents = Object.keys(groupedComponents).map(key => (0, _lodash().default)({}, ...groupedComponents[key], (val1, val2) => val1 || val2));
return {
componentId,
files: uniqComponents,
mainFile: _ramda().default.head(componentsWithFiles).mainFile,
trackDir: _ramda().default.head(componentsWithFiles).trackDir,
idFromPath
};
})();
}
getIgnoreList() {
var _this8 = this;
return (0, _bluebird().coroutine)(function* () {
const consumerPath = _this8.consumer.getPath();
let ignoreList = (0, _utils().retrieveIgnoreList)(consumerPath);
const importedComponents = _this8.bitMap.getAllComponents(_constants().COMPONENT_ORIGINS.IMPORTED);
const distDirsOfImportedComponents = importedComponents.map(componentMap => (0, _utils().pathJoinLinux)(componentMap.rootDir, _constants().DEFAULT_DIST_DIRNAME, '**'));
ignoreList = ignoreList.concat(distDirsOfImportedComponents); // the ability to track package.json is deprecated since Harmony
if (!_this8.consumer.isLegacy) ignoreList.push(_constants().PACKAGE_JSON);
return ignoreList;
})();
}
add() {
var _this9 = this;
return (0, _bluebird().coroutine)(function* () {
_this9.ignoreList = yield _this9.getIgnoreList();
_this9.gitIgnore = (0, _ignore().default)().add(_this9.ignoreList); // add ignore list
// check unknown test files
const missingFiles = (0, _utils().getMissingTestFiles)(_this9.tests);
if (!_ramda().default.isEmpty(missingFiles)) {
throw new (_exceptions().PathsNotExist)(missingFiles);
}
let componentPathsStats = {};
const resolvedComponentPathsWithoutGitIgnore = _ramda().default.flatten(yield Promise.all(_this9.componentPaths.map(componentPath => (0, _utils().glob)(componentPath)))); // add excluded list to gitignore to remove excluded files from list
const resolvedExcludedFiles = yield _this9.getFilesAccordingToDsl(resolvedComponentPathsWithoutGitIgnore, _this9.exclude);
_this9.ignoreList = [..._this9.ignoreList, ...resolvedExcludedFiles];
_this9.gitIgnore = (0, _ignore().default)().add(_this9.ignoreList); // add ignore list
const resolvedComponentPathsWithGitIgnore = _this9.gitIgnore.filter(resolvedComponentPathsWithoutGitIgnore); // Run diff on both arrays to see what was filtered out because of the gitignore file
const diff = (0, _arrayDifference().default)(resolvedComponentPathsWithGitIgnore, resolvedComponentPathsWithoutGitIgnore);
if (!_ramda().default.isEmpty(_this9.tests) && _this9.id && _ramda().default.isEmpty(resolvedComponentPathsWithoutGitIgnore)) {
const resolvedTestFiles = _ramda().default.flatten(yield Promise.all(_this9.tests.map(componentPath => (0, _utils().glob)(componentPath))));
componentPathsStats = validatePaths(resolvedTestFiles);
} else {
if (_ramda().default.isEmpty(resolvedComponentPathsWithoutGitIgnore)) {
throw new (_exceptions().PathsNotExist)(_this9.componentPaths);
}
if (!_ramda().default.isEmpty(resolvedComponentPathsWithGitIgnore)) {
componentPathsStats = validatePaths(resolvedComponentPathsWithGitIgnore);
} else {
throw new (_exceptions().NoFiles)(diff);
}
}
if (!_this9.consumer.isLegacy) {
Object.keys(componentPathsStats).forEach(compPath => {
if (!componentPathsStats[compPath].isDir) {
throw new (_addingIndividualFiles().AddingIndividualFiles)(compPath);
}
});
} // if a user entered multiple paths and entered an id, he wants all these paths to be one component
// conversely, if a user entered multiple paths without id, he wants each dir as an individual component
const isMultipleComponents = Object.keys(componentPathsStats).length > 1 && !_this9.id;
if (isMultipleComponents) {
yield _this9.addMultipleComponents(componentPathsStats);
} else {
_logger().default.debugAndAddBreadCrumb('add-components', 'adding one component'); // when a user enters more than one directory, he would like to keep the directories names
// so then when a component is imported, it will write the files into the original directories
const addedOne = yield _this9.addOneComponent(componentPathsStats);
_this9._removeNamespaceIfNotNeeded([addedOne]);
if (!_ramda().default.isEmpty(addedOne.files)) {
const addedResult = yield _this9.addOrUpdateComponentInBitMap(addedOne);
if (addedResult) _this9.addedComponents.push(addedResult);
}
}
_analytics().Analytics.setExtraData('num_components', _this9.addedComponents.length);
return {
addedComponents: _this9.addedComponents,
warnings: _this9.warnings
};
})();
}
addMultipleComponents(componentPathsStats) {
var _this10 = this;
return (0, _bluebird().coroutine)(function* () {
_logger().default.debugAndAddBreadCrumb('add-components', 'adding multiple components');
_this10._removeDirectoriesWhenTheirFilesAreAdded(componentPathsStats);
const testToRemove = !_ramda().default.isEmpty(_this10.tests) ? yield _this10.getFilesAccordingToDsl(Object.keys(componentPathsStats), _this10.tests) : [];
testToRemove.forEach(test => delete componentPathsStats[path().normalize(test)]);
const added = yield _this10._tryAddingMultiple(componentPathsStats);
validateNoDuplicateIds(added);
_this10._removeNamespaceIfNotNeeded(added);
yield _this10._addMultipleToBitMap(added);
})();
}
/**
* some uses of wildcards might add directories and their files at the same time, in such cases
* only the files are needed and the directories can be ignored.
* @see https://github.com/teambit/bit/issues/1406 for more details
*/
_removeDirectoriesWhenTheirFilesAreAdded(componentPathsStats) {
const allPaths = Object.keys(componentPathsStats);
allPaths.forEach(componentPath => {
const foundDir = allPaths.find(p => p === path().dirname(componentPath));
if (foundDir && componentPathsStats[foundDir]) {
_logger().default.debug(`add-components._removeDirectoriesWhenTheirFilesAreAdded, ignoring ${foundDir}`);
delete componentPathsStats[foundDir];
}
});
}
_addMultipleToBitMap(added) {
var _this11 = this;
return (0, _bluebird().coroutine)(function* () {
const missingMainFiles = [];
yield Promise.all(added.map( /*#__PURE__*/function () {
var _ref5 = (0, _bluebird().coroutine)(function* (component) {
if (!_ramda().default.isEmpty(component.files)) {
try {
const addedComponent = yield _this11.addOrUpdateComponentInBitMap(component);
if (addedComponent && addedComponent.files.length) _this11.addedComponents.push(addedComponent);
} catch (err) {
if (!(err instanceof _missingMainFile().default)) throw err; // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
missingMainFiles.push(err);
}
}
});
return function (_x5) {
return _ref5.apply(this, arguments);
};
}()));
if (missingMainFiles.length) {
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
throw new (_missingMainFileMultipleComponents().default)(missingMainFiles.map(err => err.componentId).sort());
}
})();
}
_removeNamespaceIfNotNeeded(addedComponents) {
const allIds = this.bitMap.getAllBitIds();
addedComponents.forEach(addedComponent => {
if (!addedComponent.idFromPath) return; // when the id was not generated from the path do nothing.
const componentsWithSameName = addedComponents // $FlowFixMe
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
.filter(a => a.idFromPath && a.idFromPath.name === addedComponent.idFromPath.name);
const bitIdFromNameOnly = new (_bitId().BitId)({
name: addedComponent.idFromPath.name
});
const existingComponentWithSameName = allIds.searchWithoutScopeAndVersion(bitIdFromNameOnly);
if (componentsWithSameName.length === 1 && !existingComponentWithSameName) {
addedComponent.componentId = bitIdFromNameOnly;
}
});
}
_tryAddingMultiple(componentPathsStats) {
var _this12 = this;
return (0, _bluebird().coroutine)(function* () {
const addedP = Object.keys(componentPathsStats).map( /*#__PURE__*/function () {
var _ref6 = (0, _bluebird().coroutine)(function* (onePath) {
const oneComponentPathStat = {
[onePath]: componentPathsStats[onePath]
};
try {
const addedComponent = yield _this12.addOneComponent(oneComponentPathStat);
return addedComponent;
} catch (err) {
if (!(err instanceof _exceptions().EmptyDirectory)) throw err;
_this12.warnings.emptyDirectory.push(onePath);
return null;
}
});
return function (_x6) {
return _ref6.apply(this, arguments);
};
}());
const added = yield Promise.all(addedP);
return _ramda().default.reject(_ramda().default.isNil, added);
})();
}
_throwForOutsideConsumer(relativeToConsumerPath) {
if (relativeToConsumerPath.startsWith('..')) {
throw new (_pathOutsideConsumer().default)(relativeToConsumerPath);
}
}
}
/**
* validatePaths - validate if paths entered by user exist and if not throw an error
*
* @param {string[]} fileArray - array of paths
* @returns {PathsStats} componentPathsStats
*/
exports.default = AddComponents;
function validatePaths(fileArray) {
const componentPathsStats = {};
fileArray.forEach(componentPath => {
if (!_fsExtra().default.existsSync(componentPath)) {
throw new (_exceptions().PathsNotExist)([componentPath]);
}
componentPathsStats[componentPath] = {
isDir: (0, _utils().isDir)(componentPath)
};
});
return componentPathsStats;
}
/**
* validate that no two files where added with the same id in the same bit add command
*/
function validateNoDuplicateIds(addComponents) {
const duplicateIds = {};
const newGroupedComponents = (0, _lodash2().default)(addComponents, 'componentId');
Object.keys(newGroupedComponents).forEach(key => {
if (newGroupedComponents[key].length > 1) duplicateIds[key] = newGroupedComponents[key];
});
if (!_ramda().default.isEmpty(duplicateIds) && !_ramda().default.isNil(duplicateIds)) throw new (_exceptions().DuplicateIds)(duplicateIds);
}
;