@teambit/tracker 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,918 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ require("core-js/modules/es.array.iterator.js");
5
+ require("core-js/modules/es.array.sort.js");
6
+ require("core-js/modules/es.promise.js");
7
+ require("core-js/modules/es.regexp.exec.js");
8
+ Object.defineProperty(exports, "__esModule", {
9
+ value: true
10
+ });
11
+ exports.default = void 0;
12
+ function _defineProperty2() {
13
+ const data = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
14
+ _defineProperty2 = function () {
15
+ return data;
16
+ };
17
+ return data;
18
+ }
19
+ function _arrayDifference() {
20
+ const data = _interopRequireDefault(require("array-difference"));
21
+ _arrayDifference = function () {
22
+ return data;
23
+ };
24
+ return data;
25
+ }
26
+ function _fsExtra() {
27
+ const data = _interopRequireDefault(require("fs-extra"));
28
+ _fsExtra = function () {
29
+ return data;
30
+ };
31
+ return data;
32
+ }
33
+ function _ignore() {
34
+ const data = _interopRequireDefault(require("ignore"));
35
+ _ignore = function () {
36
+ return data;
37
+ };
38
+ return data;
39
+ }
40
+ function _lodash() {
41
+ const data = _interopRequireDefault(require("lodash.assignwith"));
42
+ _lodash = function () {
43
+ return data;
44
+ };
45
+ return data;
46
+ }
47
+ function _lodash2() {
48
+ const data = _interopRequireDefault(require("lodash.groupby"));
49
+ _lodash2 = function () {
50
+ return data;
51
+ };
52
+ return data;
53
+ }
54
+ function path() {
55
+ const data = _interopRequireWildcard(require("path"));
56
+ path = function () {
57
+ return data;
58
+ };
59
+ return data;
60
+ }
61
+ function _ramda() {
62
+ const data = _interopRequireDefault(require("ramda"));
63
+ _ramda = function () {
64
+ return data;
65
+ };
66
+ return data;
67
+ }
68
+ function _stringFormat() {
69
+ const data = _interopRequireDefault(require("string-format"));
70
+ _stringFormat = function () {
71
+ return data;
72
+ };
73
+ return data;
74
+ }
75
+ function _analytics() {
76
+ const data = require("@teambit/legacy/dist/analytics/analytics");
77
+ _analytics = function () {
78
+ return data;
79
+ };
80
+ return data;
81
+ }
82
+ function _bitId() {
83
+ const data = require("@teambit/legacy/dist/bit-id");
84
+ _bitId = function () {
85
+ return data;
86
+ };
87
+ return data;
88
+ }
89
+ function _constants() {
90
+ const data = require("@teambit/legacy/dist/constants");
91
+ _constants = function () {
92
+ return data;
93
+ };
94
+ return data;
95
+ }
96
+ function _generalError() {
97
+ const data = _interopRequireDefault(require("@teambit/legacy/dist/error/general-error"));
98
+ _generalError = function () {
99
+ return data;
100
+ };
101
+ return data;
102
+ }
103
+ function _showDoctorError() {
104
+ const data = _interopRequireDefault(require("@teambit/legacy/dist/error/show-doctor-error"));
105
+ _showDoctorError = function () {
106
+ return data;
107
+ };
108
+ return data;
109
+ }
110
+ function _links() {
111
+ const data = require("@teambit/legacy/dist/links");
112
+ _links = function () {
113
+ return data;
114
+ };
115
+ return data;
116
+ }
117
+ function _linkContent() {
118
+ const data = require("@teambit/legacy/dist/links/link-content");
119
+ _linkContent = function () {
120
+ return data;
121
+ };
122
+ return data;
123
+ }
124
+ function _logger() {
125
+ const data = _interopRequireDefault(require("@teambit/legacy/dist/logger/logger"));
126
+ _logger = function () {
127
+ return data;
128
+ };
129
+ return data;
130
+ }
131
+ function _utils() {
132
+ const data = require("@teambit/legacy/dist/utils");
133
+ _utils = function () {
134
+ return data;
135
+ };
136
+ return data;
137
+ }
138
+ function _path2() {
139
+ const data = require("@teambit/legacy/dist/utils/path");
140
+ _path2 = function () {
141
+ return data;
142
+ };
143
+ return data;
144
+ }
145
+ function _componentMap() {
146
+ const data = _interopRequireWildcard(require("@teambit/legacy/dist/consumer/bit-map/component-map"));
147
+ _componentMap = function () {
148
+ return data;
149
+ };
150
+ return data;
151
+ }
152
+ function _missingMainFile() {
153
+ const data = _interopRequireDefault(require("@teambit/legacy/dist/consumer/bit-map/exceptions/missing-main-file"));
154
+ _missingMainFile = function () {
155
+ return data;
156
+ };
157
+ return data;
158
+ }
159
+ function _exceptions() {
160
+ const data = require("@teambit/legacy/dist/consumer/component-ops/add-components/exceptions");
161
+ _exceptions = function () {
162
+ return data;
163
+ };
164
+ return data;
165
+ }
166
+ function _addingIndividualFiles() {
167
+ const data = require("@teambit/legacy/dist/consumer/component-ops/add-components/exceptions/adding-individual-files");
168
+ _addingIndividualFiles = function () {
169
+ return data;
170
+ };
171
+ return data;
172
+ }
173
+ function _missingMainFileMultipleComponents() {
174
+ const data = _interopRequireDefault(require("@teambit/legacy/dist/consumer/component-ops/add-components/exceptions/missing-main-file-multiple-components"));
175
+ _missingMainFileMultipleComponents = function () {
176
+ return data;
177
+ };
178
+ return data;
179
+ }
180
+ function _parentDirTracked() {
181
+ const data = require("@teambit/legacy/dist/consumer/component-ops/add-components/exceptions/parent-dir-tracked");
182
+ _parentDirTracked = function () {
183
+ return data;
184
+ };
185
+ return data;
186
+ }
187
+ function _pathOutsideConsumer() {
188
+ const data = _interopRequireDefault(require("@teambit/legacy/dist/consumer/component-ops/add-components/exceptions/path-outside-consumer"));
189
+ _pathOutsideConsumer = function () {
190
+ return data;
191
+ };
192
+ return data;
193
+ }
194
+ function _versionShouldBeRemoved() {
195
+ const data = _interopRequireDefault(require("@teambit/legacy/dist/consumer/component-ops/add-components/exceptions/version-should-be-removed"));
196
+ _versionShouldBeRemoved = function () {
197
+ return data;
198
+ };
199
+ return data;
200
+ }
201
+ function _determineMainFile() {
202
+ const data = _interopRequireDefault(require("./determine-main-file"));
203
+ _determineMainFile = function () {
204
+ return data;
205
+ };
206
+ return data;
207
+ }
208
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
209
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
210
+ const REGEX_DSL_PATTERN = /{([^}]+)}/g;
211
+ class AddComponents {
212
+ // id entered by the user
213
+
214
+ // (default = false) replace the files array or only add files.
215
+
216
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
217
+
218
+ // helpful for out-of-sync
219
+
220
+ // only bit-add (not bit-create/new) should handle out-of-sync scenario
221
+ constructor(context, addProps) {
222
+ (0, _defineProperty2().default)(this, "consumer", void 0);
223
+ (0, _defineProperty2().default)(this, "bitMap", void 0);
224
+ (0, _defineProperty2().default)(this, "componentPaths", void 0);
225
+ (0, _defineProperty2().default)(this, "id", void 0);
226
+ (0, _defineProperty2().default)(this, "main", void 0);
227
+ (0, _defineProperty2().default)(this, "namespace", void 0);
228
+ (0, _defineProperty2().default)(this, "override", void 0);
229
+ (0, _defineProperty2().default)(this, "trackDirFeature", void 0);
230
+ (0, _defineProperty2().default)(this, "warnings", void 0);
231
+ (0, _defineProperty2().default)(this, "ignoreList", void 0);
232
+ (0, _defineProperty2().default)(this, "gitIgnore", void 0);
233
+ (0, _defineProperty2().default)(this, "alternateCwd", void 0);
234
+ (0, _defineProperty2().default)(this, "addedComponents", void 0);
235
+ (0, _defineProperty2().default)(this, "defaultScope", void 0);
236
+ (0, _defineProperty2().default)(this, "config", void 0);
237
+ (0, _defineProperty2().default)(this, "shouldHandleOutOfSync", void 0);
238
+ this.alternateCwd = context.alternateCwd;
239
+ this.consumer = context.consumer;
240
+ this.bitMap = this.consumer.bitMap;
241
+ this.componentPaths = this.joinConsumerPathIfNeeded(addProps.componentPaths);
242
+ this.id = addProps.id;
243
+ this.main = addProps.main;
244
+ this.namespace = addProps.namespace;
245
+ this.override = addProps.override;
246
+ this.trackDirFeature = addProps.trackDirFeature;
247
+ this.warnings = {
248
+ alreadyUsed: {},
249
+ emptyDirectory: [],
250
+ existInScope: []
251
+ };
252
+ this.addedComponents = [];
253
+ this.defaultScope = addProps.defaultScope;
254
+ this.config = addProps.config;
255
+ this.shouldHandleOutOfSync = addProps.shouldHandleOutOfSync;
256
+ }
257
+ joinConsumerPathIfNeeded(paths) {
258
+ if (paths.length > 0) {
259
+ if (this.alternateCwd !== undefined && this.alternateCwd !== null) {
260
+ const alternate = this.alternateCwd;
261
+ return paths.map(file => path().join(alternate, file));
262
+ }
263
+ return paths;
264
+ }
265
+ return [];
266
+ }
267
+
268
+ /**
269
+ * @param {string[]} files - array of file-paths from which it should search for the dsl patterns.
270
+ * @param {*} filesWithPotentialDsl - array of file-path which may have DSL patterns
271
+ *
272
+ * @returns array of file-paths from 'files' parameter that match the patterns from 'filesWithPotentialDsl' parameter
273
+ */
274
+ async getFilesAccordingToDsl(files, filesWithPotentialDsl) {
275
+ const filesListAllMatches = filesWithPotentialDsl.map(async dsl => {
276
+ const filesListMatch = files.map(async file => {
277
+ const fileInfo = (0, _utils().calculateFileInfo)(file);
278
+ const generatedFile = (0, _stringFormat().default)(dsl, fileInfo);
279
+ const matches = await (0, _utils().glob)(generatedFile);
280
+ const matchesAfterGitIgnore = this.gitIgnore.filter(matches);
281
+ return matchesAfterGitIgnore.filter(match => _fsExtra().default.existsSync(match));
282
+ });
283
+ return Promise.all(filesListMatch);
284
+ });
285
+ const filesListFlatten = _ramda().default.flatten(await Promise.all(filesListAllMatches));
286
+ const filesListUnique = _ramda().default.uniq(filesListFlatten);
287
+ return filesListUnique.map(file => {
288
+ // when files array has the test file with different letter case, use the one from the file array
289
+ const fileNormalized = (0, _utils().pathNormalizeToLinux)(file);
290
+ const fileWithCorrectCase = files.find(f => f.toLowerCase() === fileNormalized.toLowerCase()) || fileNormalized;
291
+ const relativeToConsumer = this.consumer.getPathRelativeToConsumer(fileWithCorrectCase);
292
+ return (0, _utils().pathNormalizeToLinux)(relativeToConsumer);
293
+ });
294
+ }
295
+
296
+ /**
297
+ * unsupported files, such as, binary files, don't have link-file. instead, they have a symlink
298
+ * inside the component dir, pointing to the dependency.
299
+ * this methods check whether a file is auto generated for the unsupported files.
300
+ */
301
+ async _isGeneratedForUnsupportedFiles(fileRelativePath, componentId, componentMap) {
302
+ if ((0, _linkContent().isSupportedExtension)(fileRelativePath)) return false;
303
+ const componentFromModel = await this.consumer.loadComponentFromModelIfExist(componentId);
304
+ if (!componentFromModel) {
305
+ 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`);
306
+ }
307
+ const dependencies = componentFromModel.getAllDependenciesCloned();
308
+ const sourcePaths = dependencies.getSourcesPaths();
309
+ const sourcePathsRelativeToConsumer = sourcePaths.map(sourcePath => (0, _utils().pathJoinLinux)(componentMap.rootDir, sourcePath));
310
+ return sourcePathsRelativeToConsumer.includes(fileRelativePath);
311
+ }
312
+
313
+ /**
314
+ * for imported component, the package.json in the root directory is a bit-generated file and as
315
+ * such, it should be ignored
316
+ */
317
+ _isPackageJsonOnRootDir(pathRelativeToConsumerRoot, componentMap) {
318
+ if (!componentMap.rootDir) {
319
+ throw new Error('_isPackageJsonOnRootDir should not get called on non imported components');
320
+ }
321
+ return path().join(componentMap.rootDir, _constants().PACKAGE_JSON) === path().normalize(pathRelativeToConsumerRoot);
322
+ }
323
+
324
+ /**
325
+ * imported components might have wrapDir, when they do, files should not be added outside of
326
+ * that wrapDir
327
+ */
328
+ _isOutsideOfWrapDir(pathRelativeToConsumerRoot, componentMap) {
329
+ if (!componentMap.rootDir) {
330
+ throw new Error('_isOutsideOfWrapDir should not get called on non imported components');
331
+ }
332
+ if (!componentMap.wrapDir) return false;
333
+ const wrapDirRelativeToConsumerRoot = path().join(componentMap.rootDir, componentMap.wrapDir);
334
+ return !path().normalize(pathRelativeToConsumerRoot).startsWith(wrapDirRelativeToConsumerRoot);
335
+ }
336
+
337
+ /**
338
+ * Add or update existing (imported and new) component according to bitmap
339
+ * there are 3 options:
340
+ * 1. a user is adding a new component. there is no record for this component in bit.map
341
+ * 2. a user is updating an existing component. there is a record for this component in bit.map
342
+ * 3. some or all the files of this component were previously added as another component-id.
343
+ */
344
+ async addOrUpdateComponentInBitMap(component) {
345
+ const consumerPath = this.consumer.getPath();
346
+ const parsedBitId = component.componentId;
347
+ const componentFromScope = await this._getComponentFromScopeIfExist(parsedBitId);
348
+ const files = component.files;
349
+ const foundComponentFromBitMap = this.bitMap.getComponentIfExist(component.componentId, {
350
+ ignoreScopeAndVersion: true
351
+ });
352
+ const componentFilesP = files.map(async file => {
353
+ // $FlowFixMe null is removed later on
354
+ const filePath = path().join(consumerPath, file.relativePath);
355
+ const isAutoGenerated = await (0, _utils().isAutoGeneratedFile)(filePath);
356
+ if (isAutoGenerated) {
357
+ return null;
358
+ }
359
+ const caseSensitive = false;
360
+ const existingIdOfFile = this.bitMap.getComponentIdByPath(file.relativePath, caseSensitive);
361
+ const idOfFileIsDifferent = existingIdOfFile && !existingIdOfFile.isEqual(parsedBitId);
362
+ if (idOfFileIsDifferent) {
363
+ // not imported component file but exists in bitmap
364
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
365
+ if (this.warnings.alreadyUsed[existingIdOfFile]) {
366
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
367
+ this.warnings.alreadyUsed[existingIdOfFile].push(file.relativePath);
368
+ } else {
369
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
370
+ this.warnings.alreadyUsed[existingIdOfFile] = [file.relativePath];
371
+ }
372
+ return null;
373
+ }
374
+ if (!foundComponentFromBitMap && componentFromScope && this.shouldHandleOutOfSync) {
375
+ const newId = componentFromScope.toBitIdWithLatestVersion();
376
+ if (!this.defaultScope || this.defaultScope === newId.scope) {
377
+ // otherwise, if defaultScope !== newId.scope, they're different components,
378
+ // and no need to change the id.
379
+ // for more details about this scenario, see https://github.com/teambit/bit/issues/1543, last case.
380
+ component.componentId = newId;
381
+ this.warnings.existInScope.push(newId);
382
+ }
383
+ }
384
+ return file;
385
+ });
386
+ // @ts-ignore it can't be null due to the filter function
387
+ const componentFiles = (await Promise.all(componentFilesP)).filter(file => file);
388
+ if (!componentFiles.length) return {
389
+ id: component.componentId,
390
+ files: []
391
+ };
392
+ if (foundComponentFromBitMap) {
393
+ this._updateFilesAccordingToExistingRootDir(foundComponentFromBitMap, componentFiles, component);
394
+ }
395
+ if (this.trackDirFeature) {
396
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
397
+ if (this.bitMap._areFilesArraysEqual(foundComponentFromBitMap.files, componentFiles)) {
398
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
399
+ return foundComponentFromBitMap;
400
+ }
401
+ }
402
+ if (!this.override && foundComponentFromBitMap) {
403
+ this._updateFilesWithCurrentLetterCases(foundComponentFromBitMap, componentFiles);
404
+ component.files = this._mergeFilesWithExistingComponentMapFiles(componentFiles, foundComponentFromBitMap.files);
405
+ } else {
406
+ component.files = componentFiles;
407
+ }
408
+ const {
409
+ componentId,
410
+ trackDir
411
+ } = component;
412
+ const mainFile = (0, _determineMainFile().default)(component, foundComponentFromBitMap);
413
+ const getRootDir = () => {
414
+ if (this.trackDirFeature) throw new Error('track dir should not calculate the rootDir');
415
+ if (foundComponentFromBitMap) return foundComponentFromBitMap.rootDir;
416
+ if (!trackDir) throw new Error(`addOrUpdateComponentInBitMap expect to have trackDir for non-legacy workspace`);
417
+ const fileNotInsideTrackDir = componentFiles.find(file => !(0, _utils().pathNormalizeToLinux)(file.relativePath).startsWith(`${(0, _utils().pathNormalizeToLinux)(trackDir)}/`));
418
+ if (fileNotInsideTrackDir) {
419
+ // we check for this error before. however, it's possible that a user have one trackDir
420
+ // and another dir for the tests.
421
+ throw new (_addingIndividualFiles().AddingIndividualFiles)(fileNotInsideTrackDir.relativePath);
422
+ }
423
+ return (0, _utils().pathNormalizeToLinux)(trackDir);
424
+ };
425
+ const getComponentMap = () => {
426
+ if (this.trackDirFeature) {
427
+ return this.bitMap.addFilesToComponent({
428
+ componentId,
429
+ files: component.files
430
+ });
431
+ }
432
+ const rootDir = getRootDir();
433
+ const componentMap = this.bitMap.addComponent({
434
+ componentId,
435
+ files: component.files,
436
+ defaultScope: this.defaultScope,
437
+ config: this.config,
438
+ mainFile,
439
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
440
+ override: this.override
441
+ });
442
+ if (rootDir) componentMap.changeRootDirAndUpdateFilesAccordingly(rootDir);
443
+ return componentMap;
444
+ };
445
+ const componentMap = getComponentMap();
446
+ return {
447
+ id: componentId,
448
+ files: componentMap.files
449
+ };
450
+ }
451
+
452
+ /**
453
+ * current componentFiles are relative to the workspace. we want them relative to the rootDir.
454
+ */
455
+ _updateFilesAccordingToExistingRootDir(foundComponentFromBitMap, componentFiles, component) {
456
+ const existingRootDir = foundComponentFromBitMap.rootDir;
457
+ if (!existingRootDir) return; // nothing to do.
458
+ const areFilesInsideExistingRootDir = componentFiles.every(file => (0, _utils().pathNormalizeToLinux)(file.relativePath).startsWith(`${existingRootDir}/`));
459
+ if (areFilesInsideExistingRootDir) {
460
+ _componentMap().default.changeFilesPathAccordingToItsRootDir(existingRootDir, componentFiles);
461
+ return;
462
+ }
463
+ // some (or all) added files are outside the existing rootDir, the rootDir needs to be changed
464
+ // if a directory was added and it's a parent of the existing rootDir, change the rootDir to
465
+ // the currently added rootDir.
466
+ const currentlyAddedDir = (0, _utils().pathNormalizeToLinux)(component.trackDir);
467
+ const currentlyAddedDirParentOfRootDir = currentlyAddedDir && existingRootDir.startsWith(`${currentlyAddedDir}/`);
468
+ if (currentlyAddedDirParentOfRootDir) {
469
+ foundComponentFromBitMap.changeRootDirAndUpdateFilesAccordingly(currentlyAddedDir);
470
+ _componentMap().default.changeFilesPathAccordingToItsRootDir(currentlyAddedDir, componentFiles);
471
+ return;
472
+ }
473
+ throw new (_generalError().default)(`unable to add individual files outside the root dir (${existingRootDir}) of ${component.componentId}.
474
+ you can add the directory these files are located at and it'll change the root dir of the component accordingly`);
475
+ // we might want to change the behavior here to not throw an error and only change the rootDir to "."
476
+ // foundComponentFromBitMap.changeRootDirAndUpdateFilesAccordingly('.');
477
+ }
478
+
479
+ /**
480
+ * the risk with merging the currently added files with the existing bitMap files is overriding
481
+ * the `test` property. e.g. the component directory is re-added without adding the tests flag to
482
+ * track new files in that directory. in this case, we want to preserve the `test` property.
483
+ */
484
+ _mergeFilesWithExistingComponentMapFiles(componentFiles, existingComponentMapFile) {
485
+ return _ramda().default.unionWith(_ramda().default.eqBy(_ramda().default.prop('relativePath')), existingComponentMapFile, componentFiles);
486
+ }
487
+
488
+ /**
489
+ * if an existing file is for example uppercase and the new file is lowercase it has different
490
+ * behavior according to the OS. some OS are case sensitive, some are not.
491
+ * it's safer to avoid saving both files and instead, replacing the old file with the new one.
492
+ * in case a file has replaced and it is also a mainFile, replace the mainFile as well
493
+ */
494
+ _updateFilesWithCurrentLetterCases(currentComponentMap, newFiles) {
495
+ const currentFiles = currentComponentMap.files;
496
+ currentFiles.forEach(currentFile => {
497
+ const sameFile = newFiles.find(newFile => newFile.relativePath.toLowerCase() === currentFile.relativePath.toLowerCase());
498
+ if (sameFile && currentFile.relativePath !== sameFile.relativePath) {
499
+ if (currentComponentMap.mainFile === currentFile.relativePath) {
500
+ currentComponentMap.mainFile = sameFile.relativePath;
501
+ }
502
+ currentFile.relativePath = sameFile.relativePath;
503
+ }
504
+ });
505
+ }
506
+ async _getComponentFromScopeIfExist(id) {
507
+ try {
508
+ return await this.consumer.scope.getModelComponentIgnoreScope(id);
509
+ } catch (err) {
510
+ return null;
511
+ }
512
+ }
513
+
514
+ /**
515
+ * if the id is already saved in bitmap file, it might have more data (such as scope, version)
516
+ * use that id instead.
517
+ */
518
+ _getIdAccordingToExistingComponent(currentId) {
519
+ const existingComponentId = this.bitMap.getExistingBitId(currentId, false);
520
+ if (currentId.includes(_constants().VERSION_DELIMITER)) {
521
+ if (!existingComponentId ||
522
+ // this id is new, it shouldn't have a version
523
+ !existingComponentId.hasVersion() ||
524
+ // this component is new, it shouldn't have a version
525
+ // user shouldn't add files to a an existing component with different version
526
+ // $FlowFixMe this function gets called only when this.id is set
527
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
528
+ existingComponentId.version !== _bitId().BitId.getVersionOnlyFromString(this.id)) {
529
+ // $FlowFixMe this.id is defined here
530
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
531
+ throw new (_versionShouldBeRemoved().default)(this.id);
532
+ }
533
+ }
534
+ return existingComponentId || _bitId().BitId.parse(currentId, false);
535
+ }
536
+ _getIdAccordingToTrackDir(dir) {
537
+ const dirNormalizedToLinux = (0, _utils().pathNormalizeToLinux)(dir);
538
+ const trackDirs = this.bitMap.getAllTrackDirs();
539
+ if (!trackDirs) return null;
540
+ return trackDirs[dirNormalizedToLinux];
541
+ }
542
+
543
+ /**
544
+ * used for updating main file if exists or doesn't exists
545
+ */
546
+ _addMainFileToFiles(files) {
547
+ let mainFile = this.main;
548
+ if (mainFile && mainFile.match(REGEX_DSL_PATTERN)) {
549
+ // it's a DSL
550
+ files.forEach(file => {
551
+ const fileInfo = (0, _utils().calculateFileInfo)(file.relativePath);
552
+ const generatedFile = (0, _stringFormat().default)(mainFile, fileInfo);
553
+ const foundFile = this._findMainFileInFiles(generatedFile, files);
554
+ if (foundFile) {
555
+ mainFile = foundFile.relativePath;
556
+ }
557
+ if (_fsExtra().default.existsSync(generatedFile) && !foundFile) {
558
+ const shouldIgnore = this.gitIgnore.ignores(generatedFile);
559
+ if (shouldIgnore) {
560
+ // check if file is in exclude list
561
+ throw new (_exceptions().ExcludedMainFile)(generatedFile);
562
+ }
563
+ files.push({
564
+ relativePath: (0, _utils().pathNormalizeToLinux)(generatedFile),
565
+ test: false,
566
+ name: path().basename(generatedFile)
567
+ });
568
+ mainFile = generatedFile;
569
+ }
570
+ });
571
+ }
572
+ if (!mainFile) return undefined;
573
+ if (this.alternateCwd) {
574
+ mainFile = path().join(this.alternateCwd, mainFile);
575
+ }
576
+ const mainFileRelativeToConsumer = this.consumer.getPathRelativeToConsumer(mainFile);
577
+ const mainPath = this.consumer.toAbsolutePath(mainFileRelativeToConsumer);
578
+ if (_fsExtra().default.existsSync(mainPath)) {
579
+ const shouldIgnore = this.gitIgnore.ignores(mainFileRelativeToConsumer);
580
+ if (shouldIgnore) throw new (_exceptions().ExcludedMainFile)(mainFileRelativeToConsumer);
581
+ if ((0, _utils().isDir)(mainPath)) {
582
+ throw new (_exceptions().MainFileIsDir)(mainPath);
583
+ }
584
+ const foundFile = this._findMainFileInFiles(mainFileRelativeToConsumer, files);
585
+ if (foundFile) {
586
+ return foundFile.relativePath;
587
+ }
588
+ files.push({
589
+ relativePath: (0, _utils().pathNormalizeToLinux)(mainFileRelativeToConsumer),
590
+ test: false,
591
+ name: path().basename(mainFileRelativeToConsumer)
592
+ });
593
+ return mainFileRelativeToConsumer;
594
+ }
595
+ return mainFile;
596
+ }
597
+ _findMainFileInFiles(mainFile, files) {
598
+ const normalizedMainFile = (0, _utils().pathNormalizeToLinux)(mainFile).toLowerCase();
599
+ return files.find(file => file.relativePath.toLowerCase() === normalizedMainFile);
600
+ }
601
+
602
+ /**
603
+ * given the component paths, prepare the id, mainFile and files to be added later on to bitmap
604
+ * the id of the component is either entered by the user or, if not entered, concluded by the path.
605
+ * e.g. bar/foo.js, the id would be bar/foo.
606
+ * in case bitmap has already the same id, the complete id is taken from bitmap (see _getIdAccordingToExistingComponent)
607
+ */
608
+ async addOneComponent(componentPathsStats) {
609
+ let finalBitId; // final id to use for bitmap file
610
+ let idFromPath;
611
+ if (this.id) {
612
+ finalBitId = this._getIdAccordingToExistingComponent(this.id);
613
+ }
614
+ const componentsWithFilesP = Object.keys(componentPathsStats).map(async componentPath => {
615
+ if (componentPathsStats[componentPath].isDir) {
616
+ const relativeComponentPath = this.consumer.getPathRelativeToConsumer(componentPath);
617
+ this._throwForOutsideConsumer(relativeComponentPath);
618
+ this.throwForExistingParentDir(relativeComponentPath);
619
+ const matches = await (0, _utils().glob)(path().join(relativeComponentPath, '**'), {
620
+ cwd: this.consumer.getPath(),
621
+ nodir: true
622
+ });
623
+ if (!matches.length) throw new (_exceptions().EmptyDirectory)(componentPath);
624
+ const filteredMatches = this.gitIgnore.filter(matches);
625
+ if (!filteredMatches.length) {
626
+ throw new (_exceptions().NoFiles)(matches);
627
+ }
628
+ const filteredMatchedFiles = filteredMatches.map(match => {
629
+ return {
630
+ relativePath: (0, _utils().pathNormalizeToLinux)(match),
631
+ test: false,
632
+ name: path().basename(match)
633
+ };
634
+ });
635
+ const resolvedMainFile = this._addMainFileToFiles(filteredMatchedFiles);
636
+ const absoluteComponentPath = path().resolve(componentPath);
637
+ const splitPath = absoluteComponentPath.split(path().sep);
638
+ const lastDir = splitPath[splitPath.length - 1];
639
+ if (!finalBitId) {
640
+ const idOfTrackDir = this._getIdAccordingToTrackDir(componentPath);
641
+ if (idOfTrackDir) {
642
+ finalBitId = idOfTrackDir;
643
+ } else {
644
+ const nameSpaceOrDir = this.namespace || splitPath[splitPath.length - 2];
645
+ if (!this.namespace) {
646
+ idFromPath = {
647
+ namespace: _bitId().BitId.getValidIdChunk(nameSpaceOrDir),
648
+ name: _bitId().BitId.getValidIdChunk(lastDir)
649
+ };
650
+ }
651
+ finalBitId = _bitId().BitId.getValidBitId(nameSpaceOrDir, lastDir);
652
+ }
653
+ }
654
+ const getTrackDir = () => {
655
+ if (Object.keys(componentPathsStats).length === 1) {
656
+ return relativeComponentPath;
657
+ }
658
+ return undefined;
659
+ };
660
+ const trackDir = getTrackDir();
661
+ return {
662
+ componentId: finalBitId,
663
+ files: filteredMatchedFiles,
664
+ mainFile: resolvedMainFile,
665
+ trackDir,
666
+ idFromPath,
667
+ immediateDir: lastDir
668
+ };
669
+ }
670
+ // is file
671
+ const absolutePath = path().resolve(componentPath);
672
+ const pathParsed = path().parse(absolutePath);
673
+ const relativeFilePath = this.consumer.getPathRelativeToConsumer(componentPath);
674
+ this._throwForOutsideConsumer(relativeFilePath);
675
+ if (!finalBitId) {
676
+ let dirName = pathParsed.dir;
677
+ if (!dirName) {
678
+ dirName = path().dirname(absolutePath);
679
+ }
680
+ const nameSpaceOrLastDir = this.namespace || _ramda().default.last(dirName.split(path().sep));
681
+ if (!this.namespace) {
682
+ idFromPath = {
683
+ namespace: _bitId().BitId.getValidIdChunk(nameSpaceOrLastDir),
684
+ name: _bitId().BitId.getValidIdChunk(pathParsed.name)
685
+ };
686
+ }
687
+ finalBitId = _bitId().BitId.getValidBitId(nameSpaceOrLastDir, pathParsed.name);
688
+ }
689
+ const files = [{
690
+ relativePath: (0, _utils().pathNormalizeToLinux)(relativeFilePath),
691
+ test: false,
692
+ name: path().basename(relativeFilePath)
693
+ }];
694
+ const resolvedMainFile = this._addMainFileToFiles(files);
695
+ return {
696
+ componentId: finalBitId,
697
+ files,
698
+ mainFile: resolvedMainFile,
699
+ idFromPath
700
+ };
701
+ });
702
+ let componentsWithFiles = await Promise.all(componentsWithFilesP);
703
+
704
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
705
+ const componentId = finalBitId;
706
+ componentsWithFiles = componentsWithFiles.filter(componentWithFiles => componentWithFiles.files.length);
707
+
708
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
709
+ if (componentsWithFiles.length === 0) return {
710
+ componentId,
711
+ files: []
712
+ };
713
+ if (componentsWithFiles.length === 1) return componentsWithFiles[0];
714
+ const files = componentsWithFiles.reduce((a, b) => {
715
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
716
+ return a.concat(b.files);
717
+ }, []);
718
+ const groupedComponents = (0, _lodash2().default)(files, 'relativePath');
719
+ const uniqComponents = Object.keys(groupedComponents).map(key => (0, _lodash().default)({}, ...groupedComponents[key], (val1, val2) => val1 || val2));
720
+ return {
721
+ componentId,
722
+ files: uniqComponents,
723
+ mainFile: _ramda().default.head(componentsWithFiles).mainFile,
724
+ trackDir: _ramda().default.head(componentsWithFiles).trackDir,
725
+ idFromPath
726
+ };
727
+ }
728
+ getIgnoreList() {
729
+ const consumerPath = this.consumer.getPath();
730
+ return (0, _componentMap().getIgnoreListHarmony)(consumerPath);
731
+ }
732
+ async add() {
733
+ this.ignoreList = this.getIgnoreList();
734
+ this.gitIgnore = (0, _ignore().default)().add(this.ignoreList); // add ignore list
735
+
736
+ let componentPathsStats = {};
737
+ const resolvedComponentPathsWithoutGitIgnore = _ramda().default.flatten(await Promise.all(this.componentPaths.map(componentPath => (0, _utils().glob)(componentPath))));
738
+ this.gitIgnore = (0, _ignore().default)().add(this.ignoreList); // add ignore list
739
+
740
+ const resolvedComponentPathsWithGitIgnore = this.gitIgnore.filter(resolvedComponentPathsWithoutGitIgnore);
741
+ // Run diff on both arrays to see what was filtered out because of the gitignore file
742
+ const diff = (0, _arrayDifference().default)(resolvedComponentPathsWithGitIgnore, resolvedComponentPathsWithoutGitIgnore);
743
+ if (_ramda().default.isEmpty(resolvedComponentPathsWithoutGitIgnore)) {
744
+ throw new (_exceptions().PathsNotExist)(this.componentPaths);
745
+ }
746
+ if (!_ramda().default.isEmpty(resolvedComponentPathsWithGitIgnore)) {
747
+ componentPathsStats = validatePaths(resolvedComponentPathsWithGitIgnore);
748
+ } else {
749
+ throw new (_exceptions().NoFiles)(diff);
750
+ }
751
+ Object.keys(componentPathsStats).forEach(compPath => {
752
+ if (!componentPathsStats[compPath].isDir) {
753
+ throw new (_addingIndividualFiles().AddingIndividualFiles)(compPath);
754
+ }
755
+ });
756
+ // if a user entered multiple paths and entered an id, he wants all these paths to be one component
757
+ // conversely, if a user entered multiple paths without id, he wants each dir as an individual component
758
+ const isMultipleComponents = Object.keys(componentPathsStats).length > 1 && !this.id;
759
+ if (isMultipleComponents) {
760
+ await this.addMultipleComponents(componentPathsStats);
761
+ } else {
762
+ _logger().default.debugAndAddBreadCrumb('add-components', 'adding one component');
763
+ // when a user enters more than one directory, he would like to keep the directories names
764
+ // so then when a component is imported, it will write the files into the original directories
765
+ const addedOne = await this.addOneComponent(componentPathsStats);
766
+ this._removeNamespaceIfNotNeeded([addedOne]);
767
+ if (!_ramda().default.isEmpty(addedOne.files)) {
768
+ const addedResult = await this.addOrUpdateComponentInBitMap(addedOne);
769
+ if (addedResult) this.addedComponents.push(addedResult);
770
+ }
771
+ }
772
+ await this.linkComponents(this.addedComponents.map(item => item.id));
773
+ _analytics().Analytics.setExtraData('num_components', this.addedComponents.length);
774
+ return {
775
+ addedComponents: this.addedComponents,
776
+ warnings: this.warnings
777
+ };
778
+ }
779
+ async linkComponents(ids) {
780
+ if (this.trackDirFeature) {
781
+ // if trackDirFeature is set, it happens during the component-load and because we load the
782
+ // components in the next line, it gets into an infinite loop.
783
+ return;
784
+ }
785
+ const {
786
+ components
787
+ } = await this.consumer.loadComponents(_bitId().BitIds.fromArray(ids));
788
+ const nodeModuleLinker = new (_links().NodeModuleLinker)(components, this.consumer, this.consumer.bitMap);
789
+ await nodeModuleLinker.link();
790
+ }
791
+ async addMultipleComponents(componentPathsStats) {
792
+ _logger().default.debugAndAddBreadCrumb('add-components', 'adding multiple components');
793
+ this._removeDirectoriesWhenTheirFilesAreAdded(componentPathsStats);
794
+ const added = await this._tryAddingMultiple(componentPathsStats);
795
+ validateNoDuplicateIds(added);
796
+ this._removeNamespaceIfNotNeeded(added);
797
+ await this._addMultipleToBitMap(added);
798
+ }
799
+
800
+ /**
801
+ * some uses of wildcards might add directories and their files at the same time, in such cases
802
+ * only the files are needed and the directories can be ignored.
803
+ * @see https://github.com/teambit/bit/issues/1406 for more details
804
+ */
805
+ _removeDirectoriesWhenTheirFilesAreAdded(componentPathsStats) {
806
+ const allPaths = Object.keys(componentPathsStats);
807
+ allPaths.forEach(componentPath => {
808
+ const foundDir = allPaths.find(p => p === path().dirname(componentPath));
809
+ if (foundDir && componentPathsStats[foundDir]) {
810
+ _logger().default.debug(`add-components._removeDirectoriesWhenTheirFilesAreAdded, ignoring ${foundDir}`);
811
+ delete componentPathsStats[foundDir];
812
+ }
813
+ });
814
+ }
815
+ async _addMultipleToBitMap(added) {
816
+ const missingMainFiles = [];
817
+ await Promise.all(added.map(async component => {
818
+ if (!_ramda().default.isEmpty(component.files)) {
819
+ try {
820
+ const addedComponent = await this.addOrUpdateComponentInBitMap(component);
821
+ if (addedComponent && addedComponent.files.length) this.addedComponents.push(addedComponent);
822
+ } catch (err) {
823
+ if (!(err instanceof _missingMainFile().default)) throw err;
824
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
825
+ missingMainFiles.push(err);
826
+ }
827
+ }
828
+ }));
829
+ if (missingMainFiles.length) {
830
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
831
+ throw new (_missingMainFileMultipleComponents().default)(missingMainFiles.map(err => err.componentId).sort());
832
+ }
833
+ }
834
+ _removeNamespaceIfNotNeeded(addedComponents) {
835
+ const allIds = this.bitMap.getAllBitIdsFromAllLanes();
836
+ addedComponents.forEach(addedComponent => {
837
+ if (!addedComponent.idFromPath) return; // when the id was not generated from the path do nothing.
838
+ const componentsWithSameName = addedComponents // $FlowFixMe
839
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
840
+ .filter(a => a.idFromPath && a.idFromPath.name === addedComponent.idFromPath.name);
841
+ const bitIdFromNameOnly = new (_bitId().BitId)({
842
+ name: addedComponent.idFromPath.name
843
+ });
844
+ const existingComponentWithSameName = allIds.searchWithoutScopeAndVersion(bitIdFromNameOnly);
845
+ if (componentsWithSameName.length === 1 && !existingComponentWithSameName) {
846
+ addedComponent.componentId = bitIdFromNameOnly;
847
+ }
848
+ });
849
+ }
850
+ async _tryAddingMultiple(componentPathsStats) {
851
+ const addedP = Object.keys(componentPathsStats).map(async onePath => {
852
+ const oneComponentPathStat = {
853
+ [onePath]: componentPathsStats[onePath]
854
+ };
855
+ try {
856
+ const addedComponent = await this.addOneComponent(oneComponentPathStat);
857
+ return addedComponent;
858
+ } catch (err) {
859
+ if (!(err instanceof _exceptions().EmptyDirectory)) throw err;
860
+ this.warnings.emptyDirectory.push(onePath);
861
+ return null;
862
+ }
863
+ });
864
+ const added = await Promise.all(addedP);
865
+ return _ramda().default.reject(_ramda().default.isNil, added);
866
+ }
867
+ _throwForOutsideConsumer(relativeToConsumerPath) {
868
+ if (relativeToConsumerPath.startsWith('..')) {
869
+ throw new (_pathOutsideConsumer().default)(relativeToConsumerPath);
870
+ }
871
+ }
872
+ throwForExistingParentDir(relativeToConsumerPath) {
873
+ const isParentDir = parent => {
874
+ const relative = path().relative(parent, relativeToConsumerPath);
875
+ return relative && !relative.startsWith('..') && !path().isAbsolute(relative);
876
+ };
877
+ this.bitMap.components.forEach(componentMap => {
878
+ if (!componentMap.rootDir) return;
879
+ if (isParentDir(componentMap.rootDir)) {
880
+ throw new (_parentDirTracked().ParentDirTracked)(componentMap.rootDir, componentMap.id.toStringWithoutVersion(), relativeToConsumerPath);
881
+ }
882
+ });
883
+ }
884
+ }
885
+
886
+ /**
887
+ * validatePaths - validate if paths entered by user exist and if not throw an error
888
+ *
889
+ * @param {string[]} fileArray - array of paths
890
+ * @returns {PathsStats} componentPathsStats
891
+ */
892
+ exports.default = AddComponents;
893
+ function validatePaths(fileArray) {
894
+ const componentPathsStats = {};
895
+ fileArray.forEach(componentPath => {
896
+ if (!_fsExtra().default.existsSync(componentPath)) {
897
+ throw new (_exceptions().PathsNotExist)([componentPath]);
898
+ }
899
+ componentPathsStats[componentPath] = {
900
+ isDir: (0, _utils().isDir)(componentPath)
901
+ };
902
+ });
903
+ return componentPathsStats;
904
+ }
905
+
906
+ /**
907
+ * validate that no two files where added with the same id in the same bit add command
908
+ */
909
+ function validateNoDuplicateIds(addComponents) {
910
+ const duplicateIds = {};
911
+ const newGroupedComponents = (0, _lodash2().default)(addComponents, 'componentId');
912
+ Object.keys(newGroupedComponents).forEach(key => {
913
+ if (newGroupedComponents[key].length > 1) duplicateIds[key] = newGroupedComponents[key];
914
+ });
915
+ if (!_ramda().default.isEmpty(duplicateIds) && !_ramda().default.isNil(duplicateIds)) throw new (_exceptions().DuplicateIds)(duplicateIds);
916
+ }
917
+
918
+ //# sourceMappingURL=add-components.js.map