@configjs/cli 1.1.16 → 1.1.18
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.
- package/dist/{angular-command-XN26G6L3.js → angular-command-EOREU45Q.js} +8 -8
- package/dist/{angular-installer-FY43HE72.js → angular-installer-TKZDPFLD.js} +9 -1
- package/dist/angular-setup-QDTWXOB4.js +30 -0
- package/dist/check-KAPRT4FM.js +168 -0
- package/dist/{chunk-JYWGJJ4M.js → chunk-D7IWYKUX.js} +476 -28
- package/dist/chunk-EDCNW4UO.js +92 -0
- package/dist/{chunk-TN27AX4L.js → chunk-FJLN62L4.js} +797 -18
- package/dist/{chunk-FIB2J36N.js → chunk-HI7RYD6W.js} +161 -36
- package/dist/{chunk-NYCK4R4K.js → chunk-RIJNUJDC.js} +361 -96
- package/dist/chunk-V2IBYLVH.js +932 -0
- package/dist/chunk-VN4XTFDK.js +315 -0
- package/dist/{chunk-UKEHW2LH.js → chunk-Y4XYC7QV.js} +17 -3
- package/dist/cli.js +31 -21
- package/dist/{installed-D6CUYQM5.js → installed-QMJZIZNC.js} +4 -4
- package/dist/{list-VZDUWV5O.js → list-5T6VDDAO.js} +4 -4
- package/dist/{nextjs-command-WKKOAY7I.js → nextjs-command-C6PM7A5C.js} +8 -9
- package/dist/{nextjs-installer-2ZC5IWJ6.js → nextjs-installer-OFY5BQC4.js} +9 -2
- package/dist/{nextjs-setup-DYOFF72S.js → nextjs-setup-JIKPIJCX.js} +21 -9
- package/dist/{react-command-2T6IOTHB.js → react-command-JMK6VM4Q.js} +8 -9
- package/dist/{remove-ZY3MLPGN.js → remove-4ZNQR6ZR.js} +4 -4
- package/dist/{svelte-command-B2DNNQ5Z.js → svelte-command-YUSD55NO.js} +8 -8
- package/dist/svelte-installer-UP3KDZSY.js +105 -0
- package/dist/{svelte-setup-FWXLXJAC.js → svelte-setup-33E46IBT.js} +16 -5
- package/dist/{vite-installer-Y6VMFHIM.js → vite-installer-EE2LE76G.js} +9 -2
- package/dist/{vite-setup-JRELX6K2.js → vite-setup-VO5BOI46.js} +16 -4
- package/dist/{vue-command-IOTC32AI.js → vue-command-3CYWLLFQ.js} +8 -9
- package/dist/{vue-installer-DGBBVF6F.js → vue-installer-LEGLVD77.js} +9 -2
- package/dist/{vue-setup-G44DLT2U.js → vue-setup-FK5QT7AY.js} +16 -4
- package/package.json +12 -4
- package/dist/angular-setup-Z6TCKNBG.js +0 -18
- package/dist/check-KNGZSCMM.js +0 -131
- package/dist/chunk-6GV4NKUX.js +0 -122
- package/dist/chunk-QPEUT7QG.js +0 -157
- package/dist/svelte-installer-EOSC3EP3.js +0 -65
|
@@ -1,13 +1,118 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getModuleLogger
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-VN4XTFDK.js";
|
|
4
|
+
|
|
5
|
+
// src/core/path-validator.ts
|
|
6
|
+
import { resolve, normalize, sep, isAbsolute, dirname } from "path";
|
|
7
|
+
import { realpath as realpathCallback } from "fs/promises";
|
|
8
|
+
import fs from "fs-extra";
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
var pathExists = fs.pathExists;
|
|
11
|
+
var realpath = realpathCallback;
|
|
12
|
+
var pathResolutionSchema = z.object({
|
|
13
|
+
projectRoot: z.string().min(1, "Project root cannot be empty").refine(
|
|
14
|
+
(path) => isAbsolute(path),
|
|
15
|
+
"Project root must be an absolute path"
|
|
16
|
+
),
|
|
17
|
+
userPath: z.string().min(1, "User path cannot be empty").max(1024, "Path exceeds maximum length (1024 characters)").refine((path) => !path.includes("\0"), "Path cannot contain null bytes").refine((path) => {
|
|
18
|
+
for (let i = 0; i < path.length; i++) {
|
|
19
|
+
const charCode = path.charCodeAt(i);
|
|
20
|
+
if (charCode >= 0 && charCode <= 31) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return true;
|
|
25
|
+
}, "Path cannot contain control characters")
|
|
26
|
+
});
|
|
27
|
+
function validatePathInProject(projectRoot, userPath) {
|
|
28
|
+
const validated = pathResolutionSchema.parse({
|
|
29
|
+
projectRoot,
|
|
30
|
+
userPath
|
|
31
|
+
});
|
|
32
|
+
const normalizedRoot = normalize(resolve(validated.projectRoot));
|
|
33
|
+
const resolvedPath = normalize(resolve(normalizedRoot, validated.userPath));
|
|
34
|
+
const isWithinBoundary = resolvedPath === normalizedRoot || resolvedPath.startsWith(normalizedRoot + sep);
|
|
35
|
+
if (!isWithinBoundary) {
|
|
36
|
+
throw new Error(
|
|
37
|
+
`Path traversal detected: "${userPath}" attempts to escape project root. Resolved: "${resolvedPath}", allowed: "${normalizedRoot}"`
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
if (userPath.includes("..")) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
`Path contains parent directory (..): "${userPath}". Only paths within project root allowed.`
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
if (isAbsolute(userPath)) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
`Absolute paths not allowed: "${userPath}". Use path relative to project root.`
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
return resolvedPath;
|
|
51
|
+
}
|
|
52
|
+
async function findClosestExistingPath(boundaryRoot, resolvedPath) {
|
|
53
|
+
let currentPath = resolvedPath;
|
|
54
|
+
while (true) {
|
|
55
|
+
if (await pathExists(currentPath)) {
|
|
56
|
+
return currentPath;
|
|
57
|
+
}
|
|
58
|
+
if (currentPath === boundaryRoot) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
const parentPath = dirname(currentPath);
|
|
62
|
+
if (parentPath === currentPath) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
currentPath = parentPath;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async function validateSymlinkBoundary(projectRoot, resolvedPath) {
|
|
69
|
+
const normalizedRoot = normalize(resolve(projectRoot));
|
|
70
|
+
const realRoot = await realpath(normalizedRoot).catch(() => normalizedRoot);
|
|
71
|
+
const existingPath = await findClosestExistingPath(
|
|
72
|
+
normalizedRoot,
|
|
73
|
+
resolvedPath
|
|
74
|
+
);
|
|
75
|
+
if (!existingPath) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const realExisting = await realpath(existingPath).catch(() => existingPath);
|
|
79
|
+
const normalizedRealExisting = normalize(realExisting);
|
|
80
|
+
const normalizedRealRoot = normalize(realRoot);
|
|
81
|
+
const isWithinBoundary = normalizedRealExisting === normalizedRealRoot || normalizedRealExisting.startsWith(normalizedRealRoot + sep);
|
|
82
|
+
if (!isWithinBoundary) {
|
|
83
|
+
throw new Error(
|
|
84
|
+
`Symlink traversal detected: "${resolvedPath}" resolves outside project root. Resolved: "${normalizedRealExisting}", allowed: "${normalizedRealRoot}"`
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async function validatePathInProjectWithSymlinks(projectRoot, userPath) {
|
|
89
|
+
const resolvedPath = validatePathInProject(projectRoot, userPath);
|
|
90
|
+
await validateSymlinkBoundary(projectRoot, resolvedPath);
|
|
91
|
+
return resolvedPath;
|
|
92
|
+
}
|
|
93
|
+
function getPathValidationErrorMessage(error) {
|
|
94
|
+
if (error instanceof z.ZodError) {
|
|
95
|
+
const issues = error.flatten().fieldErrors;
|
|
96
|
+
const messages = [];
|
|
97
|
+
for (const [field, msgs] of Object.entries(issues)) {
|
|
98
|
+
if (msgs && Array.isArray(msgs)) {
|
|
99
|
+
messages.push(`${field}: ${msgs.join(", ")}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return messages.join("; ") || "Invalid path format";
|
|
103
|
+
}
|
|
104
|
+
if (error instanceof Error) {
|
|
105
|
+
return error.message;
|
|
106
|
+
}
|
|
107
|
+
return "Path validation failed";
|
|
108
|
+
}
|
|
4
109
|
|
|
5
110
|
// src/utils/fs-helpers.ts
|
|
6
|
-
import { resolve as
|
|
111
|
+
import { resolve as resolve3, dirname as dirname3, extname } from "path";
|
|
7
112
|
|
|
8
113
|
// src/core/fs-adapter.ts
|
|
9
|
-
import
|
|
10
|
-
import { resolve, dirname } from "path";
|
|
114
|
+
import fs2 from "fs-extra";
|
|
115
|
+
import { resolve as resolve2, dirname as dirname2 } from "path";
|
|
11
116
|
var FileSystemAdapter = class {
|
|
12
117
|
/**
|
|
13
118
|
* @param fsImpl - Implémentation du filesystem (memfs) ou undefined pour fs-extra
|
|
@@ -19,13 +124,13 @@ var FileSystemAdapter = class {
|
|
|
19
124
|
* Obtient l'implémentation du filesystem
|
|
20
125
|
*/
|
|
21
126
|
getFs() {
|
|
22
|
-
return this.fsImpl ||
|
|
127
|
+
return this.fsImpl || fs2;
|
|
23
128
|
}
|
|
24
129
|
/**
|
|
25
130
|
* Normalise un chemin (résout les chemins relatifs)
|
|
26
131
|
*/
|
|
27
132
|
normalizePath(path) {
|
|
28
|
-
return
|
|
133
|
+
return resolve2(path);
|
|
29
134
|
}
|
|
30
135
|
// ===== Async Operations =====
|
|
31
136
|
async readFile(path, encoding = "utf-8") {
|
|
@@ -39,7 +144,7 @@ var FileSystemAdapter = class {
|
|
|
39
144
|
const buffer = content;
|
|
40
145
|
return buffer.toString(encoding);
|
|
41
146
|
} else {
|
|
42
|
-
const content = await
|
|
147
|
+
const content = await fs2.readFile(fullPath, encoding);
|
|
43
148
|
if (typeof content === "string") {
|
|
44
149
|
return content;
|
|
45
150
|
}
|
|
@@ -50,12 +155,12 @@ var FileSystemAdapter = class {
|
|
|
50
155
|
async writeFile(path, content, encoding = "utf-8") {
|
|
51
156
|
const fullPath = this.normalizePath(path);
|
|
52
157
|
const implementation = this.getFs();
|
|
53
|
-
const parentDir =
|
|
158
|
+
const parentDir = dirname2(fullPath);
|
|
54
159
|
await this.mkdir(parentDir, { recursive: true });
|
|
55
160
|
if (this.fsImpl) {
|
|
56
161
|
await implementation.promises.writeFile(fullPath, content, encoding);
|
|
57
162
|
} else {
|
|
58
|
-
await
|
|
163
|
+
await fs2.writeFile(fullPath, content, encoding);
|
|
59
164
|
}
|
|
60
165
|
}
|
|
61
166
|
async mkdir(path, _options) {
|
|
@@ -64,7 +169,7 @@ var FileSystemAdapter = class {
|
|
|
64
169
|
if (this.fsImpl) {
|
|
65
170
|
await implementation.promises.mkdir(fullPath, { recursive: true });
|
|
66
171
|
} else {
|
|
67
|
-
await
|
|
172
|
+
await fs2.ensureDir(fullPath);
|
|
68
173
|
}
|
|
69
174
|
}
|
|
70
175
|
async readdir(path) {
|
|
@@ -73,7 +178,7 @@ var FileSystemAdapter = class {
|
|
|
73
178
|
const entries = this.fsImpl.readdirSync(fullPath);
|
|
74
179
|
return Promise.resolve(entries.map((entry) => String(entry)));
|
|
75
180
|
} else {
|
|
76
|
-
return await
|
|
181
|
+
return await fs2.readdir(fullPath);
|
|
77
182
|
}
|
|
78
183
|
}
|
|
79
184
|
async stat(path) {
|
|
@@ -87,7 +192,7 @@ var FileSystemAdapter = class {
|
|
|
87
192
|
mtime: stats.mtime
|
|
88
193
|
};
|
|
89
194
|
} else {
|
|
90
|
-
const stats = await
|
|
195
|
+
const stats = await fs2.stat(fullPath);
|
|
91
196
|
return {
|
|
92
197
|
isFile: () => stats.isFile(),
|
|
93
198
|
isDirectory: () => stats.isDirectory(),
|
|
@@ -106,7 +211,7 @@ var FileSystemAdapter = class {
|
|
|
106
211
|
return false;
|
|
107
212
|
}
|
|
108
213
|
} else {
|
|
109
|
-
return await
|
|
214
|
+
return await fs2.pathExists(fullPath);
|
|
110
215
|
}
|
|
111
216
|
}
|
|
112
217
|
async readJson(path) {
|
|
@@ -115,18 +220,18 @@ var FileSystemAdapter = class {
|
|
|
115
220
|
const content = await this.readFile(fullPath);
|
|
116
221
|
return JSON.parse(content);
|
|
117
222
|
} else {
|
|
118
|
-
return await
|
|
223
|
+
return await fs2.readJson(fullPath);
|
|
119
224
|
}
|
|
120
225
|
}
|
|
121
226
|
async writeJson(path, data, options) {
|
|
122
227
|
const fullPath = this.normalizePath(path);
|
|
123
|
-
const parentDir =
|
|
228
|
+
const parentDir = dirname2(fullPath);
|
|
124
229
|
await this.mkdir(parentDir, { recursive: true });
|
|
125
230
|
if (this.fsImpl) {
|
|
126
231
|
const content = JSON.stringify(data, null, options?.spaces ?? 2);
|
|
127
232
|
await this.writeFile(fullPath, content);
|
|
128
233
|
} else {
|
|
129
|
-
await
|
|
234
|
+
await fs2.writeJson(fullPath, data, {
|
|
130
235
|
spaces: options?.spaces ?? 2,
|
|
131
236
|
EOL: options?.EOL ?? "\n"
|
|
132
237
|
});
|
|
@@ -135,13 +240,13 @@ var FileSystemAdapter = class {
|
|
|
135
240
|
async copyFile(src, dest) {
|
|
136
241
|
const srcPath = this.normalizePath(src);
|
|
137
242
|
const destPath = this.normalizePath(dest);
|
|
138
|
-
const destDir =
|
|
243
|
+
const destDir = dirname2(destPath);
|
|
139
244
|
await this.mkdir(destDir, { recursive: true });
|
|
140
245
|
if (this.fsImpl) {
|
|
141
246
|
const content = await this.readFile(srcPath);
|
|
142
247
|
await this.writeFile(destPath, content);
|
|
143
248
|
} else {
|
|
144
|
-
await
|
|
249
|
+
await fs2.copyFile(srcPath, destPath);
|
|
145
250
|
}
|
|
146
251
|
}
|
|
147
252
|
async remove(path) {
|
|
@@ -158,7 +263,7 @@ var FileSystemAdapter = class {
|
|
|
158
263
|
} catch {
|
|
159
264
|
}
|
|
160
265
|
} else {
|
|
161
|
-
await
|
|
266
|
+
await fs2.remove(fullPath);
|
|
162
267
|
}
|
|
163
268
|
}
|
|
164
269
|
// ===== Sync Operations (pour compatibilité) =====
|
|
@@ -173,7 +278,7 @@ var FileSystemAdapter = class {
|
|
|
173
278
|
const buffer = content;
|
|
174
279
|
return buffer.toString(encoding);
|
|
175
280
|
} else {
|
|
176
|
-
const content =
|
|
281
|
+
const content = fs2.readFileSync(fullPath, encoding);
|
|
177
282
|
if (typeof content === "string") {
|
|
178
283
|
return content;
|
|
179
284
|
}
|
|
@@ -184,14 +289,14 @@ var FileSystemAdapter = class {
|
|
|
184
289
|
writeFileSync(path, content) {
|
|
185
290
|
const fullPath = this.normalizePath(path);
|
|
186
291
|
const implementation = this.getFs();
|
|
187
|
-
const parentDir =
|
|
292
|
+
const parentDir = dirname2(fullPath);
|
|
188
293
|
if (!this.existsSync(parentDir)) {
|
|
189
294
|
this.mkdirSync(parentDir, { recursive: true });
|
|
190
295
|
}
|
|
191
296
|
if (this.fsImpl) {
|
|
192
297
|
implementation.writeFileSync(fullPath, content);
|
|
193
298
|
} else {
|
|
194
|
-
|
|
299
|
+
fs2.writeFileSync(fullPath, content);
|
|
195
300
|
}
|
|
196
301
|
}
|
|
197
302
|
existsSync(path) {
|
|
@@ -205,7 +310,7 @@ var FileSystemAdapter = class {
|
|
|
205
310
|
return false;
|
|
206
311
|
}
|
|
207
312
|
} else {
|
|
208
|
-
return
|
|
313
|
+
return fs2.existsSync(fullPath);
|
|
209
314
|
}
|
|
210
315
|
}
|
|
211
316
|
mkdirSync(path, _options) {
|
|
@@ -214,7 +319,7 @@ var FileSystemAdapter = class {
|
|
|
214
319
|
if (this.fsImpl) {
|
|
215
320
|
implementation.mkdirSync(fullPath, { recursive: true });
|
|
216
321
|
} else {
|
|
217
|
-
|
|
322
|
+
fs2.ensureDirSync(fullPath);
|
|
218
323
|
}
|
|
219
324
|
}
|
|
220
325
|
};
|
|
@@ -229,7 +334,7 @@ function normalizePath(path) {
|
|
|
229
334
|
}
|
|
230
335
|
async function readPackageJson(root, fsAdapter) {
|
|
231
336
|
const adapter = fsAdapter || createDefaultFsAdapter();
|
|
232
|
-
const packageJsonPath =
|
|
337
|
+
const packageJsonPath = resolve3(root, "package.json");
|
|
233
338
|
if (!await adapter.pathExists(packageJsonPath)) {
|
|
234
339
|
throw new Error(`package.json not found at ${packageJsonPath}`);
|
|
235
340
|
}
|
|
@@ -246,7 +351,7 @@ async function readPackageJson(root, fsAdapter) {
|
|
|
246
351
|
}
|
|
247
352
|
async function writePackageJson(root, pkg, fsAdapter) {
|
|
248
353
|
const adapter = fsAdapter || createDefaultFsAdapter();
|
|
249
|
-
const packageJsonPath =
|
|
354
|
+
const packageJsonPath = resolve3(root, "package.json");
|
|
250
355
|
try {
|
|
251
356
|
await adapter.writeJson(packageJsonPath, pkg, {
|
|
252
357
|
spaces: 2,
|
|
@@ -261,9 +366,9 @@ async function writePackageJson(root, pkg, fsAdapter) {
|
|
|
261
366
|
async function readTsConfig(root, fsAdapter) {
|
|
262
367
|
const adapter = fsAdapter || createDefaultFsAdapter();
|
|
263
368
|
const possiblePaths = [
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
369
|
+
resolve3(root, "tsconfig.json"),
|
|
370
|
+
resolve3(root, "tsconfig.app.json"),
|
|
371
|
+
resolve3(root, "tsconfig.node.json")
|
|
267
372
|
];
|
|
268
373
|
for (const tsconfigPath of possiblePaths) {
|
|
269
374
|
if (await adapter.pathExists(tsconfigPath)) {
|
|
@@ -285,12 +390,12 @@ async function readTsConfig(root, fsAdapter) {
|
|
|
285
390
|
}
|
|
286
391
|
async function checkPathExists(path, fsAdapter) {
|
|
287
392
|
const adapter = fsAdapter || createDefaultFsAdapter();
|
|
288
|
-
const fullPath =
|
|
393
|
+
const fullPath = resolve3(path);
|
|
289
394
|
return adapter.pathExists(fullPath);
|
|
290
395
|
}
|
|
291
396
|
async function ensureDirectory(path, fsAdapter) {
|
|
292
397
|
const adapter = fsAdapter || createDefaultFsAdapter();
|
|
293
|
-
const fullPath =
|
|
398
|
+
const fullPath = resolve3(path);
|
|
294
399
|
try {
|
|
295
400
|
await adapter.mkdir(fullPath, { recursive: true });
|
|
296
401
|
logger.debug(`Ensured directory exists: ${fullPath}`);
|
|
@@ -299,9 +404,18 @@ async function ensureDirectory(path, fsAdapter) {
|
|
|
299
404
|
throw new Error(`Failed to create directory ${fullPath}: ${errorMessage}`);
|
|
300
405
|
}
|
|
301
406
|
}
|
|
302
|
-
async function readFileContent(filePath, encoding = "utf-8", fsAdapter) {
|
|
407
|
+
async function readFileContent(filePath, encoding = "utf-8", fsAdapter, projectRoot) {
|
|
303
408
|
const adapter = fsAdapter || createDefaultFsAdapter();
|
|
304
|
-
|
|
409
|
+
let fullPath = resolve3(filePath);
|
|
410
|
+
if (projectRoot) {
|
|
411
|
+
try {
|
|
412
|
+
fullPath = await validatePathInProjectWithSymlinks(projectRoot, filePath);
|
|
413
|
+
} catch (error) {
|
|
414
|
+
const errorMsg = getPathValidationErrorMessage(error);
|
|
415
|
+
logger.error(`Path traversal attempt blocked: ${errorMsg}`);
|
|
416
|
+
throw new Error(`Invalid path: ${errorMsg}`);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
305
419
|
if (!await adapter.pathExists(fullPath)) {
|
|
306
420
|
throw new Error(`File not found: ${fullPath}`);
|
|
307
421
|
}
|
|
@@ -314,10 +428,19 @@ async function readFileContent(filePath, encoding = "utf-8", fsAdapter) {
|
|
|
314
428
|
throw new Error(`Failed to read file ${fullPath}: ${errorMessage}`);
|
|
315
429
|
}
|
|
316
430
|
}
|
|
317
|
-
async function writeFileContent(filePath, content, encoding = "utf-8", fsAdapter) {
|
|
431
|
+
async function writeFileContent(filePath, content, encoding = "utf-8", fsAdapter, projectRoot) {
|
|
318
432
|
const adapter = fsAdapter || createDefaultFsAdapter();
|
|
319
|
-
|
|
320
|
-
|
|
433
|
+
let fullPath = resolve3(filePath);
|
|
434
|
+
if (projectRoot) {
|
|
435
|
+
try {
|
|
436
|
+
fullPath = await validatePathInProjectWithSymlinks(projectRoot, filePath);
|
|
437
|
+
} catch (error) {
|
|
438
|
+
const errorMsg = getPathValidationErrorMessage(error);
|
|
439
|
+
logger.error(`Path traversal attempt blocked: ${errorMsg}`);
|
|
440
|
+
throw new Error(`Invalid path: ${errorMsg}`);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
const parentDir = dirname3(fullPath);
|
|
321
444
|
await ensureDirectory(parentDir, adapter);
|
|
322
445
|
try {
|
|
323
446
|
await adapter.writeFile(fullPath, content, encoding);
|
|
@@ -330,6 +453,8 @@ async function writeFileContent(filePath, content, encoding = "utf-8", fsAdapter
|
|
|
330
453
|
|
|
331
454
|
export {
|
|
332
455
|
createDefaultFsAdapter,
|
|
456
|
+
validatePathInProjectWithSymlinks,
|
|
457
|
+
getPathValidationErrorMessage,
|
|
333
458
|
normalizePath,
|
|
334
459
|
readPackageJson,
|
|
335
460
|
writePackageJson,
|