package-management 0.0.16 → 0.1.0

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/index.cjs CHANGED
@@ -1,9 +1,7 @@
1
1
  'use strict';
2
2
 
3
- const ErrorStackParser = require('error-stack-parser');
4
3
  const path = require('pathe');
5
- const process = require('node:process');
6
- const path$1 = require('node:path');
4
+ const util = require('node:util');
7
5
  const node_url = require('node:url');
8
6
  const node_fs = require('node:fs');
9
7
  const asyncCacheFn = require('async-cache-fn');
@@ -11,17 +9,19 @@ const execa = require('execa');
11
9
  const findUp = require('find-up');
12
10
  const promises = require('node:fs/promises');
13
11
  const mlly = require('mlly');
12
+ const WST = require('workspace-tools');
13
+ const process = require('node:process');
14
+ const path$1 = require('node:path');
14
15
  const globby = require('globby');
15
16
  const gitignoreParser = require('parse-gitignore');
16
- const WST = require('workspace-tools');
17
17
  const utils = require('pathe/utils');
18
18
  const os = require('node:os');
19
19
  const jsoncParser = require('jsonc-parser');
20
- const util = require('@arktype/util');
21
20
  const unstorage = require('unstorage');
22
21
  const defineMemoryDriver = require('unstorage/drivers/memory');
23
22
  const defineFsLiteDriver = require('unstorage/drivers/fs-lite');
24
23
 
24
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
25
25
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
26
26
 
27
27
  function _interopNamespaceCompat(e) {
@@ -36,16 +36,80 @@ function _interopNamespaceCompat(e) {
36
36
  return n;
37
37
  }
38
38
 
39
- const ErrorStackParser__default = /*#__PURE__*/_interopDefaultCompat(ErrorStackParser);
40
- const path__default$1 = /*#__PURE__*/_interopDefaultCompat(path);
39
+ const path__default = /*#__PURE__*/_interopDefaultCompat(path);
40
+ const util__default = /*#__PURE__*/_interopDefaultCompat(util);
41
+ const WST__namespace = /*#__PURE__*/_interopNamespaceCompat(WST);
41
42
  const process__default = /*#__PURE__*/_interopDefaultCompat(process);
42
- const path__default = /*#__PURE__*/_interopDefaultCompat(path$1);
43
+ const path__default$1 = /*#__PURE__*/_interopDefaultCompat(path$1);
43
44
  const gitignoreParser__default = /*#__PURE__*/_interopDefaultCompat(gitignoreParser);
44
- const WST__namespace = /*#__PURE__*/_interopNamespaceCompat(WST);
45
45
  const os__default = /*#__PURE__*/_interopDefaultCompat(os);
46
46
  const defineMemoryDriver__default = /*#__PURE__*/_interopDefaultCompat(defineMemoryDriver);
47
47
  const defineFsLiteDriver__default = /*#__PURE__*/_interopDefaultCompat(defineFsLiteDriver);
48
48
 
49
+ const getCallSites = "getCallSites" in util__default ? util__default.getCallSites : void 0;
50
+ const MAX_FRAMES = 200;
51
+ function resolveCallerFile(options) {
52
+ const { from, boundaryFunctionName, internalScripts = [] } = options ?? {};
53
+ if (from) return toCallerPath(String(from));
54
+ if (getCallSites === void 0) return void 0;
55
+ const sites = getCallSites(MAX_FRAMES, { sourceMap: true });
56
+ const scriptName = boundaryFunctionName && frameAfterFunction(sites, boundaryFunctionName) || firstForeignFrame(sites, [OWN_SCRIPT, ...internalScripts]);
57
+ return scriptName ? toFilePath(scriptName) : void 0;
58
+ }
59
+ const OWN_SCRIPT = (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href));
60
+ function frameAfterFunction(sites, functionName) {
61
+ const boundary = sites.findIndex((site) => site.functionName === functionName);
62
+ return boundary === -1 ? void 0 : sites[boundary + 1]?.scriptName;
63
+ }
64
+ function firstForeignFrame(sites, internalScripts) {
65
+ const internal = new Set(internalScripts.map(toFilePath));
66
+ return sites.find(
67
+ (site) => (
68
+ // Frames from `node:` internals and evaluated code name no file, so they
69
+ // are never the caller's location however far out they appear.
70
+ isFileScript(site.scriptName) && !internal.has(toFilePath(site.scriptName))
71
+ )
72
+ )?.scriptName;
73
+ }
74
+ const isFileScript = (script) => Boolean(script) && (script.startsWith("file:") || path.isAbsolute(script));
75
+ const toFilePath = (script) => script.startsWith("file:") ? node_url.fileURLToPath(script) : script;
76
+ function toCallerPath(from) {
77
+ if (from.startsWith("file:")) return node_url.fileURLToPath(from);
78
+ if (path.isAbsolute(from)) return from;
79
+ throw new Error(
80
+ `\`from\` must be a file: URL or an absolute path, received ${JSON.stringify(from)}. Pass \`import.meta.url\`.`
81
+ );
82
+ }
83
+
84
+ const _filename = (options) => resolveCallerFile(withOwnScript(options));
85
+ const _dirname = (options) => {
86
+ const filePath = resolveCallerFile(withOwnScript(options));
87
+ return filePath === void 0 ? void 0 : path.dirname(filePath);
88
+ };
89
+ const withOwnScript = (options) => ({
90
+ ...options,
91
+ internalScripts: [...options?.internalScripts ?? [], (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))]
92
+ });
93
+
94
+ function createFile(filePath, data, options) {
95
+ const { encoding = "utf-8", ...rest } = typeof options === "string" ? { encoding: options } : options ?? {};
96
+ const dir = path__default.dirname(filePath);
97
+ const writeFileOptions = { encoding, ...rest };
98
+ if (!node_fs.existsSync(dir)) {
99
+ node_fs.mkdirSync(dir, { recursive: true });
100
+ }
101
+ node_fs.writeFileSync(filePath, data, writeFileOptions);
102
+ }
103
+
104
+ function isWritable(filename) {
105
+ try {
106
+ node_fs.accessSync(filename, node_fs.constants.W_OK);
107
+ return true;
108
+ } catch (e) {
109
+ return false;
110
+ }
111
+ }
112
+
49
113
  const toArray = (data) => Array.isArray(data) ? data : [data];
50
114
  const entriesOf = (o) => Object.entries(o);
51
115
  const fromEntries = (entries) => Object.fromEntries(entries);
@@ -59,7 +123,7 @@ const select = (obj, selection, mode) => {
59
123
  };
60
124
  function normalizePath(path$1, option) {
61
125
  if (typeof option === "function") {
62
- return normalizePath(path$1);
126
+ return option(path$1);
63
127
  }
64
128
  if (option === false) {
65
129
  return path$1;
@@ -71,14 +135,6 @@ const invariant = (predicate, message) => {
71
135
  throw new Error(message);
72
136
  }
73
137
  };
74
- function getArrayItemAtOffset(arr, index, offset = 0) {
75
- if (arr === void 0 || index === void 0) return void 0;
76
- return arr[index + offset];
77
- }
78
- function isMatching(a, b) {
79
- if (!a || !b) return false;
80
- return a === b;
81
- }
82
138
  function checkResult(cb, options) {
83
139
  try {
84
140
  return buildSingleProp({
@@ -103,123 +159,16 @@ function buildSingleProp(entry) {
103
159
  return { [key]: value };
104
160
  }
105
161
 
106
- function findCallerStackFrame(options) {
107
- return findErrorStackFrame(options, (frame) => frame.isParentOfRootFunction);
108
- }
109
- function findErrorStackFrame(options, find) {
110
- return getErrorStackFrames(options, find)[0];
111
- }
112
- function getErrorStackFrames(options, filter) {
113
- const { error, rootFunctionName, startFrom = "top" } = options;
114
- const frames = startFrom === "bottom" ? ErrorStackParser__default.parse(error).reverse() : ErrorStackParser__default.parse(error);
115
- const { parsedFrames } = frames.reduce(
116
- (acc, frame, index) => {
117
- const parsed = parseFrame({
118
- frame,
119
- index,
120
- rootFunctionName,
121
- frames
122
- });
123
- const isValid = filter ? filter(parsed) : true;
124
- if (isValid) {
125
- acc.parsedFrames.push(parsed);
126
- }
127
- return acc;
128
- },
129
- { parsedFrames: [] }
130
- );
131
- return parsedFrames ?? [];
132
- }
133
- function parseFrame(options) {
134
- const { frame, frames, index, rootFunctionName, cwd, debug } = options ?? {};
135
- const functionName = parseFunctionName(frame.functionName);
136
- const isRootFunction = isMatching(functionName, rootFunctionName);
137
- const beforeFrameFunctionName = parseFunctionName(
138
- getArrayItemAtOffset(frames, index, -1)?.functionName
139
- );
140
- const isParentOfRootFunction = isMatching(
141
- beforeFrameFunctionName,
142
- rootFunctionName
143
- );
144
- const fileData = frame.fileName ? getFilePathData({ filepath: frame.fileName, cwd }) : void 0;
145
- const { isFileInCwd: isFrameInScope, ...restFileData } = fileData ?? {};
146
- const data = {
147
- ...restFileData,
148
- functionName,
149
- source: frame.source,
150
- sourceFunctionName: frame.functionName,
151
- isFrameInScope,
152
- place: placeFormatter(index, frames?.length),
153
- isRootFunction,
154
- isParentOfRootFunction,
155
- rootFunctionName
156
- };
157
- debug && console.log(data);
158
- return data;
159
- }
160
- function getFilePathData({
161
- filepath,
162
- cwd
163
- }) {
164
- const workingDir = cwd ?? process__default.cwd();
165
- const filePath = path.normalize(toFilePath(filepath));
166
- const fileBasename = path.basename(filePath);
167
- const dirPath = path.dirname(filePath);
168
- const dirBasename = path.basename(dirPath);
169
- const relativeFilePath = path.relative(workingDir, filePath);
170
- const relativeDirPath = path.dirname(relativeFilePath);
171
- const isFileInCwd = filePath.startsWith(workingDir);
172
- return {
173
- filePath,
174
- dirPath,
175
- relativeFilePath,
176
- relativeDirPath,
177
- fileBasename,
178
- dirBasename,
179
- isFileInCwd
180
- };
181
- }
182
- function toFilePath(fileName) {
183
- return fileName.startsWith("file:") ? node_url.fileURLToPath(fileName) : fileName;
184
- }
185
- function parseFunctionName(functionName) {
186
- if (!functionName) return void 0;
187
- return removeStart(functionName, "Module.");
188
- }
189
- function removeStart(input, value) {
190
- return input.startsWith(value) ? input.slice(value.length) : input;
191
- }
192
- function placeFormatter(index, total) {
193
- if (index === void 0 || !total) return void 0;
194
- return [index, total].join("/");
195
- }
196
-
197
- const _filename = (options) => {
198
- const { filePath } = findCallerStackFrame({ error: new Error(), ...options }) ?? {};
199
- return filePath;
200
- };
201
- const _dirname = (options) => {
202
- const { dirPath } = findCallerStackFrame({ error: new Error(), ...options }) ?? {};
203
- return dirPath;
204
- };
205
-
206
162
  async function resolveModule(module) {
207
163
  const resolved = await module;
208
- return resolved.default || resolved;
164
+ const hasDefault = resolved !== null && typeof resolved === "object" && "default" in resolved;
165
+ return hasDefault ? resolved.default : resolved;
209
166
  }
210
167
  function isPackageModuleFound(name, options) {
211
168
  return Boolean(resolvePackageModulePath(name, options));
212
169
  }
213
170
  function resolvePackageModulePath(name, options) {
214
- const resolvedPath = findResolvedModulePath(
215
- [`${name}/package.json`, name],
216
- options
217
- );
218
- if (resolvedPath === void 0) {
219
- console.error(`Could not resolve package ${name}`);
220
- return void 0;
221
- }
222
- return resolvedPath;
171
+ return findResolvedModulePath([`${name}/package.json`, name], options);
223
172
  }
224
173
  function findResolvedModulePath(paths, options) {
225
174
  for (const path of paths) {
@@ -241,28 +190,68 @@ function resolveModulePath(modulePath, options) {
241
190
  }
242
191
  }
243
192
 
193
+ function getPackageFolder(options) {
194
+ return WST__namespace.findPackageRoot(options?.cwd ?? process__default.cwd());
195
+ }
196
+
197
+ function getPackageInfo(options) {
198
+ const packageDir = getPackageFolder(options);
199
+ if (!packageDir) {
200
+ throw new Error(
201
+ `No package.json found searching up from "${options?.cwd ?? process__default.cwd()}"`
202
+ );
203
+ }
204
+ return readPackageInfo({ packageDir });
205
+ }
206
+ function readPackageInfo({
207
+ packageDir
208
+ }) {
209
+ const packageJsonPath = path__default$1.join(packageDir, "package.json");
210
+ const packageJson = readPackageJson(packageJsonPath);
211
+ return {
212
+ name: packageJson.name,
213
+ path: packageJsonPath,
214
+ dirpath: packageDir,
215
+ packageJson
216
+ };
217
+ }
218
+ const packageJsonCache = /* @__PURE__ */ new Map();
219
+ function readPackageJson(packageJsonPath) {
220
+ const { mtimeMs } = node_fs.statSync(packageJsonPath);
221
+ const cached = packageJsonCache.get(packageJsonPath);
222
+ if (cached?.mtimeMs === mtimeMs) return cached.packageJson;
223
+ const packageJson = JSON.parse(
224
+ node_fs.readFileSync(packageJsonPath, "utf-8")
225
+ );
226
+ packageJsonCache.set(packageJsonPath, { mtimeMs, packageJson });
227
+ return packageJson;
228
+ }
229
+
244
230
  const tsconfig = (tsconfigDir) => ({
245
231
  get paths() {
232
+ if (!tsconfigDir) return [];
246
233
  return globby.globbySync(["tsconfig.json", "tsconfig.*.json"], {
247
- cwd: tsconfigDir
248
- }) ?? [];
234
+ cwd: tsconfigDir,
235
+ absolute: true
236
+ });
249
237
  }
250
238
  });
251
239
 
252
- function parseGitignoreFile(gitignorePath, options) {
253
- return gitignoreParser__default(gitignorePath, options);
240
+ function parseGitignoreContent(gitignoreContent, options) {
241
+ return gitignoreParser__default(gitignoreContent, options);
254
242
  }
255
- function getGitignoreData(gitignorePath) {
256
- const gitignoreFileContent = node_fs.readFileSync(gitignorePath, "utf-8");
257
- const gitignores = parseGitignoreFile(gitignoreFileContent);
258
- return gitignores;
243
+ function getGitignoreData(gitignorePath, options) {
244
+ if (!gitignorePath || !node_fs.existsSync(gitignorePath)) {
245
+ return parseGitignoreContent("", options);
246
+ }
247
+ return parseGitignoreContent(node_fs.readFileSync(gitignorePath, "utf-8"), options);
259
248
  }
260
- const gitignore = (gitignorePath) => ({
249
+ const gitignore = (gitignorePath, options) => ({
261
250
  get data() {
262
- return getGitignoreData(gitignorePath);
251
+ return getGitignoreData(gitignorePath, options);
263
252
  },
264
253
  get patterns() {
265
- return getGitignoreData(gitignorePath).patterns;
254
+ return getGitignoreData(gitignorePath, options).patterns;
266
255
  }
267
256
  });
268
257
 
@@ -325,36 +314,13 @@ function getWorkspaceFolder(options) {
325
314
  throwIfNotFound = true
326
315
  } = options ?? {};
327
316
  const getFolder = fallbackToGitRoot ? WST__namespace.findProjectRoot : WST__namespace.getWorkspaceManagerRoot;
328
- const folder = getFolder(cwd);
317
+ const folder = checkResult(() => getFolder(cwd)).data;
329
318
  if (folder === void 0 && throwIfNotFound) {
330
319
  throw new Error(`Could not find workspace folder`);
331
320
  }
332
321
  return folder;
333
322
  }
334
323
 
335
- function getPackageFolder(options) {
336
- return WST__namespace.findPackageRoot(options?.cwd ?? process__default.cwd());
337
- }
338
-
339
- function getPackageInfo(options) {
340
- const packageDir = getPackageFolder(options);
341
- return readPackageInfo({ packageDir });
342
- }
343
- function readPackageInfo({
344
- packageDir
345
- }) {
346
- const packageJsonPath = path__default.join(packageDir, "package.json");
347
- const packageJson = JSON.parse(
348
- node_fs.readFileSync(packageJsonPath, "utf-8")
349
- );
350
- return {
351
- name: packageJson.name,
352
- path: packageJsonPath,
353
- dirpath: packageDir,
354
- packageJson
355
- };
356
- }
357
-
358
324
  function getWorkspaceProjectInfo(options) {
359
325
  try {
360
326
  const workspaceDir = getWorkspaceFolder(options);
@@ -370,13 +336,21 @@ function getWorkspacePackageInfoList(options) {
370
336
  const wstList = WST__namespace.getWorkspaceInfos(workspaceDir);
371
337
  return resolveWstList(wstList);
372
338
  }
339
+ function toPackageInfo(info) {
340
+ return {
341
+ name: info.name,
342
+ dirpath: info.path,
343
+ path: path.join(info.path, "package.json"),
344
+ packageJson: info.packageJson
345
+ };
346
+ }
373
347
  function common(options) {
374
348
  const { cwd, includeRoot: includeWorkspace } = options ?? {};
375
349
  const workspaceDir = getWorkspaceFolder({ cwd });
376
350
  function resolveWstList(list) {
377
351
  if (!workspaceDir || !list) return [];
378
- if (includeWorkspace) return [getWorkspaceProjectInfo(), ...list];
379
- return list;
352
+ const packages = list.map(toPackageInfo);
353
+ return includeWorkspace ? [getWorkspaceProjectInfo({ cwd }), ...packages] : packages;
380
354
  }
381
355
  return {
382
356
  workspaceDir,
@@ -393,7 +367,7 @@ function getWorkspacePackageInfoMap(options) {
393
367
 
394
368
  function getProjectInfoByName(name, options) {
395
369
  const { cwd } = options ?? {};
396
- return getWorkspacePackageInfoMap({ cwd })[name];
370
+ return getWorkspacePackageInfoMap({ cwd, includeRoot: true })[name];
397
371
  }
398
372
 
399
373
  function getGitRootFolder(options) {
@@ -408,7 +382,7 @@ function getGitRootFolder(options) {
408
382
  }
409
383
  return void 0;
410
384
  }
411
- return path__default$1.normalize(stdout);
385
+ return path__default.normalize(stdout);
412
386
  }
413
387
 
414
388
  function getProjectInfo(folder, options) {
@@ -439,9 +413,14 @@ function parseWorkspaceFolderTypeOptions(option, defaultOptions) {
439
413
 
440
414
  const project = (...args) => {
441
415
  const [source, projectOptions] = args;
442
- const { packageJson, packageJsonPath, packageName, projectDir } = info();
443
416
  const {
444
- findPackageManager: findPackageManager2,
417
+ packageJson,
418
+ name: packageName,
419
+ dirpath: projectDir,
420
+ path: packageJsonPath
421
+ } = getProjectInfo(source, projectOptions) ?? {};
422
+ const {
423
+ findPackageManager,
445
424
  detectPackageManagers,
446
425
  detectLockfilePackageManagers,
447
426
  detectGlobalPackageManagers,
@@ -449,41 +428,29 @@ const project = (...args) => {
449
428
  filterPackageManagers,
450
429
  mapPackageManagers
451
430
  } = definePackageManagerClient({ cwd: projectDir });
431
+ const getPackageJson = () => projectDir ? readPackageInfo({ packageDir: projectDir }).packageJson : packageJson;
452
432
  return {
453
433
  packageJson,
454
434
  packageJsonPath,
455
435
  packageName,
456
436
  projectDir,
457
- findPackageManager: findPackageManager2,
437
+ findPackageManager,
458
438
  detectPackageManagers,
459
439
  detectGlobalPackageManagers,
460
440
  detectLockfilePackageManagers,
461
441
  globalVersions,
462
442
  mapPackageManagers,
463
- tsconfig: tsconfig(projectDir ?? ""),
464
- gitignore: gitignore(path__default$1.join(projectDir ?? "", ".gitignore")),
443
+ // Passed through as-is: substituting "" for an unresolved project made
444
+ // both of these read from the calling process's directory instead.
445
+ tsconfig: tsconfig(projectDir),
446
+ gitignore: gitignore(
447
+ projectDir ? path__default.join(projectDir, ".gitignore") : void 0
448
+ ),
465
449
  filterPackageManagers,
466
- getPackageJson: () => get("packageJson"),
467
- findDependencyInPackageJson: (options) => findDependencyInPackageJson(options, get("packageJson")),
468
- isDependencyInPackageJson: (options) => isDependencyInPackageJson(options, get("packageJson"))
450
+ getPackageJson,
451
+ findDependencyInPackageJson: (options) => findDependencyInPackageJson(options, getPackageJson()),
452
+ isDependencyInPackageJson: (options) => isDependencyInPackageJson(options, getPackageJson())
469
453
  };
470
- function info() {
471
- const {
472
- packageJson: packageJson2,
473
- name: packageName2,
474
- dirpath: projectDir2,
475
- path: packageJsonPath2
476
- } = getProjectInfo(source, projectOptions) ?? {};
477
- return {
478
- packageJson: packageJson2,
479
- packageJsonPath: packageJsonPath2,
480
- packageName: packageName2,
481
- projectDir: projectDir2
482
- };
483
- }
484
- function get(key) {
485
- return info()[key];
486
- }
487
454
  };
488
455
 
489
456
  function getWorkspacePackageNames(options) {
@@ -498,18 +465,24 @@ const workspace = {
498
465
  getProject: project
499
466
  };
500
467
 
501
- function importer(imports, options) {
468
+ async function importer(imports, options) {
502
469
  const { install: defaultInstall = true, installer } = options ?? {};
470
+ const resolved = imports.map((option) => resolveImportOption(option));
471
+ const missing = resolved.filter(
472
+ (option) => Boolean(option.name) && (option.install ?? defaultInstall) && !((option.checkExists ?? true) && isSatisfied(option.name))
473
+ );
474
+ await installMissing(
475
+ missing.filter(({ dev }) => !dev).map(({ name }) => name),
476
+ { dev: false },
477
+ installer
478
+ );
479
+ await installMissing(
480
+ missing.filter(({ dev }) => dev).map(({ name }) => name),
481
+ { dev: true },
482
+ installer
483
+ );
503
484
  return Promise.all(
504
- imports.map(async (e) => {
505
- const importOpt = resolveImportOption(e);
506
- const shouldInstall = importOpt.install ?? defaultInstall;
507
- if (shouldInstall && importOpt.name) {
508
- await installImport(importOpt.name, importOpt, installer);
509
- }
510
- const m = await importOpt.import();
511
- return resolveModule(m);
512
- })
485
+ resolved.map(async (option) => resolveModule(await option.import()))
513
486
  );
514
487
  }
515
488
  const definePackage = (option) => {
@@ -533,12 +506,11 @@ function resolveImportOption(option) {
533
506
  }
534
507
  return option;
535
508
  }
536
- async function installImport(packageName, options, installer) {
537
- if (!packageName) return;
538
- const { checkExists } = options ?? {};
539
- if (checkExists && isPackageDependency(packageName)) return;
509
+ const isSatisfied = (packageName) => isPackageDependency(packageName) && isPackageModuleFound(packageName);
510
+ async function installMissing(packageNames, options, installer) {
511
+ if (packageNames.length === 0) return;
540
512
  const installerFn = installer ?? (await workspace.getProject("<package_folder>").findPackageManager()).installPackage;
541
- await installerFn(packageName, options);
513
+ await installerFn(packageNames, options);
542
514
  }
543
515
 
544
516
  const importMap = async (importMap2, options) => {
@@ -560,20 +532,36 @@ function definePackageManager(config, options) {
560
532
  const lockfiles = toArray(config.meta.lockfile);
561
533
  return await findUp.findUp(lockfiles, { cwd });
562
534
  });
535
+ const globalVersion = asyncCacheFn.asyncCacheFn(
536
+ async (options2) => {
537
+ try {
538
+ const { stdout } = await $$({
539
+ command,
540
+ args: [agentOptions.version],
541
+ cwd: defaultCwd,
542
+ ...options2
543
+ });
544
+ return `${stdout}`.trim();
545
+ } catch {
546
+ return void 0;
547
+ }
548
+ }
549
+ );
563
550
  const installPackage = async (packageName, options2) => {
564
551
  const install = agentArgs.install;
565
- const { dev, preferOffline } = select(
566
- install.options,
567
- {
568
- preferOffline: true,
569
- cwd: defaultCwd,
570
- ...options2
571
- });
552
+ const { dev = false, preferOffline = true } = options2 ?? {};
553
+ const flags = select(install.options, { dev, preferOffline });
572
554
  const packageNames = toArray(packageName);
555
+ assertInstallableNames(packageNames);
573
556
  try {
574
557
  await $$({
575
558
  command,
576
- args: [install.command, dev, preferOffline, ...packageNames],
559
+ args: [
560
+ install.command,
561
+ flags.dev,
562
+ flags.preferOffline,
563
+ ...packageNames
564
+ ],
577
565
  cwd: defaultCwd,
578
566
  ...options2
579
567
  });
@@ -617,19 +605,12 @@ function definePackageManager(config, options) {
617
605
  if (!lockfilePath) return void 0;
618
606
  return promises.readFile(lockfilePath, "utf8");
619
607
  }),
620
- globalVersion: asyncCacheFn.asyncCacheFn(async (...args) => {
621
- const [options2] = args;
622
- try {
623
- const { stdout } = await $$({
624
- command,
625
- args: [agentOptions.version],
626
- cwd: defaultCwd,
627
- ...options2
628
- });
629
- return `${stdout}`;
630
- } catch (e) {
631
- return void 0;
632
- }
608
+ globalVersion,
609
+ matchesVersion: asyncCacheFn.asyncCacheFn(async (...args) => {
610
+ const { matchesVersion } = config.meta;
611
+ if (!matchesVersion) return true;
612
+ const version = await globalVersion.noCache(...args);
613
+ return version ? matchesVersion(version) : false;
633
614
  }),
634
615
  definePackage,
635
616
  installPackage,
@@ -643,6 +624,16 @@ function definePackageManager(config, options) {
643
624
  }
644
625
  };
645
626
  }
627
+ function assertInstallableNames(packageNames) {
628
+ const rejected = packageNames.filter(
629
+ (name) => name.length === 0 || name.startsWith("-")
630
+ );
631
+ if (rejected.length > 0) {
632
+ throw new Error(
633
+ `Not a package name: ${rejected.map((name) => JSON.stringify(name)).join(", ")}. A package name cannot be empty or begin with "-".`
634
+ );
635
+ }
636
+ }
646
637
  async function $$(options) {
647
638
  const { command, args = [], silent = true, cwd, shellOptions } = options;
648
639
  return execa.execa(command, args.filter(notFalsy), {
@@ -665,7 +656,9 @@ const bun = definePackageManagerConfig({
665
656
  command: "bun",
666
657
  runner: "bunx",
667
658
  meta: {
668
- lockfile: "bun.lockb"
659
+ // Bun wrote a binary lockfile originally and a text one from 1.2 onwards,
660
+ // so a project using either must still be detected.
661
+ lockfile: ["bun.lock", "bun.lockb"]
669
662
  },
670
663
  args: {
671
664
  install: {
@@ -676,7 +669,7 @@ const bun = definePackageManagerConfig({
676
669
  }
677
670
  },
678
671
  uninstall: {
679
- command: "uninstall"
672
+ command: "remove"
680
673
  }
681
674
  },
682
675
  options: {
@@ -740,7 +733,9 @@ const yarn = definePackageManagerConfig({
740
733
  command: "yarn",
741
734
  runner: "yarn dlx",
742
735
  meta: {
743
- lockfile: "yarn.lock"
736
+ lockfile: "yarn.lock",
737
+ // Berry shares this command and lockfile, so the version decides.
738
+ matchesVersion: (version) => version.startsWith("1.")
744
739
  },
745
740
  args: {
746
741
  install: {
@@ -759,6 +754,33 @@ const yarn = definePackageManagerConfig({
759
754
  }
760
755
  });
761
756
 
757
+ const yarnBerry = definePackageManagerConfig({
758
+ id: "yarn-berry",
759
+ name: "Yarn Berry",
760
+ command: "yarn",
761
+ runner: "yarn dlx",
762
+ meta: {
763
+ lockfile: "yarn.lock",
764
+ // Classic shares this command and lockfile; everything past 1.x is Berry.
765
+ matchesVersion: (version) => !version.startsWith("1.")
766
+ },
767
+ args: {
768
+ install: {
769
+ command: "add",
770
+ options: {
771
+ dev: "-D",
772
+ preferOffline: "--cached"
773
+ }
774
+ },
775
+ uninstall: {
776
+ command: "remove"
777
+ }
778
+ },
779
+ options: {
780
+ version: "--version"
781
+ }
782
+ });
783
+
762
784
  async function findPackageManager(packageManagers, options) {
763
785
  const packageManager = await findPackageManagerSafely(
764
786
  packageManagers,
@@ -788,7 +810,9 @@ async function detectPackageManagers(packageManagers, options) {
788
810
  async function detectLockfilePackageManagers(packageManagers, options) {
789
811
  return filterPackageManagers(
790
812
  packageManagers,
791
- (packageManager) => packageManager.hasLockfile(options),
813
+ // Yarn Classic and Berry share a lockfile name, so a lockfile match alone
814
+ // would report both. The version check settles which one it is.
815
+ async (packageManager) => await packageManager.hasLockfile(options) && await packageManager.matchesVersion(options),
792
816
  options
793
817
  );
794
818
  }
@@ -798,7 +822,7 @@ async function detectGlobalPackageManagers(packageManagers, options) {
798
822
  // Without the `await`, `Boolean` receives a pending promise and is always
799
823
  // `true`, so every package manager passes the filter regardless of whether
800
824
  // it is actually installed.
801
- async (packageManager) => Boolean(await packageManager.globalVersion(options)),
825
+ async (packageManager) => Boolean(await packageManager.globalVersion(options)) && await packageManager.matchesVersion(options),
802
826
  options
803
827
  );
804
828
  }
@@ -831,7 +855,7 @@ function selectAllowedPackageManagers(packageManagers, options) {
831
855
  );
832
856
  }
833
857
 
834
- const packageManagerConfigs = [pnpm, yarn, bun, npm];
858
+ const packageManagerConfigs = [pnpm, yarn, yarnBerry, bun, npm];
835
859
  function definePackageManagerClient(options) {
836
860
  const configs = packageManagerConfigs.map(
837
861
  (config) => definePackageManager(config, options)
@@ -861,8 +885,11 @@ function definePackageManagerClient(options) {
861
885
  };
862
886
  }
863
887
 
864
- function isPackageDependency(packageName) {
865
- return toArray(packageName).every((name) => isDependencyInPackageJson(name));
888
+ function isPackageDependency(packageName, options) {
889
+ const { packageJson } = getPackageInfo(options);
890
+ return toArray(packageName).every(
891
+ (name) => isDependencyInPackageJson(name, packageJson)
892
+ );
866
893
  }
867
894
 
868
895
  function definePathAliases(aliasDefinitions) {
@@ -880,42 +907,49 @@ function definePathAliases(aliasDefinitions) {
880
907
  };
881
908
  }
882
909
  function getAliasedFilePath(aliasMap, options) {
883
- const { to, startingFrom, cwd, checkExistence, glob } = typeof options === "string" || Array.isArray(options) ? { to: options } : options;
884
- const resolveOptions = { cwd, checkExistence, glob, aliasMap };
910
+ const { to, startingFrom, cwd, from, checkExistence, glob } = typeof options === "string" || Array.isArray(options) ? { to: options } : options;
911
+ const resolveOptions = { cwd, from, checkExistence, glob, aliasMap };
885
912
  try {
886
913
  return startingFrom ? resolveRelativePathTo(to, startingFrom, resolveOptions) : resolvePathTo(to, resolveOptions);
887
914
  } catch (error) {
888
- if (checkExistence || glob) return void 0;
915
+ if (error instanceof PathNotFoundError) return void 0;
889
916
  throw error;
890
917
  }
891
918
  }
919
+ class PathNotFoundError extends Error {
920
+ }
892
921
  function resolveRelativePathTo(to, from, options) {
893
922
  const pathFrom = resolvePathTo(from, options);
894
923
  const pathTo = resolvePathTo(to, options);
895
- return path__default$1.relative(pathFrom, pathTo);
924
+ return path__default.relative(pathFrom, pathTo);
896
925
  }
897
- function resolvePathTo(pathTo, { cwd, checkExistence, glob, aliasMap }) {
898
- const normalized = normalizePathTo(pathTo, { cwd, aliasMap });
926
+ function resolvePathTo(pathTo, { cwd, from, checkExistence, glob, aliasMap }) {
927
+ const normalized = normalizePathTo(pathTo, { cwd, from, aliasMap });
899
928
  if (glob) {
900
929
  const globPaths = globby.globbySync(normalized, { cwd });
901
930
  if (!globPaths[0])
902
- throw new Error(`No paths found for glob: ${normalized}`);
931
+ throw new PathNotFoundError(`No paths found for glob: ${normalized}`);
903
932
  return globPaths[0];
904
933
  }
905
934
  if (!glob && checkExistence && !node_fs.existsSync(normalized))
906
- throw new Error(`Path does not exist: ${normalized}`);
935
+ throw new PathNotFoundError(`Path does not exist: ${normalized}`);
907
936
  return normalized;
908
937
  }
909
938
  function normalizePathTo(pathTo, options) {
910
- const { cwd, aliasMap } = options ?? {};
911
- const aliasedPath = Array.isArray(pathTo) ? path__default$1.join(...pathTo.filter(isNotNull)) : pathTo;
912
- const baseDir = Array.isArray(pathTo) ? pathTo[0] : findAliasToken(aliasedPath, aliasMap);
913
- if (baseDir === void 0) return aliasedPath;
914
- const baseDirPath = executeMapFn(aliasMap, baseDir, [{ cwd }]);
915
- if (typeof baseDirPath !== "string" || baseDirPath.length === 0) {
916
- throw new Error(`Path alias resolved to no location: ${baseDir}`);
939
+ const { cwd, from, aliasMap } = options ?? {};
940
+ const baseDir = Array.isArray(pathTo) ? pathTo[0] : findAliasToken(pathTo, aliasMap);
941
+ if (baseDir === void 0) return pathTo;
942
+ const baseDirPath = assertResolved(
943
+ baseDir,
944
+ executeMapFn(aliasMap, baseDir, [{ cwd, from }])
945
+ );
946
+ return Array.isArray(pathTo) ? path__default.join(baseDirPath, ...pathTo.slice(1).filter(isNotNull)) : utils.resolveAlias(pathTo, { [baseDir]: baseDirPath });
947
+ }
948
+ function assertResolved(alias, resolved) {
949
+ if (typeof resolved !== "string" || resolved.length === 0) {
950
+ throw new Error(`Path alias resolved to no location: ${alias}`);
917
951
  }
918
- return utils.resolveAlias(aliasedPath, { [baseDir]: baseDirPath });
952
+ return resolved;
919
953
  }
920
954
  function findAliasToken(pathTo, aliasMap) {
921
955
  return Object.keys(aliasMap ?? {}).filter((alias) => pathTo === alias || pathTo.startsWith(`${alias}/`)).sort((a, b) => b.length - a.length)[0];
@@ -933,10 +967,17 @@ function getAliasMap(aliasDefs) {
933
967
  return [
934
968
  [alias, resolve],
935
969
  ...subpaths.map(({ to }) => {
936
- const subpathAlias = path__default$1.join(alias, to);
970
+ const subpathAlias = path__default.join(alias, to);
937
971
  return [
938
972
  subpathAlias,
939
- (opts) => utils.resolveAlias(subpathAlias, { [alias]: resolve(opts) })
973
+ (opts) => (
974
+ // The same assertion the bare alias gets. Without it an
975
+ // unresolvable parent produced `join(undefined, "/node_modules")`
976
+ // — a path at the filesystem root — instead of failing.
977
+ utils.resolveAlias(subpathAlias, {
978
+ [alias]: assertResolved(alias, resolve(opts))
979
+ })
980
+ )
940
981
  ];
941
982
  })
942
983
  ];
@@ -1011,13 +1052,13 @@ const predefinedPathAliases = {
1011
1052
  subpaths: []
1012
1053
  },
1013
1054
  "<current_file>": {
1014
- // resolve: () => fileURLToPath(import.meta.url),
1015
- resolve: () => _filename({ rootFunctionName: "getFilePath" }) ?? "",
1055
+ // `from` is the caller naming itself, which is exact. Without it the stack
1056
+ // is read, which is a best effort and Node-only.
1057
+ resolve: (opts) => _filename({ from: opts?.from, boundaryFunctionName: "getFilePath" }),
1016
1058
  subpaths: []
1017
1059
  },
1018
1060
  "<current_folder>": {
1019
- // resolve: () => fileURLToPath(import.meta.url),
1020
- resolve: () => _dirname({ rootFunctionName: "getFilePath" }) ?? "",
1061
+ resolve: (opts) => _dirname({ from: opts?.from, boundaryFunctionName: "getFilePath" }),
1021
1062
  subpaths: []
1022
1063
  }
1023
1064
  };
@@ -1040,59 +1081,65 @@ const jsonSourceResolvers = {
1040
1081
  text: (text) => {
1041
1082
  return {
1042
1083
  text: () => text,
1043
- data: () => JSON.parse(text)
1084
+ // `jsonc-parser`'s parse, not `JSON.parse`: the whole point of this
1085
+ // module is editing files like tsconfig.json, which carry comments.
1086
+ data: () => jsoncParser.parse(text)
1044
1087
  };
1045
1088
  },
1046
1089
  filepath: (filepath) => {
1047
1090
  const text = node_fs.readFileSync(filepath, "utf-8");
1048
1091
  return {
1049
1092
  text: () => text,
1050
- data: () => JSON.parse(text)
1093
+ // `jsonc-parser`'s parse, not `JSON.parse`: the whole point of this
1094
+ // module is editing files like tsconfig.json, which carry comments.
1095
+ data: () => jsoncParser.parse(text)
1051
1096
  };
1052
1097
  }
1053
1098
  };
1054
1099
  function resolveJsonSource(source, as) {
1055
1100
  const [sourceType, sourceData] = Object.entries(source).find(([_, selected]) => selected !== void 0) ?? [];
1056
- if (!sourceType || !(sourceType in jsonSourceResolvers) || !sourceData) {
1101
+ if (!sourceType || !(sourceType in jsonSourceResolvers) || sourceData === void 0) {
1057
1102
  throw new Error("Invalid source data");
1058
1103
  }
1059
1104
  const sourceTypeResolvers = jsonSourceResolvers[sourceType](
1060
1105
  sourceData
1061
1106
  );
1062
- const resolved = util.morph(sourceTypeResolvers, (key, v) => {
1063
- try {
1064
- const value = v();
1065
- return !as || key === as ? [key, value] : [];
1066
- } catch (e) {
1067
- throw new Error(`Failed to resolve ${key} from ${sourceType}`);
1068
- }
1069
- });
1107
+ const resolved = fromEntries(
1108
+ entriesOf(sourceTypeResolvers).flatMap(([key, v]) => {
1109
+ if (as && key !== as) return [];
1110
+ try {
1111
+ return [[key, v()]];
1112
+ } catch (error) {
1113
+ throw new Error(`Failed to resolve ${key} from ${sourceType}`, {
1114
+ cause: error
1115
+ });
1116
+ }
1117
+ })
1118
+ );
1070
1119
  if (as) {
1071
1120
  return resolved[as];
1072
1121
  }
1073
1122
  return resolved;
1074
1123
  }
1075
1124
 
1125
+ const toPathSegment = (segment) => /^\d+$/.test(segment) ? Number(segment) : segment;
1076
1126
  function resolveEditPath(path, options) {
1077
- const { pathSeparator = "." } = {};
1078
- const arr = toArray(path);
1079
- return arr.map((path2) => {
1080
- if (typeof path2 === "string") {
1081
- return pathSeparator === false ? path2 : path2.split(pathSeparator);
1082
- }
1083
- return path2;
1084
- }).flat();
1127
+ const { pathSeparator = "." } = options || {};
1128
+ if (Array.isArray(path)) return path;
1129
+ if (typeof path === "number" || pathSeparator === false) return [path];
1130
+ return path.split(pathSeparator).map(toPathSegment);
1085
1131
  }
1086
- function parseJSONCEdits(edits) {
1132
+ function parseJSONCEdits(edits, defaultEditOptions) {
1133
+ const resolve = (path, options) => resolveEditPath(path, { ...defaultEditOptions, ...options });
1087
1134
  if (Array.isArray(edits)) {
1088
1135
  return edits.map(({ path, ...edit }) => ({
1089
- path: resolveEditPath(path),
1136
+ path: resolve(path, edit.options),
1090
1137
  ...edit
1091
1138
  }));
1092
1139
  }
1093
1140
  return Object.entries(edits).map(
1094
1141
  ([path, value]) => ({
1095
- path: resolveEditPath(path),
1142
+ path: resolve(path, value.options),
1096
1143
  ...value
1097
1144
  })
1098
1145
  );
@@ -1104,14 +1151,17 @@ function modifyJSON({
1104
1151
  }) {
1105
1152
  return checkResult(() => {
1106
1153
  const text = resolveJsonSource(json, "text");
1107
- const jsoncEdits = parseJSONCEdits(edits);
1108
- const editResult = jsoncEdits.flatMap(
1109
- (edit) => jsoncParser.modify(text, edit.path, edit.value, {
1110
- ...defaultEditOptions,
1111
- ...edit.options
1112
- })
1154
+ const jsoncEdits = parseJSONCEdits(edits, defaultEditOptions);
1155
+ const updated = jsoncEdits.reduce(
1156
+ (current, edit) => jsoncParser.applyEdits(
1157
+ current,
1158
+ jsoncParser.modify(current, edit.path, edit.value, {
1159
+ ...defaultEditOptions,
1160
+ ...edit.options
1161
+ })
1162
+ ),
1163
+ text
1113
1164
  );
1114
- const updated = jsoncParser.applyEdits(text, editResult);
1115
1165
  return resolveJsonSource({ text: updated });
1116
1166
  });
1117
1167
  }
@@ -1146,117 +1196,91 @@ const storage = unstorage.createStorage({ driver: defineMemoryDriver__default()
1146
1196
  const tempFileSystem = defineFileSystemStorage({
1147
1197
  base: path.join(os__default.tmpdir(), ".package-manager")
1148
1198
  });
1199
+ const encodeEntry = (value) => typeof value === "string" ? value : JSON.stringify(value);
1149
1200
  function defineFileSystemEntries(definition) {
1150
- const fileSystemEntries = Object.entries(definition).map(([k, v]) => {
1151
- if (v instanceof Function) {
1152
- const {
1153
- file,
1154
- options,
1155
- serialize = (input) => JSON.stringify(input),
1156
- deserialize = (input) => {
1157
- try {
1158
- return JSON.parse(input);
1159
- } catch {
1160
- return input;
1161
- }
1162
- }
1163
- } = v();
1164
- return {
1165
- key: k,
1166
- value: serialize(file),
1167
- options,
1168
- serialize,
1169
- deserialize
1170
- };
1201
+ const fileSystemEntries = Object.entries(definition).map(([key, value]) => {
1202
+ if (typeof value === "function") {
1203
+ const { file, options } = value();
1204
+ return { key, value: encodeEntry(file), options };
1171
1205
  }
1172
- if (isStorageValue(v)) {
1173
- return {
1174
- key: k,
1175
- value: JSON.stringify(v)
1176
- };
1206
+ if (!isStorageValue(value)) {
1207
+ throw new Error(
1208
+ `Cannot store a ${typeof value} at "${key}": file system entries must be a storage value or a function returning one.`
1209
+ );
1177
1210
  }
1178
- return void 0;
1179
- }).filter((v) => v !== void 0);
1211
+ return { key, value: encodeEntry(value) };
1212
+ });
1180
1213
  const resolved = {
1181
1214
  definition,
1182
1215
  fileSystemEntries
1183
1216
  };
1184
1217
  return resolved;
1185
1218
  }
1219
+ const keyToFilePath = (root, key) => path.join(root, ...key.split(/[:/\\]+/).filter(Boolean));
1186
1220
  function defineFileSystemStorage(options) {
1187
1221
  const { base: root, initial, ...storageOptions } = options;
1188
- let initialFileEntriesData = defineFileSystemEntries(initial ?? {});
1222
+ let entriesData = defineFileSystemEntries(initial ?? {});
1189
1223
  const storage2 = unstorage.createStorage({
1190
1224
  driver: defineFsLiteDriver__default({ base: root, ...storageOptions })
1191
1225
  });
1226
+ const getFilePath = (key) => keyToFilePath(root, key);
1227
+ const getFile = async (key) => ({
1228
+ key,
1229
+ filepath: getFilePath(key),
1230
+ data: await storage2.getItem(key),
1231
+ // `getItemRaw` resolves to null for a missing file rather than throwing.
1232
+ read: async () => (await storage2.getItemRaw(key))?.toString()
1233
+ });
1234
+ const removeAllFiles = async () => storage2.clear();
1192
1235
  const fileStorage = {
1193
1236
  createFile: async (key, data) => {
1194
1237
  await storage2.setItem(key, data);
1195
1238
  return {
1196
1239
  key,
1197
- filepath: path.join(root, key),
1240
+ filepath: getFilePath(key),
1198
1241
  get: async () => storage2.getItem(key),
1199
1242
  update: async (data2) => storage2.setItem(key, data2)
1200
1243
  };
1201
1244
  },
1202
- async getFilePath(key) {
1203
- return (await this.getFile(key)).filepath;
1204
- },
1205
- getFile: async (key) => {
1206
- const storageData = await storage2.getItem(key);
1207
- return {
1208
- key,
1209
- filepath: path.join(root, key),
1210
- data: storageData,
1211
- read: async () => (await storage2.getItemRaw(key))?.toString()
1212
- };
1213
- },
1214
- async readFile(key) {
1215
- const { read } = await this.getFile(key);
1216
- const content = await read();
1217
- return content;
1218
- },
1219
- snapshotFs: async (base = root) => {
1220
- return unstorage.snapshot(storage2, base);
1221
- },
1222
- restoreFs: async (snapshot2) => {
1223
- return unstorage.restoreSnapshot(storage2, snapshot2);
1224
- },
1245
+ getFilePath,
1246
+ getFile,
1247
+ readFile: async (key) => (await getFile(key)).read(),
1248
+ // `base` is a key prefix. Defaulting it to the filesystem root would match
1249
+ // no key at all and silently report an empty filesystem.
1250
+ snapshotFs: async (base = "") => unstorage.snapshot(storage2, base),
1251
+ restoreFs: async (snapshot2, base) => unstorage.restoreSnapshot(storage2, snapshot2, base),
1225
1252
  initializeFs: async (override) => {
1226
- if (override) {
1227
- initialFileEntriesData = defineFileSystemEntries(override);
1228
- }
1229
- await storage2.clear();
1230
- return storage2.setItems(initialFileEntriesData.fileSystemEntries);
1253
+ const previousKeys = entriesData.fileSystemEntries.map(({ key }) => key);
1254
+ if (override) entriesData = defineFileSystemEntries(override);
1255
+ await Promise.all(previousKeys.map((key) => storage2.removeItem(key)));
1256
+ await storage2.setItems(entriesData.fileSystemEntries);
1231
1257
  },
1232
1258
  defineFileSystemEntries,
1233
- removeAllFiles: storage2.clear,
1259
+ removeAllFiles,
1234
1260
  async deleteFileSystem() {
1235
- await this.removeAllFiles();
1236
- await storage2.unmount(root, true);
1261
+ await removeAllFiles();
1262
+ await storage2.dispose();
1237
1263
  await promises.rm(root, { recursive: true, force: true });
1238
1264
  },
1239
1265
  storage: storage2,
1240
1266
  meta: {
1241
- fileEntriesData: initialFileEntriesData
1267
+ // A getter, so that `initializeFs(override)` is reflected here rather
1268
+ // than this reporting whatever the definition was at construction.
1269
+ get fileEntriesData() {
1270
+ return entriesData;
1271
+ }
1242
1272
  }
1243
1273
  };
1244
- if (initial) {
1245
- return {
1246
- initialize: async () => {
1247
- await fileStorage.initializeFs(initial);
1248
- return fileStorage;
1249
- }
1250
- };
1251
- }
1252
1274
  return fileStorage;
1253
1275
  }
1254
1276
 
1255
1277
  exports._dirname = _dirname;
1256
1278
  exports._filename = _filename;
1279
+ exports.createFile = createFile;
1257
1280
  exports.defineFileSystemEntries = defineFileSystemEntries;
1258
1281
  exports.defineFileSystemStorage = defineFileSystemStorage;
1259
1282
  exports.definePackage = definePackage;
1283
+ exports.definePackageManager = definePackageManager;
1260
1284
  exports.definePackageManagerClient = definePackageManagerClient;
1261
1285
  exports.definePathAliases = definePathAliases;
1262
1286
  exports.detectGlobalPackageManagers = detectGlobalPackageManagers;
@@ -1279,6 +1303,7 @@ exports.importer = importer;
1279
1303
  exports.isDependencyInPackageJson = isDependencyInPackageJson;
1280
1304
  exports.isPackageDependency = isPackageDependency;
1281
1305
  exports.isPackageModuleFound = isPackageModuleFound;
1306
+ exports.isWritable = isWritable;
1282
1307
  exports.mapPackageManagers = mapPackageManagers;
1283
1308
  exports.modifyJSON = modifyJSON;
1284
1309
  exports.modifyJSONFile = modifyJSONFile;