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

673 lines (510 loc) 24.3 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 _ramda() { const data = _interopRequireDefault(require("ramda")); _ramda = function () { return data; }; return data; } function _fsExtra() { const data = _interopRequireDefault(require("fs-extra")); _fsExtra = function () { return data; }; return data; } function _semver() { const data = _interopRequireDefault(require("semver")); _semver = function () { return data; }; return data; } function path() { const data = _interopRequireWildcard(require("path")); path = function () { return data; }; return data; } function _logger() { const data = _interopRequireDefault(require("../../logger/logger")); _logger = function () { return data; }; return data; } function _path2() { const data = require("../../utils/path"); _path2 = function () { return data; }; return data; } function _constants() { const data = require("../../constants"); _constants = function () { return data; }; return data; } function _componentNodeModulesPath() { const data = _interopRequireDefault(require("../../utils/bit/component-node-modules-path")); _componentNodeModulesPath = function () { return data; }; return data; } function _packageJsonUtils() { const data = require("../component/package-json-utils"); _packageJsonUtils = function () { return data; }; return data; } function _dataToPersist() { const data = _interopRequireDefault(require("../component/sources/data-to-persist")); _dataToPersist = function () { return data; }; return data; } function _removePath() { const data = _interopRequireDefault(require("../component/sources/remove-path")); _removePath = function () { return data; }; return data; } function _envExtension() { const data = _interopRequireDefault(require("../../legacy-extensions/env-extension")); _envExtension = function () { return data; }; return data; } function _componentConfig() { const data = _interopRequireDefault(require("../config/component-config")); _componentConfig = function () { return data; }; return data; } function _showDoctorError() { const data = _interopRequireDefault(require("../../error/show-doctor-error")); _showDoctorError = function () { return data; }; return data; } class ComponentWriter { // when using capsule, the consumer is not defined constructor({ component, writeToPath, writeConfig = false, writePackageJson = true, override = true, isolated = false, origin, consumer, bitMap, writeBitDependencies = false, deleteBitDirContent, existingComponentMap, excludeRegistryPrefix = false, applyExtensionsAddedConfig = false }) { (0, _defineProperty2().default)(this, "component", void 0); (0, _defineProperty2().default)(this, "writeToPath", void 0); (0, _defineProperty2().default)(this, "writeConfig", void 0); (0, _defineProperty2().default)(this, "writePackageJson", void 0); (0, _defineProperty2().default)(this, "override", void 0); (0, _defineProperty2().default)(this, "isolated", void 0); (0, _defineProperty2().default)(this, "origin", void 0); (0, _defineProperty2().default)(this, "consumer", void 0); (0, _defineProperty2().default)(this, "bitMap", void 0); (0, _defineProperty2().default)(this, "writeBitDependencies", void 0); (0, _defineProperty2().default)(this, "deleteBitDirContent", void 0); (0, _defineProperty2().default)(this, "existingComponentMap", void 0); (0, _defineProperty2().default)(this, "excludeRegistryPrefix", void 0); (0, _defineProperty2().default)(this, "applyExtensionsAddedConfig", void 0); this.component = component; this.writeToPath = writeToPath; this.writeConfig = writeConfig; this.writePackageJson = writePackageJson; this.override = override; this.isolated = isolated; this.origin = origin; this.consumer = consumer; this.bitMap = bitMap; this.writeBitDependencies = writeBitDependencies; this.deleteBitDirContent = deleteBitDirContent; this.existingComponentMap = existingComponentMap; this.excludeRegistryPrefix = excludeRegistryPrefix; this.applyExtensionsAddedConfig = applyExtensionsAddedConfig; } static getInstance(componentWriterProps) { return new ComponentWriter(componentWriterProps); } /** * write the component to the filesystem and update .bitmap with the details. * * bitMap gets updated before writing the files to the filesystem, because as part of writing the * package-json file, the componentMap is needed to be stored with the updated version. * * when a component is not new, write the files according to the paths in .bitmap. */ write() { var _this = this; return (0, _bluebird().coroutine)(function* () { if (!_this.consumer) throw new Error('ComponentWriter.write expect to have a consumer'); yield _this.populateComponentsFilesToWrite(); // $FlowFixMe consumer is set _this.component.dataToPersist.addBasePath(_this.consumer.getPath()); yield _this.component.dataToPersist.persistAllToFS(); return _this.component; })(); } populateComponentsFilesToWrite(packageManager) { var _this2 = this; return (0, _bluebird().coroutine)(function* () { if (!_this2.component.files || !_this2.component.files.length) { throw new (_showDoctorError().default)(`Component ${_this2.component.id.toString()} is invalid as it has no files`); } _this2.component.dataToPersist = new (_dataToPersist().default)(); _this2._updateFilesBasePaths(); _this2.component.componentMap = _this2.existingComponentMap || _this2.addComponentToBitMap(_this2.writeToPath); _this2._copyFilesIntoDistsWhenDistsOutsideComponentDir(); _this2._determineWhetherToDeleteComponentDirContent(); yield _this2._handlePreviouslyNestedCurrentlyImportedCase(); _this2._determineWhetherToWriteConfig(); _this2._updateComponentRootPathAccordingToBitMap(); _this2._updateBitMapIfNeeded(); yield _this2._updateConsumerConfigIfNeeded(); _this2._determineWhetherToWritePackageJson(); yield _this2.populateFilesToWriteToComponentDir(packageManager); _this2.populateArtifacts(); return _this2.component; })(); } populateFilesToWriteToComponentDir(packageManager) { var _this3 = this; return (0, _bluebird().coroutine)(function* () { if (_this3.deleteBitDirContent) { _this3.component.dataToPersist.removePath(new (_removePath().default)(_this3.writeToPath)); } _this3.component.files.forEach(file => file.override = _this3.override); _this3.component.files.map(file => _this3.component.dataToPersist.addFile(file)); const dists = yield _this3.component.dists.getDistsToWrite(_this3.component, _this3.bitMap, _this3.consumer, false); if (dists) _this3.component.dataToPersist.merge(dists); if (_this3.writeConfig && _this3.consumer) { const configToWrite = yield _this3.component.getConfigToWrite(_this3.consumer, _this3.bitMap); _this3.component.dataToPersist.merge(configToWrite.dataToPersist); } // make sure the project's package.json is not overridden by Bit // If a consumer is of isolated env it's ok to override the root package.json (used by the env installation // of compilers / testers / extensions) if (_this3.writePackageJson && (_this3.isolated || _this3.consumer && _this3.consumer.isolated || _this3.writeToPath !== '.')) { const artifactsDir = _this3.getArtifactsDir(); const { packageJson, distPackageJson } = (0, _packageJsonUtils().preparePackageJsonToWrite)(_this3.bitMap, _this3.component, artifactsDir || _this3.writeToPath, _this3.override, _this3.writeBitDependencies, _this3.excludeRegistryPrefix, packageManager); const componentConfig = _componentConfig().default.fromComponent(_this3.component); // @todo: temporarily this is running only when there is no version (or version is "latest") // so then package.json always has a valid version. we'll need to figure out when the version // needs to be incremented and when it should not. if ((!_this3.consumer || _this3.consumer.isolated) && !_this3.component.id.hasVersion()) { // this only needs to be done in an isolated // or consumerless (dependency in an isolated) environment packageJson.addOrUpdateProperty('version', _this3._getNextPatchVersion()); } if (!_this3.consumer || _this3.consumer.isolated) { // bit-bin should not be installed in the capsule. it'll be symlinked later on. // see package-manager.linkBitBinInCapsule(); packageJson.removeDependency('bit-bin'); } componentConfig.setCompiler(_this3.component.compiler ? _this3.component.compiler.toBitJsonObject() : {}); componentConfig.setTester(_this3.component.tester ? _this3.component.tester.toBitJsonObject() : {}); packageJson.addOrUpdateProperty('bit', componentConfig.toPlainObject()); if (_this3.applyExtensionsAddedConfig) { _this3._mergePackageJsonPropsFromExtensions(packageJson); } _this3._mergeChangedPackageJsonProps(packageJson); _this3._mergePackageJsonPropsFromOverrides(packageJson); _this3.component.dataToPersist.addFile(packageJson.toVinylFile()); if (distPackageJson) _this3.component.dataToPersist.addFile(distPackageJson.toVinylFile()); _this3.component.packageJsonFile = packageJson; } // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! if (_this3.component.license && _this3.component.license.contents) { _this3.component.license.updatePaths({ newBase: _this3.writeToPath }); // $FlowFixMe this.component.license is set _this3.component.license.override = _this3.override; // $FlowFixMe this.component.license is set // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! _this3.component.dataToPersist.addFile(_this3.component.license); } })(); } /** * currently, it writes all artifacts. * later, this responsibility might move to pkg extension, which could write only artifacts * that are set in package.json.files[], to have a similar structure of a package. */ populateArtifacts() { const artifactsVinyl = _ramda().default.flatten(this.component.extensions.map(e => e.artifacts)); const artifactsDir = this.getArtifactsDir(); if (artifactsDir) { artifactsVinyl.forEach(a => a.updatePaths({ newBase: artifactsDir })); } this.component.dataToPersist.addManyFiles(artifactsVinyl); } getArtifactsDir() { if (!this.consumer || this.consumer.isLegacy) return null; if (this.origin === _constants().COMPONENT_ORIGINS.NESTED) return this.component.writtenPath; return (0, _componentNodeModulesPath().default)(this.consumer.config._bindingPrefix, this.component.id, true, this.component.defaultScope); } addComponentToBitMap(rootDir) { const filesForBitMap = this.component.files.map(file => { // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! return { name: file.basename, relativePath: (0, _path2().pathNormalizeToLinux)(file.relative), test: file.test }; }); return this.bitMap.addComponent({ componentId: this.component.id, files: filesForBitMap, mainFile: (0, _path2().pathNormalizeToLinux)(this.component.mainFile), rootDir, origin: this.origin, trackDir: this.existingComponentMap && this.existingComponentMap.trackDir, originallySharedDir: this.component.originallySharedDir, wrapDir: this.component.wrapDir }); } /** * these changes were added by extensions */ _mergePackageJsonPropsFromExtensions(packageJson) { // The special keys will be merged in other place const specialKeys = ['extensions', 'dependencies', 'devDependencies', 'peerDependencies']; if (!this.component.extensionsAddedConfig || _ramda().default.isEmpty(this.component.extensionsAddedConfig)) return; const valuesToMerge = _ramda().default.omit(specialKeys, this.component.extensionsAddedConfig); packageJson.mergePackageJsonObject(valuesToMerge); } /** * these changes were entered manually by a user via `overrides` key */ _mergePackageJsonPropsFromOverrides(packageJson) { const valuesToMerge = this.component.overrides.componentOverridesPackageJsonData; packageJson.mergePackageJsonObject(valuesToMerge); } /** * these are changes done by a compiler */ _mergeChangedPackageJsonProps(packageJson) { if (!this.component.packageJsonChangedProps) return; const valuesToMerge = this._replaceDistPathTemplateWithCalculatedDistPath(packageJson); packageJson.mergePackageJsonObject(valuesToMerge); } /** * see https://github.com/teambit/bit/issues/1808 for more info why it's needed */ _replaceDistPathTemplateWithCalculatedDistPath(packageJson) { // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! const packageJsonChangedProps = this.component.packageJsonChangedProps; const isReplaceNeeded = _ramda().default.values(packageJsonChangedProps).some(val => val.includes(_constants().COMPONENT_DIST_PATH_TEMPLATE)); if (!isReplaceNeeded) { return packageJsonChangedProps; } const distRootDir = this.component.dists.getDistDir(this.consumer, this.writeToPath || '.'); const distRelativeToPackageJson = (0, _path2().getPathRelativeRegardlessCWD)(path().dirname(packageJson.filePath), // $FlowFixMe distRootDir); return Object.keys(packageJsonChangedProps).reduce((acc, key) => { const val = packageJsonChangedProps[key].replace(_constants().COMPONENT_DIST_PATH_TEMPLATE, distRelativeToPackageJson); acc[key] = val; return acc; }, {}); } _copyFilesIntoDistsWhenDistsOutsideComponentDir() { if (!this.consumer) return; // not relevant when consumer is not available if (!this.consumer.shouldDistsBeInsideTheComponent() && this.component.dists.isEmpty()) { // since the dists are set to be outside the components dir, the source files must be saved there // otherwise, other components in dists won't be able to link to this component this.component.copyFilesIntoDists(); } } _updateComponentRootPathAccordingToBitMap() { // $FlowFixMe this.component.componentMap is set // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! this.writeToPath = this.component.componentMap.getRootDir(); this.component.writtenPath = this.writeToPath; this._updateFilesBasePaths(); } /** * when there is componentMap, this component (with this version or other version) is already part of the project. * There are several options as to what was the origin before and what is the origin now and according to this, * we update/remove/don't-touch the record in bit.map. * 1) current origin is AUTHORED - If the version is the same as before, don't update bit.map. Otherwise, update. * 2) current origin is IMPORTED - If the version is the same as before, don't update bit.map. Otherwise, update. * 3) current origin is NESTED - If it was not NESTED before, don't update. */ _updateBitMapIfNeeded() { if (this.isolated) return; const componentMapExistWithSameVersion = this.bitMap.isExistWithSameVersion(this.component.id); if (componentMapExistWithSameVersion) { if (this.existingComponentMap && // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! this.existingComponentMap !== _constants().COMPONENT_ORIGINS.NESTED && this.origin === _constants().COMPONENT_ORIGINS.NESTED) { return; } this.bitMap.removeComponent(this.component.id); } // $FlowFixMe this.component.componentMap is set // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! this.component.componentMap = this.addComponentToBitMap(this.component.componentMap.rootDir); } _updateConsumerConfigIfNeeded() { var _this4 = this; return (0, _bluebird().coroutine)(function* () { var _this4$component$comp2; // for authored components there is no bit.json/package.json component specific // so if the overrides or envs were changed, it should be written to the consumer-config const areEnvsChanged = /*#__PURE__*/function () { var _ref = (0, _bluebird().coroutine)(function* () { var _this4$component, _this4$component$comp; // $FlowFixMe this.component.componentMap is set // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! const context = { componentDir: (_this4$component = _this4.component) === null || _this4$component === void 0 ? void 0 : (_this4$component$comp = _this4$component.componentMap) === null || _this4$component$comp === void 0 ? void 0 : _this4$component$comp.getComponentDir() }; const compilerFromConsumer = _this4.consumer ? yield _this4.consumer.getEnv(_constants().COMPILER_ENV_TYPE, context) : undefined; const testerFromConsumer = _this4.consumer ? yield _this4.consumer.getEnv(_constants().TESTER_ENV_TYPE, context) : undefined; const compilerFromComponent = _this4.component.compiler ? _this4.component.compiler.toModelObject() : undefined; const testerFromComponent = _this4.component.tester ? _this4.component.tester.toModelObject() : undefined; return _envExtension().default.areEnvsDifferent(compilerFromConsumer ? compilerFromConsumer.toModelObject() : undefined, compilerFromComponent) || _envExtension().default.areEnvsDifferent(testerFromConsumer ? testerFromConsumer.toModelObject() : undefined, testerFromComponent); }); return function areEnvsChanged() { return _ref.apply(this, arguments); }; }(); if (((_this4$component$comp2 = _this4.component.componentMap) === null || _this4$component$comp2 === void 0 ? void 0 : _this4$component$comp2.origin) === _constants().COMPONENT_ORIGINS.AUTHORED && _this4.consumer) { var _this4$consumer, _this4$consumer$confi, _this4$consumer$confi2; const envsChanged = yield areEnvsChanged(); (_this4$consumer = _this4.consumer) === null || _this4$consumer === void 0 ? void 0 : (_this4$consumer$confi = _this4$consumer.config) === null || _this4$consumer$confi === void 0 ? void 0 : (_this4$consumer$confi2 = _this4$consumer$confi.componentsConfig) === null || _this4$consumer$confi2 === void 0 ? void 0 : _this4$consumer$confi2.updateOverridesIfChanged(_this4.component, envsChanged); } })(); } _determineWhetherToWriteConfig() { // $FlowFixMe this.component.componentMap is set // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! if (this.component.componentMap.origin === _constants().COMPONENT_ORIGINS.AUTHORED) { this.writeConfig = false; } } /** * don't write the package.json for an authored component, because its dependencies are managed * by the root package.json */ _determineWhetherToWritePackageJson() { this.writePackageJson = this.writePackageJson && this.origin !== _constants().COMPONENT_ORIGINS.AUTHORED; } /** * when a user imports a component that was a dependency before, write the component directly * into the components directory for an easy access/change. Then, remove the current record from * bit.map and add an updated one. */ _handlePreviouslyNestedCurrentlyImportedCase() { var _this5 = this; return (0, _bluebird().coroutine)(function* () { if (!_this5.consumer) return; // $FlowFixMe this.component.componentMap is set // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! if (_this5.origin === _constants().COMPONENT_ORIGINS.IMPORTED && _this5.component.componentMap.origin === _constants().COMPONENT_ORIGINS.NESTED) { yield _this5._cleanOldNestedComponent(); _this5.component.componentMap = _this5.addComponentToBitMap(_this5.writeToPath); } })(); } /** * For IMPORTED component we have to delete the content of the directory before importing. * Otherwise, when the author adds new files outside of the previous originallySharedDir and this user imports them * the environment will contain both copies, the old one with the old originallySharedDir and the new one. * If a user made changes to the imported component, it will show a warning and stop the process. */ _determineWhetherToDeleteComponentDirContent() { if (typeof this.deleteBitDirContent === 'undefined') { this.deleteBitDirContent = this.origin === _constants().COMPONENT_ORIGINS.IMPORTED; } } _updateFilesBasePaths() { const newBase = this.writeToPath || '.'; this.component.files.forEach(file => file.updatePaths({ newBase })); if (!this.component.dists.isEmpty()) { this.component.dists.get().forEach(dist => dist.updatePaths({ newBase })); } } _cleanOldNestedComponent() { var _this6 = this; return (0, _bluebird().coroutine)(function* () { if (!_this6.consumer) throw new Error('ComponentWriter._cleanOldNestedComponent expect to have a consumer'); // $FlowFixMe this function gets called when it was previously NESTED, so the rootDir is set // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! const oldLocation = path().join(_this6.consumer.getPath(), _this6.component.componentMap.rootDir); _logger().default.debugAndAddBreadCrumb('component-writer._cleanOldNestedComponent', 'deleting the old directory of a component at {oldLocation}', { oldLocation }); yield _fsExtra().default.remove(oldLocation); yield _this6._removeNodeModulesLinksFromDependents(); _this6.bitMap.removeComponent(_this6.component.id); })(); } _removeNodeModulesLinksFromDependents() { var _this7 = this; return (0, _bluebird().coroutine)(function* () { if (!_this7.consumer) { throw new Error('ComponentWriter._removeNodeModulesLinksFromDependents expect to have a consumer'); } const directDependentIds = yield _this7.consumer.getAuthoredAndImportedDependentsIdsOf([_this7.component]); yield Promise.all(directDependentIds.map(dependentId => { const dependentComponentMap = _this7.consumer ? _this7.consumer.bitMap.getComponent(dependentId) : null; const relativeLinkPath = _this7.consumer ? (0, _componentNodeModulesPath().default)(_this7.consumer.config._bindingPrefix, _this7.component.id) : null; const nodeModulesLinkAbs = _this7.consumer && dependentComponentMap && relativeLinkPath ? _this7.consumer.toAbsolutePath(path().join(dependentComponentMap.getRootDir(), relativeLinkPath)) : null; if (nodeModulesLinkAbs) { _logger().default.debug(`deleting an obsolete link to node_modules at ${nodeModulesLinkAbs}`); } return nodeModulesLinkAbs ? _fsExtra().default.remove(nodeModulesLinkAbs) : Promise.resolve(); })); })(); } _getNextPatchVersion() { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion return _semver().default.inc(this.component.version, 'prerelease') || '0.0.1-0'; } } exports.default = ComponentWriter;