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

620 lines (468 loc) 21.7 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 _ramda() { const data = _interopRequireDefault(require("ramda")); _ramda = function () { return data; }; return data; } function _glob() { const data = _interopRequireDefault(require("glob")); _glob = 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 _utils() { const data = require("../utils"); _utils = function () { return data; }; return data; } function _linkGenerator() { const data = require("./link-generator"); _linkGenerator = function () { return data; }; return data; } function _linkContent() { const data = require("./link-content"); _linkContent = function () { return data; }; return data; } function _componentNodeModulesPath() { const data = _interopRequireDefault(require("../utils/bit/component-node-modules-path")); _componentNodeModulesPath = function () { return data; }; return data; } function _symlink() { const data = _interopRequireDefault(require("./symlink")); _symlink = function () { return data; }; return data; } function _dataToPersist() { const data = _interopRequireDefault(require("../consumer/component/sources/data-to-persist")); _dataToPersist = function () { return data; }; return data; } function _linkFile() { const data = _interopRequireDefault(require("./link-file")); _linkFile = function () { return data; }; return data; } function _componentsList() { const data = _interopRequireDefault(require("../consumer/component/components-list")); _componentsList = function () { return data; }; return data; } function _packageJsonFile() { const data = _interopRequireDefault(require("../consumer/component/package-json-file")); _packageJsonFile = function () { return data; }; return data; } function _path2() { const data = require("../utils/path"); _path2 = function () { return data; }; return data; } function _removePath() { const data = _interopRequireDefault(require("../consumer/component/sources/remove-path")); _removePath = function () { return data; }; return data; } /** * link given components to node_modules, so it's possible to use absolute link instead of relative * for example, require('@bit/remote-scope.bar.foo) */ class NodeModuleLinker { // preparation for the capsule, which is going to have only BitMap with no Consumer constructor(components, consumer, bitMap) { (0, _defineProperty2().default)(this, "components", void 0); (0, _defineProperty2().default)(this, "consumer", void 0); (0, _defineProperty2().default)(this, "bitMap", void 0); (0, _defineProperty2().default)(this, "dataToPersist", void 0); this.components = _componentsList().default.getUniqueComponents(components); this.consumer = consumer; this.bitMap = bitMap; this.dataToPersist = new (_dataToPersist().default)(); } link() { var _this = this; return (0, _bluebird().coroutine)(function* () { const links = yield _this.getLinks(); const linksResults = _this.getLinksResults(); if (_this.consumer) links.addBasePath(_this.consumer.getPath()); yield links.persistAllToFS(); return linksResults; })(); } getLinks() { var _this2 = this; return (0, _bluebird().coroutine)(function* () { _this2.dataToPersist = new (_dataToPersist().default)(); yield _this2._populateShouldDependenciesSavedAsComponentsData(); yield Promise.all(_this2.components.map(component => { const componentId = component.id.toString(); _logger().default.debug(`linking component to node_modules: ${componentId}`); const componentMap = _this2.bitMap.getComponent(component.id); component.componentMap = componentMap; switch (componentMap.origin) { case _constants().COMPONENT_ORIGINS.IMPORTED: return _this2._populateImportedComponentsLinks(component); case _constants().COMPONENT_ORIGINS.NESTED: return _this2._populateNestedComponentsLinks(component); case _constants().COMPONENT_ORIGINS.AUTHORED: return _this2._populateAuthoredComponentsLinks(component); default: throw new Error(`ComponentMap.origin ${componentMap.origin} of ${componentId} is not recognized`); } })); return _this2.dataToPersist; })(); } getLinksResults() { const linksResults = []; const getExistingLinkResult = id => linksResults.find(linkResult => linkResult.id.isEqual(id)); const addLinkResult = (id, from, to) => { if (!id) return; const existingLinkResult = getExistingLinkResult(id); if (existingLinkResult) { existingLinkResult.bound.push({ from, to }); } else { linksResults.push({ id, bound: [{ from, to }] }); } }; this.dataToPersist.symlinks.forEach(symlink => { addLinkResult(symlink.componentId, symlink.src, symlink.dest); }); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! this.dataToPersist.files.forEach(file => { // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! addLinkResult(file.componentId, file.srcPath, file.path); }); this.components.forEach(component => { const existingLinkResult = getExistingLinkResult(component.id); if (!existingLinkResult) { linksResults.push({ id: component.id, bound: [] }); } }); return linksResults; } _populateImportedComponentsLinks(component) { var _this3 = this; return (0, _bluebird().coroutine)(function* () { if (_this3.consumer && !_this3.consumer.isLegacy) { yield _this3._populateImportedNonLegacyComponentsLinks(component); return; } const componentMap = component.componentMap; const componentId = component.id; // @todo: this should probably be `const bindingPrefix = component.bindingPrefix;` const bindingPrefix = component.bindingPrefix || _constants().DEFAULT_BINDINGS_PREFIX; const linkPath = (0, _componentNodeModulesPath().default)(bindingPrefix, componentId, true, _this3._getDefaultScope(component)); // when a user moves the component directory, use component.writtenPath to find the correct target // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! const srcTarget = component.writtenPath || componentMap.rootDir; const shouldDistsBeInsideTheComponent = _this3.consumer ? _this3.consumer.shouldDistsBeInsideTheComponent() : true; if (_this3.consumer && !component.dists.isEmpty() && component.dists.writeDistsFiles && !shouldDistsBeInsideTheComponent) { // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! const distTarget = component.dists.getDistDir(_this3.consumer, componentMap.getRootDir()); const packagesSymlinks = _this3._getSymlinkPackages(srcTarget, distTarget, component); _this3.dataToPersist.addManySymlinks(packagesSymlinks); const distSymlink = _symlink().default.makeInstance(distTarget, linkPath, componentId); distSymlink.forDistOutsideComponentsDir = true; _this3.dataToPersist.addSymlink(distSymlink); } else if (srcTarget !== '.') { // avoid creating symlinks from node_modules to itself _this3.dataToPersist.addSymlink(_symlink().default.makeInstance(srcTarget, linkPath, componentId)); } yield _this3._populateDependenciesAndMissingLinks(component); })(); } _populateNestedComponentsLinks(component) { var _this4 = this; return (0, _bluebird().coroutine)(function* () { yield _this4._populateDependenciesAndMissingLinks(component); })(); } _getDefaultScope(component) { if (component) { return component.defaultScope; } return this.consumer ? this.consumer.config.defaultScope : null; } /** * for Harmony version and above, instead of symlink from the component dir to node_modules, * create a directory on node_modules and symlink each one of the source files, this way, the * structure is exactly the same as Authored */ _populateImportedNonLegacyComponentsLinks(component) { var _this5 = this; return (0, _bluebird().coroutine)(function* () { const componentId = component.id; const linkPath = (0, _componentNodeModulesPath().default)(component.bindingPrefix, componentId, true, _this5._getDefaultScope(component)); const componentMap = component.componentMap; const filesToBind = componentMap.getAllFilesPaths(); filesToBind.forEach(file => { const fileWithRootDir = componentMap.hasRootDir() ? path().join(componentMap.rootDir, file) : file; const dest = path().join(linkPath, file); _this5.dataToPersist.addSymlink(_symlink().default.makeInstance(fileWithRootDir, dest, componentId)); }); yield _this5._populateDependenciesAndMissingLinks(component); })(); } /** * even when an authored component has rootDir, we can't just symlink that rootDir to * node_modules/rootDir. it could work only when the main-file is index.js, not for other cases. * node expects the module inside node_modules to have either package.json with valid "main" * property or an index.js file. this main property can't be relative. */ _populateAuthoredComponentsLinks(component) { const componentId = component.id; const linkPath = (0, _componentNodeModulesPath().default)(component.bindingPrefix, componentId, true, this._getDefaultScope(component)); const componentMap = component.componentMap; const filesToBind = componentMap.getAllFilesPaths(); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! component.dists.updateDistsPerWorkspaceConfig(component.id, this.consumer, component.componentMap); filesToBind.forEach(file => { // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! const isMain = file === componentMap.mainFile; const fileWithRootDir = componentMap.hasRootDir() ? path().join(componentMap.rootDir, file) : file; const possiblyDist = component.dists.calculateDistFileForAuthored(path().normalize(fileWithRootDir), // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! this.consumer, isMain); const dest = path().join(linkPath, file); const destRelative = (0, _path2().getPathRelativeRegardlessCWD)(path().dirname(dest), possiblyDist); const fileContent = (0, _linkContent().getLinkToFileContent)(destRelative); // if component.compiler is set, this component is working with the old compiler (< v15) // and not with compile extension. as such, the dists for author are in the root, not in the // component directory. Having symlinks here instead of links causes import of module-paths to // break. try e2e-test: 'as author, move individual component files to dedicated directory with bit move --component' if (fileContent && component.compiler) { const linkFile = _linkFile().default.load({ filePath: dest, content: fileContent, srcPath: file, componentId, override: true, ignorePreviousSymlink: true // in case the component didn't have a compiler before, this file was a symlink }); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! this.dataToPersist.addFile(linkFile); } else { // it's an un-supported file, or it's Harmony version and above, create a symlink instead this.dataToPersist.addSymlink(_symlink().default.makeInstance(fileWithRootDir, dest, componentId)); } }); this._deleteOldLinksOfIdWithoutScope(component); this._createPackageJsonForAuthor(component); } /** * for AUTHORED components, when a component is new, upon build, we generate links on * node_modules. The path doesn't have the scope-name as it doesn't exist yet. (e.g. @bit/foo). * Later on, when the component is exported and has a scope-name, the path is complete. * (e.g. @bit/scope.foo). At this stage, this function deletes the old-partial paths. */ _deleteOldLinksOfIdWithoutScope(component) { if (component.id.scope) { const previousDest = (0, _componentNodeModulesPath().default)(component.bindingPrefix, component.id.changeScope(null), true, this._getDefaultScope(component)); this.dataToPersist.removePath(new (_removePath().default)(previousDest)); } } /** * for IMPORTED and NESTED components */ _populateDependenciesAndMissingLinks(component) { var _this6 = this; return (0, _bluebird().coroutine)(function* () { // $FlowFixMe loaded from FS, componentMap must be set // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! const componentMap = component.componentMap; if (component.issues && ( // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! component.issues.missingLinks || component.issues.missingCustomModuleResolutionLinks) && _this6.consumer && component.componentFromModel) { const componentWithDependencies = yield component.toComponentWithDependencies(_this6.consumer); component.copyAllDependenciesFromModel(); const componentsDependenciesLinks = (0, _linkGenerator().getComponentsDependenciesLinks)([componentWithDependencies], _this6.consumer, false, _this6.bitMap); _this6.dataToPersist.addManyFiles(componentsDependenciesLinks.files); _this6.dataToPersist.addManySymlinks(componentsDependenciesLinks.symlinks); } if (component.hasDependencies()) { const dependenciesLinks = yield _this6._getDependenciesLinks(component, componentMap); _this6.dataToPersist.addManySymlinks(dependenciesLinks); } })(); } /** * When the dists is outside the components directory, it doesn't have access to the node_modules of the component's * root-dir. The solution is to go through the node_modules packages one by one and symlink them. */ _getSymlinkPackages(from, to, component) { if (!this.consumer) throw new Error('getSymlinkPackages expects the Consumer to be defined'); const dependenciesSavedAsComponents = component.dependenciesSavedAsComponents; const fromNodeModules = path().join(from, 'node_modules'); const toNodeModules = path().join(to, 'node_modules'); _logger().default.debug(`symlinkPackages for dists outside the component directory from ${fromNodeModules} to ${toNodeModules}`); const unfilteredDirs = _glob().default.sync('*', { cwd: fromNodeModules }); // when dependenciesSavedAsComponents the node_modules/@bit has real link files, we don't want to touch them // otherwise, node_modules/@bit has packages as any other directory in node_modules const dirsToFilter = dependenciesSavedAsComponents ? [this.consumer.config._bindingPrefix] : []; const customResolvedData = component.dependencies.getCustomResolvedData(); if (!_ramda().default.isEmpty(customResolvedData)) { // filter out packages that are actually symlinks to dependencies Object.keys(customResolvedData).forEach(importSource => dirsToFilter.push((0, _utils().first)(importSource.split('/')))); } const dirs = dirsToFilter.length ? unfilteredDirs.filter(dir => !dirsToFilter.includes(dir)) : unfilteredDirs; if (!dirs.length) return []; return dirs.map(dir => { const fromDir = path().join(fromNodeModules, dir); const toDir = path().join(toNodeModules, dir); return _symlink().default.makeInstance(fromDir, toDir); }); } _getDependenciesLinks(component, componentMap) { var _this7 = this; return (0, _bluebird().coroutine)(function* () { const getSymlinks = /*#__PURE__*/function () { var _ref = (0, _bluebird().coroutine)(function* (dependency) { var _this7$consumer; const dependencyComponentMap = _this7.bitMap.getComponentIfExist(dependency.id); const depModel = yield ((_this7$consumer = _this7.consumer) === null || _this7$consumer === void 0 ? void 0 : _this7$consumer.scope.getModelComponentIfExist(dependency.id)) || Promise.resolve(); const bindingPrefix = depModel ? depModel.bindingPrefix : _constants().DEFAULT_BINDINGS_PREFIX; const dependenciesLinks = []; if (!dependencyComponentMap || !dependencyComponentMap.hasRootDir()) return dependenciesLinks; const parentRootDir = componentMap.getRootDir(); const dependencyRootDir = dependencyComponentMap.getRootDir(); dependenciesLinks.push(_this7._getDependencyLink(parentRootDir, dependency.id, dependencyRootDir, bindingPrefix)); if (_this7.consumer && !_this7.consumer.shouldDistsBeInsideTheComponent()) { // when dists are written outside the component, it doesn't matter whether a component // has dists files or not, in case it doesn't have, the files are copied from the component // dir into the dist dir. (see consumer-component.write()) const from = component.dists.getDistDirForConsumer(_this7.consumer, parentRootDir); const to = component.dists.getDistDirForConsumer(_this7.consumer, dependencyRootDir); const distSymlink = _this7._getDependencyLink(from, dependency.id, to, bindingPrefix); distSymlink.forDistOutsideComponentsDir = true; dependenciesLinks.push(distSymlink); } return dependenciesLinks; }); return function getSymlinks(_x) { return _ref.apply(this, arguments); }; }(); const symlinksP = component.getAllDependencies().map(dependency => getSymlinks(dependency)); const symlinks = yield Promise.all(symlinksP); return _ramda().default.flatten(symlinks); })(); } _getDependencyLink(parentRootDir, bitId, rootDir, bindingPrefix) { const relativeDestPath = (0, _componentNodeModulesPath().default)(bindingPrefix, bitId, true, this._getDefaultScope()); const destPathInsideParent = path().join(parentRootDir, relativeDestPath); return _symlink().default.makeInstance(rootDir, destPathInsideParent, bitId); } /** * create package.json on node_modules/@bit/component-name/package.json with a property 'main' * pointing to the component's main file. * It is needed for Authored components only. * Since an authored component doesn't have rootDir, it's impossible to symlink to the component directory. * It makes it easier for Author to use absolute syntax between their own components. */ _createPackageJsonForAuthor(component) { // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! const hasPackageJsonAsComponentFile = component.files.some(file => file.relative === _constants().PACKAGE_JSON); if (hasPackageJsonAsComponentFile) return; // don't generate package.json on top of the user package.json const dest = path().join((0, _componentNodeModulesPath().default)(component.bindingPrefix, component.id, true, this._getDefaultScope(component))); const packageJson = _packageJsonFile().default.createFromComponent(dest, component); this.dataToPersist.addFile(packageJson.toVinylFile()); } /** * links are normally generated by `bit import`, `bit link` and `bit install`. * for `bit import` the data about whether dependenciesSavedAsComponents is already populated * for the rest, it's not. * @todo: avoid repopulating for imported. (not easy because by default, all components get "true"). */ _populateShouldDependenciesSavedAsComponentsData() { var _this8 = this; return (0, _bluebird().coroutine)(function* () { if (!_this8.components.length || !_this8.consumer) return; const bitIds = _this8.components.map(c => c.id); const shouldDependenciesSavedAsComponents = yield _this8.consumer.shouldDependenciesSavedAsComponents(bitIds); _this8.components.forEach(component => { const shouldSavedAsComponents = shouldDependenciesSavedAsComponents.find(c => c.id.isEqual(component.id)); if (!shouldSavedAsComponents) { throw new Error(`_populateShouldDependenciesSavedAsComponentsData, saveDependenciesAsComponents is missing for ${component.id.toString()}`); } component.dependenciesSavedAsComponents = shouldSavedAsComponents.saveDependenciesAsComponents; }); })(); } } exports.default = NodeModuleLinker;