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

1,300 lines (995 loc) 46.4 kB
"use strict"; 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); }