-
Notifications
You must be signed in to change notification settings - Fork 68
/
internal.ts
120 lines (113 loc) · 3.95 KB
/
internal.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/*
* Copyright (c) 2020, salesforce.com, inc.
* All rights reserved.
* Licensed under the BSD 3-Clause license.
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
import * as fs from 'fs';
import { join, resolve } from 'path';
import { Optional } from '@salesforce/ts-types';
import { Messages } from '../messages';
import { SfError } from '../sfError';
Messages.importMessagesDirectory(__dirname);
const messages = Messages.loadMessages('@salesforce/core', 'config');
/**
* The name of the project config file.
*
* @ignore
*/
// This has to be defined on util to prevent circular deps with project and configFile.
export const SFDX_PROJECT_JSON = 'sfdx-project.json';
/**
* Performs an upward directory search for an sfdx project file. Returns the absolute path to the project.
*
* **See** {@link SFDX_PROJECT_JSON}
*
* **See** {@link traverseForFile}
*
* **Throws** *{@link SfError}{ name: 'InvalidProjectWorkspaceError' }* If the current folder is not located in a workspace.
*
* @param dir The directory path to start traversing from.
* @ignore
*/
export async function resolveProjectPath(dir: string = process.cwd()): Promise<string> {
const projectPath = await traverse.forFile(dir, SFDX_PROJECT_JSON);
if (!projectPath) {
throw messages.createError('invalidProjectWorkspace');
}
return projectPath;
}
/**
* Performs a synchronous upward directory search for an sfdx project file. Returns the absolute path to the project.
*
* **See** {@link SFDX_PROJECT_JSON}
*
* **See** {@link traverseForFile}
*
* **Throws** *{@link SfError}{ name: 'InvalidProjectWorkspaceError' }* If the current folder is not located in a workspace.
*
* @param dir The directory path to start traversing from.
* @ignore
*/
export function resolveProjectPathSync(dir: string = process.cwd()): string {
const projectPath = traverse.forFileSync(dir, SFDX_PROJECT_JSON);
if (!projectPath) {
throw messages.createError('invalidProjectWorkspace');
}
return projectPath;
}
/**
* These methods were moved from the deprecated 'fs' module in v2 and are only used in sfdx-core above
*
* They were migrated into the 'traverse' constant in order to stub them in unit tests
*/
export const traverse = {
/**
* Searches a file path in an ascending manner (until reaching the filesystem root) for the first occurrence a
* specific file name. Resolves with the directory path containing the located file, or `null` if the file was
* not found.
*
* @param dir The directory path in which to start the upward search.
* @param file The file name to look for.
*/
forFile: async (dir: string, file: string): Promise<Optional<string>> => {
let foundProjectDir: Optional<string>;
try {
fs.statSync(join(dir, file));
foundProjectDir = dir;
} catch (err) {
if (err && (err as SfError).code === 'ENOENT') {
const nextDir = resolve(dir, '..');
if (nextDir !== dir) {
// stop at root
foundProjectDir = await traverse.forFile(nextDir, file);
}
}
}
return foundProjectDir;
},
/**
* Searches a file path synchronously in an ascending manner (until reaching the filesystem root) for the first occurrence a
* specific file name. Resolves with the directory path containing the located file, or `null` if the file was
* not found.
*
* @param dir The directory path in which to start the upward search.
* @param file The file name to look for.
*/
forFileSync: (dir: string, file: string): Optional<string> => {
let foundProjectDir: Optional<string>;
try {
fs.statSync(join(dir, file));
foundProjectDir = dir;
} catch (err) {
if (err && (err as SfError).code === 'ENOENT') {
const nextDir = resolve(dir, '..');
if (nextDir !== dir) {
// stop at root
foundProjectDir = traverse.forFileSync(nextDir, file);
}
}
}
return foundProjectDir;
},
};