@teambit/doctor 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.
Files changed (83) hide show
  1. package/core-diagnoses/broken-symlink-files.ts +78 -0
  2. package/core-diagnoses/orphan-symlink-objects.ts +51 -0
  3. package/core-diagnoses/validate-bit-version.ts +56 -0
  4. package/core-diagnoses/validate-git-exec.ts +38 -0
  5. package/core-diagnoses/validate-npm-exec.ts +40 -0
  6. package/core-diagnoses/validate-workspace-bit-json-syntax.ts +35 -0
  7. package/core-diagnoses/validate-yarn-exec.ts +40 -0
  8. package/diagnosis-list-template.ts +28 -0
  9. package/diagnosis.ts +81 -0
  10. package/dist/core-diagnoses/broken-symlink-files.d.ts +15 -0
  11. package/dist/core-diagnoses/broken-symlink-files.js +127 -0
  12. package/dist/core-diagnoses/broken-symlink-files.js.map +1 -0
  13. package/dist/core-diagnoses/orphan-symlink-objects.d.ts +10 -0
  14. package/dist/core-diagnoses/orphan-symlink-objects.js +84 -0
  15. package/dist/core-diagnoses/orphan-symlink-objects.js.map +1 -0
  16. package/dist/core-diagnoses/validate-bit-version.d.ts +9 -0
  17. package/dist/core-diagnoses/validate-bit-version.js +94 -0
  18. package/dist/core-diagnoses/validate-bit-version.js.map +1 -0
  19. package/dist/core-diagnoses/validate-git-exec.d.ts +10 -0
  20. package/dist/core-diagnoses/validate-git-exec.js +69 -0
  21. package/dist/core-diagnoses/validate-git-exec.js.map +1 -0
  22. package/dist/core-diagnoses/validate-npm-exec.d.ts +10 -0
  23. package/dist/core-diagnoses/validate-npm-exec.js +73 -0
  24. package/dist/core-diagnoses/validate-npm-exec.js.map +1 -0
  25. package/dist/core-diagnoses/validate-workspace-bit-json-syntax.d.ts +9 -0
  26. package/dist/core-diagnoses/validate-workspace-bit-json-syntax.js +67 -0
  27. package/dist/core-diagnoses/validate-workspace-bit-json-syntax.js.map +1 -0
  28. package/dist/core-diagnoses/validate-yarn-exec.d.ts +10 -0
  29. package/dist/core-diagnoses/validate-yarn-exec.js +72 -0
  30. package/dist/core-diagnoses/validate-yarn-exec.js.map +1 -0
  31. package/dist/diagnosis-list-template.d.ts +2 -0
  32. package/dist/diagnosis-list-template.js +42 -0
  33. package/dist/diagnosis-list-template.js.map +1 -0
  34. package/dist/diagnosis.d.ts +41 -0
  35. package/dist/diagnosis.js +74 -0
  36. package/dist/diagnosis.js.map +1 -0
  37. package/dist/doctor-cmd.d.ts +21 -0
  38. package/dist/doctor-cmd.js +125 -0
  39. package/dist/doctor-cmd.js.map +1 -0
  40. package/dist/doctor-registrar-builder.d.ts +2 -0
  41. package/dist/doctor-registrar-builder.js +69 -0
  42. package/dist/doctor-registrar-builder.js.map +1 -0
  43. package/dist/doctor-registrar.d.ts +21 -0
  44. package/dist/doctor-registrar.js +63 -0
  45. package/dist/doctor-registrar.js.map +1 -0
  46. package/dist/doctor-results-template.d.ts +2 -0
  47. package/dist/doctor-results-template.js +115 -0
  48. package/dist/doctor-results-template.js.map +1 -0
  49. package/dist/doctor.aspect.d.ts +2 -0
  50. package/dist/doctor.aspect.js +18 -0
  51. package/dist/doctor.aspect.js.map +1 -0
  52. package/dist/doctor.d.ts +31 -0
  53. package/dist/doctor.js +342 -0
  54. package/dist/doctor.js.map +1 -0
  55. package/dist/doctor.main.runtime.d.ts +8 -0
  56. package/dist/doctor.main.runtime.js +44 -0
  57. package/dist/doctor.main.runtime.js.map +1 -0
  58. package/dist/esm.mjs +6 -0
  59. package/dist/exceptions/diagnosis-not-found.d.ts +5 -0
  60. package/dist/exceptions/diagnosis-not-found.js +30 -0
  61. package/dist/exceptions/diagnosis-not-found.js.map +1 -0
  62. package/dist/exceptions/missing-diagnosis-name.d.ts +4 -0
  63. package/dist/exceptions/missing-diagnosis-name.js +21 -0
  64. package/dist/exceptions/missing-diagnosis-name.js.map +1 -0
  65. package/dist/index.d.ts +6 -0
  66. package/dist/index.js +48 -0
  67. package/dist/index.js.map +1 -0
  68. package/dist/preview-1719544843434.js +7 -0
  69. package/doctor-cmd.ts +97 -0
  70. package/doctor-registrar-builder.ts +22 -0
  71. package/doctor-registrar.ts +58 -0
  72. package/doctor-results-template.ts +105 -0
  73. package/doctor.aspect.ts +5 -0
  74. package/doctor.main.runtime.ts +17 -0
  75. package/doctor.ts +250 -0
  76. package/esm.mjs +6 -0
  77. package/exceptions/diagnosis-not-found.ts +8 -0
  78. package/exceptions/missing-diagnosis-name.ts +7 -0
  79. package/index.ts +7 -0
  80. package/package.json +54 -0
  81. package/tsconfig.json +45 -0
  82. package/types/asset.d.ts +29 -0
  83. package/types/style.d.ts +42 -0
@@ -0,0 +1,78 @@
1
+ import fs from 'fs-extra';
2
+ import glob from 'glob';
3
+ import path from 'path';
4
+ import { loadConsumer } from '@teambit/legacy/dist/consumer';
5
+ import { Scope } from '@teambit/legacy/dist/scope';
6
+ import Diagnosis, { ExamineBareResult } from '../diagnosis';
7
+ import { uniq } from 'lodash';
8
+
9
+ type BrokenSymlink = { symlinkPath: string; brokenPath: string; pathToDelete: string };
10
+ export const DIAGNOSIS_NAME = 'check environment symlinks';
11
+
12
+ export default class BrokenSymlinkFiles extends Diagnosis {
13
+ name = DIAGNOSIS_NAME;
14
+ description = 'validate generated symlinks for workspace environments';
15
+ category = 'local environments';
16
+
17
+ _formatSymptoms(bareResult: ExamineBareResult): string {
18
+ if (!bareResult.data) throw new Error('BrokenSymlinkFiles, bareResult.data is missing');
19
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
20
+ const toString = bareResult.data.brokenSymlinks
21
+ .map(
22
+ (brokenSymlink) => `symlink path: "${brokenSymlink.symlinkPath}", broken link: "${brokenSymlink.brokenPath}"`
23
+ )
24
+ .join('\n');
25
+ return `the following symlinks points to non-existing paths\n${toString}`;
26
+ }
27
+
28
+ _formatManualTreat(bareResult: ExamineBareResult) {
29
+ if (!bareResult.data) throw new Error('BrokenSymlinkFiles, bareResult.data is missing');
30
+ const toString = uniq(bareResult.data.brokenSymlinks.map((b) => b.pathToDelete)).join('\n');
31
+ return `please delete the following paths:\n${toString}`;
32
+ }
33
+
34
+ async _runExamine(): Promise<ExamineBareResult> {
35
+ const consumer = await loadConsumer();
36
+ const envComponentsDir = path.join(consumer.scope.getPath(), Scope.getComponentsRelativePath());
37
+ const potentialSymlinks = glob.sync('**/node_modules/@bit/**', { cwd: envComponentsDir });
38
+ const potentialSymlinksAbs = potentialSymlinks.map((p) => path.join(envComponentsDir, p));
39
+ const brokenSymlinks: BrokenSymlink[] = [];
40
+ const results = potentialSymlinksAbs.map(async (potentialSymlink) => {
41
+ const link = await this._getLinkIfExist(potentialSymlink);
42
+ if (!link) return;
43
+ const exists = await fs.pathExists(link);
44
+ if (exists) return;
45
+ const brokenSymlink = {
46
+ symlinkPath: potentialSymlink,
47
+ brokenPath: link,
48
+ pathToDelete: this._getPathToDelete(potentialSymlink),
49
+ };
50
+ brokenSymlinks.push(brokenSymlink);
51
+ });
52
+ await Promise.all(results);
53
+ return {
54
+ valid: brokenSymlinks.length === 0,
55
+ data: {
56
+ brokenSymlinks,
57
+ },
58
+ };
59
+ }
60
+
61
+ async _getLinkIfExist(symlinkPath: string): Promise<string | null | undefined> {
62
+ try {
63
+ const link = await fs.readlink(symlinkPath);
64
+ return link;
65
+ } catch (err: any) {
66
+ // probably not a symlink
67
+ return null;
68
+ }
69
+ }
70
+
71
+ /**
72
+ * deleting the environment directory causes Bit to reinstall it next time
73
+ */
74
+ _getPathToDelete(symlinkPath: string): string {
75
+ const envDirectory = symlinkPath.split(path.join('node_modules', '@bit'))[0];
76
+ return envDirectory.slice(0, -1); // remove the last slash
77
+ }
78
+ }
@@ -0,0 +1,51 @@
1
+ import { ComponentIdList } from '@teambit/component-id';
2
+ import { loadConsumer } from '@teambit/legacy/dist/consumer';
3
+ import { ModelComponent, Symlink } from '@teambit/legacy/dist/scope/models';
4
+ import Diagnosis, { ExamineBareResult } from '../diagnosis';
5
+
6
+ export const DIAGNOSIS_NAME = 'check orphan refs';
7
+ export default class OrphanSymlinkObjects extends Diagnosis {
8
+ name = DIAGNOSIS_NAME;
9
+ description = 'checks for empty internal refs in local workspace';
10
+ category = 'internal store';
11
+
12
+ _formatSymptoms(bareResult: ExamineBareResult): string {
13
+ if (!bareResult.data) throw new Error('OrphanSymlinkObjects, bareResult.data is missing');
14
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
15
+ return `the following refs points to non-existing components "${bareResult.data.orphanSymlinks.toString()}"`;
16
+ }
17
+
18
+ _formatManualTreat(bareResult: ExamineBareResult) {
19
+ if (!bareResult.data) throw new Error('OrphanSymlinkObjects, bareResult.data is missing');
20
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
21
+ return `please delete the following paths:\n${bareResult.data.objectsToDelete.join('\n')}`;
22
+ }
23
+
24
+ async _runExamine(): Promise<ExamineBareResult> {
25
+ const consumer = await loadConsumer();
26
+ const symlinks = await consumer.scope.objects.list([Symlink]);
27
+ const orphanSymlinks = new ComponentIdList();
28
+ const objectsToDelete = [];
29
+ await Promise.all(
30
+ symlinks.map(async (symlink) => {
31
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
32
+ const realComponentId: ComponentID = symlink.getRealComponentId();
33
+ const realModelComponent = ModelComponent.fromBitId(realComponentId);
34
+ const foundComponent = await consumer.scope.objects.load(realModelComponent.hash());
35
+ if (!foundComponent) {
36
+ orphanSymlinks.push(realComponentId);
37
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
38
+ objectsToDelete.push(consumer.scope.objects.objectPath(symlink.hash()));
39
+ }
40
+ })
41
+ );
42
+
43
+ return {
44
+ valid: orphanSymlinks.length === 0,
45
+ data: {
46
+ orphanSymlinks,
47
+ objectsToDelete,
48
+ },
49
+ };
50
+ }
51
+ }
@@ -0,0 +1,56 @@
1
+ import semver from 'semver';
2
+ import { listRemote } from '@teambit/bvm.list';
3
+ import { getHarmonyVersion } from '@teambit/legacy/dist/bootstrap';
4
+ import Diagnosis, { ExamineBareResult } from '../diagnosis';
5
+
6
+ export default class ValidateBitVersion extends Diagnosis {
7
+ name = 'validate bit version';
8
+ description = 'validate that bit version is up to date';
9
+ category = 'core';
10
+
11
+ _formatSymptoms(bareResult: ExamineBareResult): string {
12
+ if (!bareResult.data) throw new Error('ValidateBitVersion, bareResult.data is missing');
13
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
14
+ if (!bareResult.data.latestVersion) {
15
+ return 'could not fetch bit latest version';
16
+ }
17
+ return `bit is not up to date.
18
+ your version: ${bareResult.data.currentVersion}
19
+ latest version: ${bareResult.data.latestVersion}`;
20
+ }
21
+
22
+ _formatManualTreat(bareResult: ExamineBareResult) {
23
+ if (!bareResult.data) throw new Error('ValidateBitVersion, bareResult.data is missing');
24
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
25
+ if (!bareResult.data.latestVersion) {
26
+ return 'please make sure you have an internet connection';
27
+ }
28
+ return 'please upgrade your bit version (bvm upgrade)';
29
+ }
30
+
31
+ async _runExamine(): Promise<ExamineBareResult> {
32
+ const bitRemoteVersionOnBvm = await listRemote({ limit: 1 });
33
+ const bitLatestVersion = bitRemoteVersionOnBvm.entries[0].version;
34
+ const bitCurrentVersion = getHarmonyVersion(true);
35
+ if (bitLatestVersion) {
36
+ if (semver.lt(bitCurrentVersion, bitLatestVersion)) {
37
+ return {
38
+ valid: false,
39
+ data: {
40
+ latestVersion: bitLatestVersion,
41
+ currentVersion: bitCurrentVersion,
42
+ },
43
+ };
44
+ }
45
+ return {
46
+ valid: true,
47
+ };
48
+ }
49
+ return {
50
+ valid: false,
51
+ data: {
52
+ latestVersion: null,
53
+ },
54
+ };
55
+ }
56
+ }
@@ -0,0 +1,38 @@
1
+ import execa from 'execa';
2
+ import getGitExecutablePath from '@teambit/legacy/dist/utils/git/git-executable';
3
+ import Diagnosis, { ExamineBareResult } from '../diagnosis';
4
+
5
+ export const DIAGNOSIS_NAME_VALIDATE_GIT_EXEC = 'validate git exec';
6
+ export default class ValidateGitExec extends Diagnosis {
7
+ name = DIAGNOSIS_NAME_VALIDATE_GIT_EXEC;
8
+ description = 'validate that git executable found';
9
+ category = 'vendors';
10
+
11
+ _formatSymptoms(bareResult: ExamineBareResult): string {
12
+ const gitExecutablePath = bareResult?.data?.gitExecutablePath;
13
+ return `git executable not found (path '${gitExecutablePath}')`;
14
+ }
15
+
16
+ _formatManualTreat() {
17
+ return "please ensure that git is installed and/or git_path is configured correctly - 'bit config set git_path <GIT_PATH>'";
18
+ }
19
+
20
+ async _runExamine(): Promise<ExamineBareResult> {
21
+ const gitExecutablePath = getGitExecutablePath();
22
+ try {
23
+ await execa(gitExecutablePath, ['--version']);
24
+ return {
25
+ valid: true,
26
+ };
27
+ } catch (err: any) {
28
+ // if (err.code === 'ENOENT') {
29
+ // }
30
+ return {
31
+ valid: false,
32
+ data: {
33
+ gitExecutablePath,
34
+ },
35
+ };
36
+ }
37
+ }
38
+ }
@@ -0,0 +1,40 @@
1
+ import execa from 'execa';
2
+ import logger from '@teambit/legacy/dist/logger/logger';
3
+ import Diagnosis, { ExamineBareResult } from '../diagnosis';
4
+
5
+ export default class ValidateNpmExec extends Diagnosis {
6
+ name = 'validate npm exec';
7
+ description = 'validate that npm executable found';
8
+ category = 'vendors';
9
+
10
+ _formatSymptoms(): string {
11
+ return 'npm executable not found';
12
+ }
13
+
14
+ _formatManualTreat() {
15
+ return 'please ensure npm is installed';
16
+ }
17
+
18
+ async _runExamine(): Promise<ExamineBareResult> {
19
+ const npmVersion = await getNpmVersion();
20
+ if (npmVersion) {
21
+ return {
22
+ valid: true,
23
+ };
24
+ }
25
+ return {
26
+ valid: false,
27
+ data: {},
28
+ };
29
+ }
30
+ }
31
+
32
+ export async function getNpmVersion(): Promise<string | null | undefined> {
33
+ try {
34
+ const { stdout, stderr } = await execa('npm', ['--version']);
35
+ if (stdout && !stderr) return stdout;
36
+ } catch (err: any) {
37
+ logger.debugAndAddBreadCrumb('npm-client', `got an error when executing "npm --version". ${err.message}`);
38
+ }
39
+ return null;
40
+ }
@@ -0,0 +1,35 @@
1
+ import { loadConsumer } from '@teambit/legacy/dist/consumer';
2
+ import WorkspaceConfig from '@teambit/legacy/dist/consumer/config/workspace-config';
3
+ import Diagnosis, { ExamineBareResult } from '../diagnosis';
4
+
5
+ export default class ValidateWorkspaceBitJsonSyntax extends Diagnosis {
6
+ name = "validate workspace's bit config";
7
+ description = 'validate workspace configuration object';
8
+ category = 'configuration';
9
+
10
+ _formatSymptoms(bareResult: ExamineBareResult): string {
11
+ const bitJsonPath = bareResult?.data?.bitJsonPath;
12
+ return `invalid workspace.jsonc: ${bitJsonPath} is not a valid JSON file.`;
13
+ }
14
+
15
+ _formatManualTreat() {
16
+ return 'manually fix the workspace.jsonc or consider running bit init --reset to recreate the file';
17
+ }
18
+
19
+ // TODO: support configuration from package.json
20
+ async _runExamine(): Promise<ExamineBareResult> {
21
+ const consumer = await loadConsumer();
22
+ const consumerPath = consumer.getPath();
23
+ try {
24
+ await WorkspaceConfig.loadIfExist(consumerPath, consumer.scope.path);
25
+ return {
26
+ valid: true,
27
+ };
28
+ } catch (e: any) {
29
+ return {
30
+ valid: false,
31
+ data: {},
32
+ };
33
+ }
34
+ }
35
+ }
@@ -0,0 +1,40 @@
1
+ import execa from 'execa';
2
+ import logger from '@teambit/legacy/dist/logger/logger';
3
+ import Diagnosis, { ExamineBareResult } from '../diagnosis';
4
+
5
+ export default class ValidateYarnExec extends Diagnosis {
6
+ name = 'validate yarn exec';
7
+ description = 'validate that yarn executable found';
8
+ category = 'vendors';
9
+
10
+ _formatSymptoms(): string {
11
+ return 'yarn executable not found';
12
+ }
13
+
14
+ _formatManualTreat() {
15
+ return 'please ensure yarn is installed';
16
+ }
17
+
18
+ async _runExamine(): Promise<ExamineBareResult> {
19
+ const yarnVersion = await getYarnVersion();
20
+ if (yarnVersion) {
21
+ return {
22
+ valid: true,
23
+ };
24
+ }
25
+ return {
26
+ valid: false,
27
+ data: {},
28
+ };
29
+ }
30
+ }
31
+
32
+ export async function getYarnVersion(): Promise<string | null | undefined> {
33
+ try {
34
+ const { stdout } = await execa('yarn', ['-v']);
35
+ return stdout;
36
+ } catch (e: any) {
37
+ logger.debugAndAddBreadCrumb('npm-client', `can't find yarn version by running yarn -v. ${e.message}`);
38
+ }
39
+ return null;
40
+ }
@@ -0,0 +1,28 @@
1
+ import chalk from 'chalk';
2
+ import { table } from 'table';
3
+
4
+ import Diagnosis from './diagnosis';
5
+
6
+ // const NAME_COLUMN_WIDTH = 100;
7
+ // const DESCRIPTION_COLUMN_WIDTH = 30;
8
+
9
+ const tableColumnConfig = {
10
+ columnDefault: {
11
+ alignment: 'left',
12
+ },
13
+ };
14
+
15
+ type DiagnosisRow = [string, string, string];
16
+
17
+ function createRow(diagnosis: Diagnosis): DiagnosisRow {
18
+ return [diagnosis.category, diagnosis.name, diagnosis.description];
19
+ }
20
+
21
+ export default function formatDiagnosesList(diagnosesList: Diagnosis[]): string {
22
+ const header = [chalk.bold('category'), chalk.bold('name'), chalk.bold('description')];
23
+ const rows = diagnosesList.map(createRow);
24
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
25
+ rows.unshift(header);
26
+ const output = table(rows, tableColumnConfig);
27
+ return output;
28
+ }
package/diagnosis.ts ADDED
@@ -0,0 +1,81 @@
1
+ export type ExamineBareResult = {
2
+ valid: boolean;
3
+ data?: Record<string, any>;
4
+ };
5
+
6
+ export type DiagnosisMetaData = {
7
+ name: string;
8
+ description: string;
9
+ category: string;
10
+ };
11
+
12
+ export type ExamineResult = {
13
+ diagnosisMetaData: DiagnosisMetaData;
14
+ bareResult: ExamineBareResult;
15
+ formattedSymptoms: string; // A human readable of the found issues
16
+ formattedManualTreat: string; // human readable steps to fix
17
+ };
18
+
19
+ export default class Diagnosis {
20
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
21
+ name: string;
22
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
23
+ description: string;
24
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
25
+ category: string;
26
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
27
+ result: Record<string, any>;
28
+
29
+ /**
30
+ * A function that actually runs the examination
31
+ */
32
+ async _runExamine(): Promise<ExamineBareResult> {
33
+ throw new Error('You must implement this method');
34
+ }
35
+
36
+ /**
37
+ * Returns a descriptive symptoms message which might include specific data from the examination
38
+ * @param bareResult ExamineBareResult
39
+ */
40
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
41
+ _formatSymptoms(bareResult: ExamineBareResult): string {
42
+ throw new Error('You must implement this method');
43
+ }
44
+
45
+ /**
46
+ * Returns a descriptive instruction to handle the issue (might include specific data from the examination)
47
+ * @param bareResult ExamineBareResult
48
+ */
49
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
50
+ _formatManualTreat(bareResult: ExamineBareResult): string {
51
+ throw new Error('You must implement this method');
52
+ }
53
+
54
+ getMeta() {
55
+ return {
56
+ category: this.category,
57
+ name: this.name,
58
+ description: this.description,
59
+ };
60
+ }
61
+
62
+ async examine(): Promise<ExamineResult> {
63
+ const bareResult = await this._runExamine();
64
+ if (bareResult.valid) {
65
+ return {
66
+ diagnosisMetaData: this.getMeta(),
67
+ bareResult,
68
+ formattedSymptoms: '',
69
+ formattedManualTreat: '',
70
+ };
71
+ }
72
+ const formattedSymptoms = this._formatSymptoms(bareResult);
73
+ const formattedManualTreat = this._formatManualTreat(bareResult);
74
+ return {
75
+ diagnosisMetaData: this.getMeta(),
76
+ bareResult,
77
+ formattedSymptoms,
78
+ formattedManualTreat,
79
+ };
80
+ }
81
+ }
@@ -0,0 +1,15 @@
1
+ import Diagnosis, { ExamineBareResult } from '../diagnosis';
2
+ export declare const DIAGNOSIS_NAME = "check environment symlinks";
3
+ export default class BrokenSymlinkFiles extends Diagnosis {
4
+ name: string;
5
+ description: string;
6
+ category: string;
7
+ _formatSymptoms(bareResult: ExamineBareResult): string;
8
+ _formatManualTreat(bareResult: ExamineBareResult): string;
9
+ _runExamine(): Promise<ExamineBareResult>;
10
+ _getLinkIfExist(symlinkPath: string): Promise<string | null | undefined>;
11
+ /**
12
+ * deleting the environment directory causes Bit to reinstall it next time
13
+ */
14
+ _getPathToDelete(symlinkPath: string): string;
15
+ }
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.DIAGNOSIS_NAME = void 0;
7
+ function _fsExtra() {
8
+ const data = _interopRequireDefault(require("fs-extra"));
9
+ _fsExtra = function () {
10
+ return data;
11
+ };
12
+ return data;
13
+ }
14
+ function _glob() {
15
+ const data = _interopRequireDefault(require("glob"));
16
+ _glob = function () {
17
+ return data;
18
+ };
19
+ return data;
20
+ }
21
+ function _path() {
22
+ const data = _interopRequireDefault(require("path"));
23
+ _path = function () {
24
+ return data;
25
+ };
26
+ return data;
27
+ }
28
+ function _consumer() {
29
+ const data = require("@teambit/legacy/dist/consumer");
30
+ _consumer = function () {
31
+ return data;
32
+ };
33
+ return data;
34
+ }
35
+ function _scope() {
36
+ const data = require("@teambit/legacy/dist/scope");
37
+ _scope = function () {
38
+ return data;
39
+ };
40
+ return data;
41
+ }
42
+ function _diagnosis() {
43
+ const data = _interopRequireDefault(require("../diagnosis"));
44
+ _diagnosis = function () {
45
+ return data;
46
+ };
47
+ return data;
48
+ }
49
+ function _lodash() {
50
+ const data = require("lodash");
51
+ _lodash = function () {
52
+ return data;
53
+ };
54
+ return data;
55
+ }
56
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
57
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
58
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
59
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
60
+ const DIAGNOSIS_NAME = exports.DIAGNOSIS_NAME = 'check environment symlinks';
61
+ class BrokenSymlinkFiles extends _diagnosis().default {
62
+ constructor(...args) {
63
+ super(...args);
64
+ _defineProperty(this, "name", DIAGNOSIS_NAME);
65
+ _defineProperty(this, "description", 'validate generated symlinks for workspace environments');
66
+ _defineProperty(this, "category", 'local environments');
67
+ }
68
+ _formatSymptoms(bareResult) {
69
+ if (!bareResult.data) throw new Error('BrokenSymlinkFiles, bareResult.data is missing');
70
+ // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
71
+ const toString = bareResult.data.brokenSymlinks.map(brokenSymlink => `symlink path: "${brokenSymlink.symlinkPath}", broken link: "${brokenSymlink.brokenPath}"`).join('\n');
72
+ return `the following symlinks points to non-existing paths\n${toString}`;
73
+ }
74
+ _formatManualTreat(bareResult) {
75
+ if (!bareResult.data) throw new Error('BrokenSymlinkFiles, bareResult.data is missing');
76
+ const toString = (0, _lodash().uniq)(bareResult.data.brokenSymlinks.map(b => b.pathToDelete)).join('\n');
77
+ return `please delete the following paths:\n${toString}`;
78
+ }
79
+ async _runExamine() {
80
+ const consumer = await (0, _consumer().loadConsumer)();
81
+ const envComponentsDir = _path().default.join(consumer.scope.getPath(), _scope().Scope.getComponentsRelativePath());
82
+ const potentialSymlinks = _glob().default.sync('**/node_modules/@bit/**', {
83
+ cwd: envComponentsDir
84
+ });
85
+ const potentialSymlinksAbs = potentialSymlinks.map(p => _path().default.join(envComponentsDir, p));
86
+ const brokenSymlinks = [];
87
+ const results = potentialSymlinksAbs.map(async potentialSymlink => {
88
+ const link = await this._getLinkIfExist(potentialSymlink);
89
+ if (!link) return;
90
+ const exists = await _fsExtra().default.pathExists(link);
91
+ if (exists) return;
92
+ const brokenSymlink = {
93
+ symlinkPath: potentialSymlink,
94
+ brokenPath: link,
95
+ pathToDelete: this._getPathToDelete(potentialSymlink)
96
+ };
97
+ brokenSymlinks.push(brokenSymlink);
98
+ });
99
+ await Promise.all(results);
100
+ return {
101
+ valid: brokenSymlinks.length === 0,
102
+ data: {
103
+ brokenSymlinks
104
+ }
105
+ };
106
+ }
107
+ async _getLinkIfExist(symlinkPath) {
108
+ try {
109
+ const link = await _fsExtra().default.readlink(symlinkPath);
110
+ return link;
111
+ } catch (err) {
112
+ // probably not a symlink
113
+ return null;
114
+ }
115
+ }
116
+
117
+ /**
118
+ * deleting the environment directory causes Bit to reinstall it next time
119
+ */
120
+ _getPathToDelete(symlinkPath) {
121
+ const envDirectory = symlinkPath.split(_path().default.join('node_modules', '@bit'))[0];
122
+ return envDirectory.slice(0, -1); // remove the last slash
123
+ }
124
+ }
125
+ exports.default = BrokenSymlinkFiles;
126
+
127
+ //# sourceMappingURL=broken-symlink-files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_fsExtra","data","_interopRequireDefault","require","_glob","_path","_consumer","_scope","_diagnosis","_lodash","e","__esModule","default","_defineProperty","r","t","_toPropertyKey","Object","defineProperty","value","enumerable","configurable","writable","i","_toPrimitive","Symbol","toPrimitive","call","TypeError","String","Number","DIAGNOSIS_NAME","exports","BrokenSymlinkFiles","Diagnosis","constructor","args","_formatSymptoms","bareResult","Error","toString","brokenSymlinks","map","brokenSymlink","symlinkPath","brokenPath","join","_formatManualTreat","uniq","b","pathToDelete","_runExamine","consumer","loadConsumer","envComponentsDir","path","scope","getPath","Scope","getComponentsRelativePath","potentialSymlinks","glob","sync","cwd","potentialSymlinksAbs","p","results","potentialSymlink","link","_getLinkIfExist","exists","fs","pathExists","_getPathToDelete","push","Promise","all","valid","length","readlink","err","envDirectory","split","slice"],"sources":["broken-symlink-files.ts"],"sourcesContent":["import fs from 'fs-extra';\nimport glob from 'glob';\nimport path from 'path';\nimport { loadConsumer } from '@teambit/legacy/dist/consumer';\nimport { Scope } from '@teambit/legacy/dist/scope';\nimport Diagnosis, { ExamineBareResult } from '../diagnosis';\nimport { uniq } from 'lodash';\n\ntype BrokenSymlink = { symlinkPath: string; brokenPath: string; pathToDelete: string };\nexport const DIAGNOSIS_NAME = 'check environment symlinks';\n\nexport default class BrokenSymlinkFiles extends Diagnosis {\n name = DIAGNOSIS_NAME;\n description = 'validate generated symlinks for workspace environments';\n category = 'local environments';\n\n _formatSymptoms(bareResult: ExamineBareResult): string {\n if (!bareResult.data) throw new Error('BrokenSymlinkFiles, bareResult.data is missing');\n // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!\n const toString = bareResult.data.brokenSymlinks\n .map(\n (brokenSymlink) => `symlink path: \"${brokenSymlink.symlinkPath}\", broken link: \"${brokenSymlink.brokenPath}\"`\n )\n .join('\\n');\n return `the following symlinks points to non-existing paths\\n${toString}`;\n }\n\n _formatManualTreat(bareResult: ExamineBareResult) {\n if (!bareResult.data) throw new Error('BrokenSymlinkFiles, bareResult.data is missing');\n const toString = uniq(bareResult.data.brokenSymlinks.map((b) => b.pathToDelete)).join('\\n');\n return `please delete the following paths:\\n${toString}`;\n }\n\n async _runExamine(): Promise<ExamineBareResult> {\n const consumer = await loadConsumer();\n const envComponentsDir = path.join(consumer.scope.getPath(), Scope.getComponentsRelativePath());\n const potentialSymlinks = glob.sync('**/node_modules/@bit/**', { cwd: envComponentsDir });\n const potentialSymlinksAbs = potentialSymlinks.map((p) => path.join(envComponentsDir, p));\n const brokenSymlinks: BrokenSymlink[] = [];\n const results = potentialSymlinksAbs.map(async (potentialSymlink) => {\n const link = await this._getLinkIfExist(potentialSymlink);\n if (!link) return;\n const exists = await fs.pathExists(link);\n if (exists) return;\n const brokenSymlink = {\n symlinkPath: potentialSymlink,\n brokenPath: link,\n pathToDelete: this._getPathToDelete(potentialSymlink),\n };\n brokenSymlinks.push(brokenSymlink);\n });\n await Promise.all(results);\n return {\n valid: brokenSymlinks.length === 0,\n data: {\n brokenSymlinks,\n },\n };\n }\n\n async _getLinkIfExist(symlinkPath: string): Promise<string | null | undefined> {\n try {\n const link = await fs.readlink(symlinkPath);\n return link;\n } catch (err: any) {\n // probably not a symlink\n return null;\n }\n }\n\n /**\n * deleting the environment directory causes Bit to reinstall it next time\n */\n _getPathToDelete(symlinkPath: string): string {\n const envDirectory = symlinkPath.split(path.join('node_modules', '@bit'))[0];\n return envDirectory.slice(0, -1); // remove the last slash\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,10 @@
1
+ import Diagnosis, { ExamineBareResult } from '../diagnosis';
2
+ export declare const DIAGNOSIS_NAME = "check orphan refs";
3
+ export default class OrphanSymlinkObjects extends Diagnosis {
4
+ name: string;
5
+ description: string;
6
+ category: string;
7
+ _formatSymptoms(bareResult: ExamineBareResult): string;
8
+ _formatManualTreat(bareResult: ExamineBareResult): string;
9
+ _runExamine(): Promise<ExamineBareResult>;
10
+ }