package-management 0.0.9 → 0.0.11

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.mjs CHANGED
@@ -1,12 +1,13 @@
1
1
  import ErrorStackParser from 'error-stack-parser';
2
- import path$1, { normalize, basename, dirname, relative } from 'pathe';
2
+ import path$1, { normalize, basename, dirname, relative, join } from 'pathe';
3
3
  import process from 'node:process';
4
4
  import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
5
6
  import { readFileSync, existsSync, writeFileSync } from 'node:fs';
6
- import { execa, execaSync } from 'execa';
7
7
  import { asyncCacheFn } from 'async-cache-fn';
8
+ import { execaSync, execa } from 'execa';
8
9
  import { findUp } from 'find-up';
9
- import { readFile } from 'node:fs/promises';
10
+ import { readFile, rm } from 'node:fs/promises';
10
11
  import { resolvePathSync } from 'mlly';
11
12
  import { globbySync } from 'globby';
12
13
  import gitignoreParser from 'parse-gitignore';
@@ -14,16 +15,19 @@ import * as WST from 'workspace-tools';
14
15
  import { resolveAlias } from 'pathe/utils';
15
16
  import os from 'node:os';
16
17
  import { modify, applyEdits } from 'jsonc-parser';
18
+ import { morph } from '@arktype/util';
19
+ import { createStorage, restoreSnapshot, snapshot } from 'unstorage';
20
+ import defineMemoryDriver from 'unstorage/drivers/memory';
21
+ import defineFsLiteDriver from 'unstorage/drivers/fs-lite';
17
22
 
18
23
  const toArray = (data) => Array.isArray(data) ? data : [data];
19
24
  const entriesOf = (o) => Object.entries(o);
20
25
  const fromEntries = (entries) => Object.fromEntries(entries);
21
26
  const notFalsy = (value) => [false, null, void 0].every((v) => v !== value);
22
27
  const select = (obj, selection, mode) => {
23
- if (!selection)
24
- return obj;
28
+ if (!selection) return obj;
25
29
  const filtered = entriesOf(obj).filter(([key]) => {
26
- return mode === "omit" ? !selection[key] : selection[key];
30
+ return selection[key];
27
31
  });
28
32
  return fromEntries(filtered);
29
33
  };
@@ -42,15 +46,36 @@ const invariant = (predicate, message) => {
42
46
  }
43
47
  };
44
48
  function getArrayItemAtOffset(arr, index, offset = 0) {
45
- if (!index || !arr)
46
- return void 0;
49
+ if (arr === void 0 || index === void 0) return void 0;
47
50
  return arr[index + offset];
48
51
  }
49
52
  function isMatching(a, b) {
50
- if (!a || !b)
51
- return false;
53
+ if (!a || !b) return false;
52
54
  return a === b;
53
55
  }
56
+ function checkResult(cb, options) {
57
+ try {
58
+ return buildSingleProp({
59
+ key: options?.keys?.data ?? "data",
60
+ value: cb()
61
+ });
62
+ } catch (error) {
63
+ return buildSingleProp({
64
+ key: "error",
65
+ value: error
66
+ });
67
+ }
68
+ }
69
+ function isPropertyKey(input) {
70
+ return typeof input === "string" || typeof input === "number" || typeof input === "symbol";
71
+ }
72
+ function buildSingleProp(entry) {
73
+ const [key, value] = Array.isArray(entry) ? entry : [entry.key, entry.value];
74
+ if (!isPropertyKey(key)) {
75
+ return {};
76
+ }
77
+ return { [key]: value };
78
+ }
54
79
 
55
80
  function findCallerStackFrame(options) {
56
81
  return findErrorStackFrame(options, (frame) => frame.isParentOfRootFunction);
@@ -111,7 +136,7 @@ function getFilePathData({
111
136
  cwd
112
137
  }) {
113
138
  const workingDir = cwd ?? process.cwd();
114
- const filePath = normalize(filepath);
139
+ const filePath = normalize(toFilePath(filepath));
115
140
  const fileBasename = basename(filePath);
116
141
  const dirPath = dirname(filePath);
117
142
  const dirBasename = basename(dirPath);
@@ -128,17 +153,18 @@ function getFilePathData({
128
153
  isFileInCwd
129
154
  };
130
155
  }
156
+ function toFilePath(fileName) {
157
+ return fileName.startsWith("file:") ? fileURLToPath(fileName) : fileName;
158
+ }
131
159
  function parseFunctionName(functionName) {
132
- if (!functionName)
133
- return void 0;
160
+ if (!functionName) return void 0;
134
161
  return removeStart(functionName, "Module.");
135
162
  }
136
163
  function removeStart(input, value) {
137
164
  return input.startsWith(value) ? input.slice(value.length) : input;
138
165
  }
139
166
  function placeFormatter(index, total) {
140
- if (!index || !total)
141
- return void 0;
167
+ if (index === void 0 || !total) return void 0;
142
168
  return [index, total].join("/");
143
169
  }
144
170
 
@@ -172,8 +198,7 @@ function resolvePackageModulePath(name, options) {
172
198
  function findResolvedModulePath(paths, options) {
173
199
  for (const path of paths) {
174
200
  const resolvedPath = resolveModulePath(path, options);
175
- if (resolvedPath === void 0)
176
- continue;
201
+ if (resolvedPath === void 0) continue;
177
202
  return resolvedPath;
178
203
  }
179
204
  }
@@ -227,8 +252,7 @@ function isDependencyInPackageJson(options, packageJson) {
227
252
  }
228
253
  function findDependencyInPackageJson(option, packageJson) {
229
254
  const { name, type } = typeof option === "string" ? { name: option, type: void 0 } : option;
230
- if (!packageJson)
231
- return void 0;
255
+ if (!packageJson) return void 0;
232
256
  const allowedTypes = typeof type === "string" ? {
233
257
  [type]: true
234
258
  } : type ?? {
@@ -239,8 +263,7 @@ function findDependencyInPackageJson(option, packageJson) {
239
263
  const matches = allowedDependencyTypes.map((type2) => {
240
264
  return getPackageJsonDependencyItem({ name, type: type2 }, packageJson);
241
265
  }).filter(notFalsy);
242
- if (matches.length === 0)
243
- return void 0;
266
+ if (matches.length === 0) return void 0;
244
267
  return {
245
268
  firstMatch: matches[0],
246
269
  matches
@@ -250,12 +273,10 @@ function getPackageJsonDependencyItem({
250
273
  name,
251
274
  type
252
275
  }, packageJson) {
253
- if (!packageJson)
254
- return void 0;
276
+ if (!packageJson) return void 0;
255
277
  const dependencyMap = getPackageJsonDependencyMap(type, packageJson);
256
278
  const version = dependencyMap?.[name];
257
- if (version === void 0)
258
- return void 0;
279
+ if (version === void 0) return void 0;
259
280
  return {
260
281
  name,
261
282
  version,
@@ -277,7 +298,7 @@ function getWorkspaceFolder(options) {
277
298
  fallbackToGitRoot = true,
278
299
  throwIfNotFound = true
279
300
  } = options ?? {};
280
- const getFolder = fallbackToGitRoot ? WST.findProjectRoot : WST.getWorkspaceRoot;
301
+ const getFolder = fallbackToGitRoot ? WST.findProjectRoot : WST.getWorkspaceManagerRoot;
281
302
  const folder = getFolder(cwd);
282
303
  if (folder === void 0 && throwIfNotFound) {
283
304
  throw new Error(`Could not find workspace folder`);
@@ -320,17 +341,15 @@ function getWorkspaceProjectInfo(options) {
320
341
 
321
342
  function getWorkspacePackageInfoList(options) {
322
343
  const { workspaceDir, resolveWstList } = common(options);
323
- const wstList = WST.getWorkspaces(workspaceDir);
344
+ const wstList = WST.getWorkspaceInfos(workspaceDir);
324
345
  return resolveWstList(wstList);
325
346
  }
326
347
  function common(options) {
327
348
  const { cwd, includeRoot: includeWorkspace } = options ?? {};
328
349
  const workspaceDir = getWorkspaceFolder({ cwd });
329
350
  function resolveWstList(list) {
330
- if (!workspaceDir)
331
- return [];
332
- if (includeWorkspace)
333
- return [getWorkspaceProjectInfo(), ...list];
351
+ if (!workspaceDir || !list) return [];
352
+ if (includeWorkspace) return [getWorkspaceProjectInfo(), ...list];
334
353
  return list;
335
354
  }
336
355
  return {
@@ -351,6 +370,21 @@ function getProjectInfoByName(name, options) {
351
370
  return getWorkspacePackageInfoMap({ cwd })[name];
352
371
  }
353
372
 
373
+ function getGitRootFolder(options) {
374
+ const { cwd = process.cwd(), throwIfNotFound = true } = options ?? {};
375
+ const { stdout } = execaSync("git", ["rev-parse", "--show-toplevel"], {
376
+ cwd,
377
+ reject: false
378
+ });
379
+ if (!stdout) {
380
+ if (throwIfNotFound) {
381
+ throw new Error(`Directory "${cwd}" is not in a git repository`);
382
+ }
383
+ return void 0;
384
+ }
385
+ return path$1.normalize(stdout);
386
+ }
387
+
354
388
  function getProjectInfo(folder, options) {
355
389
  if (isWorkspaceFolderTypeOption(folder)) {
356
390
  return getWorkspaceProjectInfo(
@@ -361,7 +395,7 @@ function getProjectInfo(folder, options) {
361
395
  return getPackageInfo(options);
362
396
  }
363
397
  if (folder === "<gitroot_folder>") {
364
- return getPackageInfo(options);
398
+ return readPackageInfo({ packageDir: getGitRootFolder(options) });
365
399
  }
366
400
  return getProjectInfoByName(folder.packageName, options);
367
401
  }
@@ -376,9 +410,6 @@ function parseWorkspaceFolderTypeOptions(option, defaultOptions) {
376
410
  }
377
411
  return { ...defaultOptions, ...option["<workspace_folder>"] };
378
412
  }
379
- getProjectInfo({
380
- "<workspace_folder>": {}
381
- });
382
413
 
383
414
  const project = (...args) => {
384
415
  const [source, projectOptions] = args;
@@ -388,7 +419,9 @@ const project = (...args) => {
388
419
  detectPackageManagers,
389
420
  detectLockfilePackageManagers,
390
421
  detectGlobalPackageManagers,
391
- filterPackageManagers
422
+ globalVersions,
423
+ filterPackageManagers,
424
+ mapPackageManagers
392
425
  } = definePackageManagerClient({ cwd: projectDir });
393
426
  return {
394
427
  packageJson,
@@ -399,6 +432,8 @@ const project = (...args) => {
399
432
  detectPackageManagers,
400
433
  detectGlobalPackageManagers,
401
434
  detectLockfilePackageManagers,
435
+ globalVersions,
436
+ mapPackageManagers,
402
437
  tsconfig: tsconfig(projectDir ?? ""),
403
438
  gitignore: gitignore(path$1.join(projectDir ?? "", ".gitignore")),
404
439
  filterPackageManagers,
@@ -473,11 +508,9 @@ function resolveImportOption(option) {
473
508
  return option;
474
509
  }
475
510
  async function installImport(packageName, options, installer) {
476
- if (!packageName)
477
- return;
511
+ if (!packageName) return;
478
512
  const { checkExists } = options ?? {};
479
- if (checkExists && isPackageDependency(packageName))
480
- return;
513
+ if (checkExists && isPackageDependency(packageName)) return;
481
514
  const installerFn = installer ?? (await workspace.getProject("<package_folder>").findPackageManager()).installPackage;
482
515
  await installerFn(packageName, options);
483
516
  }
@@ -509,9 +542,7 @@ function definePackageManager(config, options) {
509
542
  preferOffline: true,
510
543
  cwd: defaultCwd,
511
544
  ...options2
512
- },
513
- "pick"
514
- );
545
+ });
515
546
  const packageNames = toArray(packageName);
516
547
  try {
517
548
  await $$({
@@ -520,25 +551,32 @@ function definePackageManager(config, options) {
520
551
  cwd: defaultCwd,
521
552
  ...options2
522
553
  });
523
- } catch (e) {
524
- throw new Error(`Failed to install: ${packageNames.join(", ")}`);
554
+ } catch (error) {
555
+ throw new Error(`Failed to install: ${packageNames.join(", ")}`, {
556
+ cause: error
557
+ });
525
558
  }
526
559
  };
527
560
  const uninstallPackage = async (packageName, options2) => {
528
561
  const uninstall = agentArgs.uninstall;
529
- await Promise.all(
530
- toArray(packageName).map(async (name) => {
531
- try {
532
- await $$({
533
- command,
534
- args: [uninstall.command, name],
535
- cwd: defaultCwd,
536
- ...options2
537
- });
538
- } catch (e) {
539
- }
540
- })
562
+ const cwd = options2?.cwd ?? defaultCwd;
563
+ const { packageJson } = getPackageInfo({ cwd });
564
+ const installed = toArray(packageName).filter(
565
+ (name) => isDependencyInPackageJson(name, packageJson)
541
566
  );
567
+ if (installed.length === 0) return;
568
+ try {
569
+ await $$({
570
+ command,
571
+ args: [uninstall.command, ...installed],
572
+ cwd,
573
+ ...options2
574
+ });
575
+ } catch (error) {
576
+ throw new Error(`Failed to uninstall: ${installed.join(", ")}`, {
577
+ cause: error
578
+ });
579
+ }
542
580
  };
543
581
  return {
544
582
  id: config.id,
@@ -550,8 +588,7 @@ function definePackageManager(config, options) {
550
588
  }),
551
589
  readLockfile: asyncCacheFn(async (...args) => {
552
590
  const lockfilePath = await findLockfilePath.noCache(...args);
553
- if (!lockfilePath)
554
- return void 0;
591
+ if (!lockfilePath) return void 0;
555
592
  return readFile(lockfilePath, "utf8");
556
593
  }),
557
594
  globalVersion: asyncCacheFn(async (...args) => {
@@ -585,7 +622,10 @@ async function $$(options) {
585
622
  return execa(command, args.filter(notFalsy), {
586
623
  cwd,
587
624
  ...shellOptions,
588
- stdio: silent ? "ignore" : "inherit"
625
+ // `pipe` keeps output off the console while still capturing it: a failed
626
+ // command can report why it failed, and `globalVersion` can read stdout.
627
+ // `ignore` discards the reason along with the output.
628
+ stdio: silent ? "pipe" : "inherit"
589
629
  });
590
630
  }
591
631
 
@@ -694,18 +734,24 @@ const yarn = definePackageManagerConfig({
694
734
  });
695
735
 
696
736
  async function findPackageManager(packageManagers, options) {
697
- const { ...rest } = options ?? {};
698
- const packageManager = await findPackageManagerSafely(packageManagers, rest);
737
+ const packageManager = await findPackageManagerSafely(
738
+ packageManagers,
739
+ options
740
+ );
699
741
  invariant(packageManager, "No package manager found");
700
742
  return packageManager;
701
743
  }
702
744
  async function findPackageManagerSafely(packageManagers, options) {
703
- const lockfilePm = (await detectLockfilePackageManagers(packageManagers, options))[0];
704
- if (lockfilePm) {
705
- return lockfilePm;
706
- }
707
- const globalPm = (await detectGlobalPackageManagers(packageManagers, options))[0];
708
- return globalPm;
745
+ const [fromLockfile] = await detectLockfilePackageManagers(
746
+ packageManagers,
747
+ options
748
+ );
749
+ if (fromLockfile) return fromLockfile;
750
+ const [fromGlobal] = await detectGlobalPackageManagers(
751
+ packageManagers,
752
+ options
753
+ );
754
+ return fromGlobal;
709
755
  }
710
756
  async function detectPackageManagers(packageManagers, options) {
711
757
  return [
@@ -716,29 +762,47 @@ async function detectPackageManagers(packageManagers, options) {
716
762
  async function detectLockfilePackageManagers(packageManagers, options) {
717
763
  return filterPackageManagers(
718
764
  packageManagers,
719
- (e) => e.hasLockfile(options),
765
+ (packageManager) => packageManager.hasLockfile(options),
720
766
  options
721
767
  );
722
768
  }
723
769
  async function detectGlobalPackageManagers(packageManagers, options) {
724
770
  return filterPackageManagers(
725
771
  packageManagers,
726
- async (e) => Boolean(e.globalVersion(options)),
772
+ // Without the `await`, `Boolean` receives a pending promise and is always
773
+ // `true`, so every package manager passes the filter regardless of whether
774
+ // it is actually installed.
775
+ async (packageManager) => Boolean(await packageManager.globalVersion(options)),
776
+ options
777
+ );
778
+ }
779
+ async function getGlobalVersions(packageManagers, options) {
780
+ const entries = await mapPackageManagers(
781
+ packageManagers,
782
+ async (packageManager) => [packageManager.id, await packageManager.globalVersion(options)],
727
783
  options
728
784
  );
785
+ return Object.fromEntries(entries);
786
+ }
787
+ async function mapPackageManagers(packageManagers, mapFn, options) {
788
+ return Promise.all(
789
+ selectAllowedPackageManagers(packageManagers, options).map(
790
+ (packageManager) => mapFn(packageManager)
791
+ )
792
+ );
729
793
  }
730
794
  async function filterPackageManagers(packageManagers, filterFn, options) {
731
- const allowedPackageManagers = packageManagers.filter(({ id }) => {
732
- if (!options?.allowed)
733
- return true;
734
- return id in options.allowed;
735
- });
736
- return (await Promise.all(
737
- allowedPackageManagers.map(async (pm) => {
738
- const valid = await filterFn(pm);
739
- return valid ? pm : void 0;
740
- })
741
- )).filter(notFalsy);
795
+ const matches = await mapPackageManagers(
796
+ packageManagers,
797
+ async (packageManager) => await filterFn(packageManager) ? packageManager : void 0,
798
+ options
799
+ );
800
+ return matches.filter(notFalsy);
801
+ }
802
+ function selectAllowedPackageManagers(packageManagers, options) {
803
+ return packageManagers.filter(
804
+ ({ id }) => options?.allowed ? id in options.allowed : true
805
+ );
742
806
  }
743
807
 
744
808
  const packageManagerConfigs = [pnpm, yarn, bun, npm];
@@ -763,7 +827,11 @@ function definePackageManagerClient(options) {
763
827
  detectGlobalPackageManagers: asyncCacheFn(
764
828
  async (options2) => detectGlobalPackageManagers(configs, options2)
765
829
  ),
766
- filterPackageManagers: async (filterFn, options2) => filterPackageManagers(configs, filterFn, options2)
830
+ globalVersions: asyncCacheFn(
831
+ async (options2) => getGlobalVersions(configs, options2)
832
+ ),
833
+ filterPackageManagers: async (filterFn, options2) => filterPackageManagers(configs, filterFn, options2),
834
+ mapPackageManagers: async (mapFn, options2) => mapPackageManagers(configs, mapFn, options2)
767
835
  };
768
836
  }
769
837
 
@@ -786,17 +854,13 @@ function definePathAliases(aliasDefinitions) {
786
854
  };
787
855
  }
788
856
  function getAliasedFilePath(aliasMap, options) {
857
+ const { to, startingFrom, cwd, checkExistence, glob } = typeof options === "string" || Array.isArray(options) ? { to: options } : options;
858
+ const resolveOptions = { cwd, checkExistence, glob, aliasMap };
789
859
  try {
790
- if (typeof options === "string" || Array.isArray(options)) {
791
- return resolvePathTo(options, { aliasMap });
792
- }
793
- const opts = { ...options, aliasMap };
794
- if (opts.startingFrom) {
795
- return resolveRelativePathTo(opts.to, opts.startingFrom, opts);
796
- }
797
- return resolvePathTo(opts.to, opts);
798
- } catch (e) {
799
- return void 0;
860
+ return startingFrom ? resolveRelativePathTo(to, startingFrom, resolveOptions) : resolvePathTo(to, resolveOptions);
861
+ } catch (error) {
862
+ if (checkExistence || glob) return void 0;
863
+ throw error;
800
864
  }
801
865
  }
802
866
  function resolveRelativePathTo(to, from, options) {
@@ -818,18 +882,20 @@ function resolvePathTo(pathTo, { cwd, checkExistence, glob, aliasMap }) {
818
882
  }
819
883
  function normalizePathTo(pathTo, options) {
820
884
  const { cwd, aliasMap } = options ?? {};
821
- if (Array.isArray(pathTo)) {
822
- const [baseDir] = pathTo;
823
- const aliasedPath = path$1.join(...pathTo.filter(isNotNull));
824
- return resolveAlias(aliasedPath, {
825
- [baseDir]: executeMapFn(aliasMap, baseDir, [{ cwd }])
826
- });
885
+ const aliasedPath = Array.isArray(pathTo) ? path$1.join(...pathTo.filter(isNotNull)) : pathTo;
886
+ const baseDir = Array.isArray(pathTo) ? pathTo[0] : findAliasToken(aliasedPath, aliasMap);
887
+ if (baseDir === void 0) return aliasedPath;
888
+ const baseDirPath = executeMapFn(aliasMap, baseDir, [{ cwd }]);
889
+ if (typeof baseDirPath !== "string" || baseDirPath.length === 0) {
890
+ throw new Error(`Path alias resolved to no location: ${baseDir}`);
827
891
  }
828
- return pathTo;
892
+ return resolveAlias(aliasedPath, { [baseDir]: baseDirPath });
893
+ }
894
+ function findAliasToken(pathTo, aliasMap) {
895
+ return Object.keys(aliasMap ?? {}).filter((alias) => pathTo === alias || pathTo.startsWith(`${alias}/`)).sort((a, b) => b.length - a.length)[0];
829
896
  }
830
897
  function executeMapFn(map, key, args) {
831
- if (!map || !key || !(key in map))
832
- return void 0;
898
+ if (!map || !key || !(key in map)) return void 0;
833
899
  const fnArgs = Array.isArray(args) ? args : [args];
834
900
  const resolver = map?.[key];
835
901
  return typeof resolver === "function" ? resolver?.(...fnArgs) : resolver;
@@ -868,7 +934,7 @@ const predefinedPathAliases = {
868
934
  ]
869
935
  },
870
936
  "<workspace_folder?>": {
871
- resolve: (opts) => getWorkspaceFolder(opts),
937
+ resolve: (opts) => getWorkspaceFolder({ ...opts, fallbackToGitRoot: false }),
872
938
  subpaths: [
873
939
  {
874
940
  to: "node_modules"
@@ -938,44 +1004,226 @@ function getFolderByPackageName(name, options) {
938
1004
  return info?.dirpath;
939
1005
  }
940
1006
 
941
- function getGitRootFolder(options) {
942
- const output = execaSync(`git rev-parse --show-toplevel`, {
943
- ...options,
944
- reject: false
1007
+ const jsonSourceResolvers = {
1008
+ data: (json) => {
1009
+ return {
1010
+ text: () => JSON.stringify(json),
1011
+ data: () => json
1012
+ };
1013
+ },
1014
+ text: (text) => {
1015
+ return {
1016
+ text: () => text,
1017
+ data: () => JSON.parse(text)
1018
+ };
1019
+ },
1020
+ filepath: (filepath) => {
1021
+ const text = readFileSync(filepath, "utf-8");
1022
+ return {
1023
+ text: () => text,
1024
+ data: () => JSON.parse(text)
1025
+ };
1026
+ }
1027
+ };
1028
+ function resolveJsonSource(source, as) {
1029
+ const [sourceType, sourceData] = Object.entries(source).find(([_, selected]) => selected !== void 0) ?? [];
1030
+ if (!sourceType || !(sourceType in jsonSourceResolvers) || !sourceData) {
1031
+ throw new Error("Invalid source data");
1032
+ }
1033
+ const sourceTypeResolvers = jsonSourceResolvers[sourceType](
1034
+ sourceData
1035
+ );
1036
+ const resolved = morph(sourceTypeResolvers, (key, v) => {
1037
+ try {
1038
+ const value = v();
1039
+ return !as || key === as ? [key, value] : [];
1040
+ } catch (e) {
1041
+ throw new Error(`Failed to resolve ${key} from ${sourceType}`);
1042
+ }
945
1043
  });
946
- if (!output.stdout) {
947
- console.warn(`Directory "${output.cwd}" is not in a git repository`);
948
- return void 0;
1044
+ if (as) {
1045
+ return resolved[as];
949
1046
  }
950
- return path$1.normalize(output.stdout);
1047
+ return resolved;
951
1048
  }
952
1049
 
953
- function modifyJSONCFileSync({
954
- edits,
955
- filepath,
956
- autoCommit = true
957
- }) {
958
- const jsoncContent = readFileSync(filepath, "utf-8");
959
- const modifiers = Array.isArray(edits) ? edits : [edits];
960
- const editResult = modifiers.flatMap(
961
- (edit) => modify(jsoncContent, edit.paths, edit.update, {
962
- formattingOptions: { tabSize: 0, insertSpaces: false }
1050
+ function resolveEditPath(path, options) {
1051
+ const { pathSeparator = "." } = {};
1052
+ const arr = toArray(path);
1053
+ return arr.map((path2) => {
1054
+ if (typeof path2 === "string") {
1055
+ return pathSeparator === false ? path2 : path2.split(pathSeparator);
1056
+ }
1057
+ return path2;
1058
+ }).flat();
1059
+ }
1060
+ function parseJSONCEdits(edits) {
1061
+ if (Array.isArray(edits)) {
1062
+ return edits.map(({ path, ...edit }) => ({
1063
+ path: resolveEditPath(path),
1064
+ ...edit
1065
+ }));
1066
+ }
1067
+ return Object.entries(edits).map(
1068
+ ([path, value]) => ({
1069
+ path: resolveEditPath(path),
1070
+ ...value
963
1071
  })
964
1072
  );
965
- const updatedFileContent = applyEdits(jsoncContent, editResult);
966
- const commit = () => writeFileSync(filepath, updatedFileContent);
967
- if (autoCommit) {
968
- commit();
969
- }
970
- return {
971
- updatedFileContent,
972
- commit
1073
+ }
1074
+ function modifyJSON({
1075
+ json,
1076
+ edits,
1077
+ defaultEditOptions
1078
+ }) {
1079
+ return checkResult(() => {
1080
+ const text = resolveJsonSource(json, "text");
1081
+ const jsoncEdits = parseJSONCEdits(edits);
1082
+ const editResult = jsoncEdits.flatMap(
1083
+ (edit) => modify(text, edit.path, edit.value, {
1084
+ ...defaultEditOptions,
1085
+ ...edit.options
1086
+ })
1087
+ );
1088
+ const updated = applyEdits(text, editResult);
1089
+ return resolveJsonSource({ text: updated });
1090
+ });
1091
+ }
1092
+ function modifyJSONFile(filepath, edits, options) {
1093
+ return checkResult(() => {
1094
+ const { autoCommit = true, defaultEditOptions } = options || {};
1095
+ const { data: json, error } = modifyJSON({
1096
+ json: { filepath },
1097
+ edits,
1098
+ defaultEditOptions
1099
+ });
1100
+ if (error) {
1101
+ throw error;
1102
+ }
1103
+ const commit = () => writeFileSync(filepath, json.text);
1104
+ if (autoCommit) {
1105
+ commit();
1106
+ return json;
1107
+ }
1108
+ return {
1109
+ json,
1110
+ commit
1111
+ };
1112
+ });
1113
+ }
1114
+
1115
+ function isStorageValue(input) {
1116
+ return input === null || typeof input === "string" || typeof input === "number" || typeof input === "boolean" || typeof input === "object";
1117
+ }
1118
+
1119
+ const storage = createStorage({ driver: defineMemoryDriver() });
1120
+ const tempFileSystem = defineFileSystemStorage({
1121
+ base: join(os.tmpdir(), ".package-manager")
1122
+ });
1123
+ function defineFileSystemEntries(definition) {
1124
+ const fileSystemEntries = Object.entries(definition).map(([k, v]) => {
1125
+ if (v instanceof Function) {
1126
+ const {
1127
+ file,
1128
+ options,
1129
+ serialize = (input) => JSON.stringify(input),
1130
+ deserialize = (input) => {
1131
+ try {
1132
+ return JSON.parse(input);
1133
+ } catch {
1134
+ return input;
1135
+ }
1136
+ }
1137
+ } = v();
1138
+ return {
1139
+ key: k,
1140
+ value: serialize(file),
1141
+ options,
1142
+ serialize,
1143
+ deserialize
1144
+ };
1145
+ }
1146
+ if (isStorageValue(v)) {
1147
+ return {
1148
+ key: k,
1149
+ value: JSON.stringify(v)
1150
+ };
1151
+ }
1152
+ return void 0;
1153
+ }).filter((v) => v !== void 0);
1154
+ const resolved = {
1155
+ definition,
1156
+ fileSystemEntries
973
1157
  };
1158
+ return resolved;
974
1159
  }
975
- const jsonc = (filepath) => {
976
- return {
977
- modify: (edits, options) => modifyJSONCFileSync({ edits, filepath, ...options })
1160
+ function defineFileSystemStorage(options) {
1161
+ const { base: root, initial, ...storageOptions } = options;
1162
+ let initialFileEntriesData = defineFileSystemEntries(initial ?? {});
1163
+ const storage2 = createStorage({
1164
+ driver: defineFsLiteDriver({ base: root, ...storageOptions })
1165
+ });
1166
+ const fileStorage = {
1167
+ createFile: async (key, data) => {
1168
+ await storage2.setItem(key, data);
1169
+ return {
1170
+ key,
1171
+ filepath: join(root, key),
1172
+ get: async () => storage2.getItem(key),
1173
+ update: async (data2) => storage2.setItem(key, data2)
1174
+ };
1175
+ },
1176
+ async getFilePath(key) {
1177
+ return (await this.getFile(key)).filepath;
1178
+ },
1179
+ getFile: async (key) => {
1180
+ const storageData = await storage2.getItem(key);
1181
+ return {
1182
+ key,
1183
+ filepath: join(root, key),
1184
+ data: storageData,
1185
+ read: async () => (await storage2.getItemRaw(key))?.toString()
1186
+ };
1187
+ },
1188
+ async readFile(key) {
1189
+ const { read } = await this.getFile(key);
1190
+ const content = await read();
1191
+ return content;
1192
+ },
1193
+ snapshotFs: async (base = root) => {
1194
+ return snapshot(storage2, base);
1195
+ },
1196
+ restoreFs: async (snapshot2) => {
1197
+ return restoreSnapshot(storage2, snapshot2);
1198
+ },
1199
+ initializeFs: async (override) => {
1200
+ if (override) {
1201
+ initialFileEntriesData = defineFileSystemEntries(override);
1202
+ }
1203
+ await storage2.clear();
1204
+ return storage2.setItems(initialFileEntriesData.fileSystemEntries);
1205
+ },
1206
+ defineFileSystemEntries,
1207
+ removeAllFiles: storage2.clear,
1208
+ async deleteFileSystem() {
1209
+ await this.removeAllFiles();
1210
+ await storage2.unmount(root, true);
1211
+ await rm(root, { recursive: true, force: true });
1212
+ },
1213
+ storage: storage2,
1214
+ meta: {
1215
+ fileEntriesData: initialFileEntriesData
1216
+ }
978
1217
  };
979
- };
1218
+ if (initial) {
1219
+ return {
1220
+ initialize: async () => {
1221
+ await fileStorage.initializeFs(initial);
1222
+ return fileStorage;
1223
+ }
1224
+ };
1225
+ }
1226
+ return fileStorage;
1227
+ }
980
1228
 
981
- export { _dirname, _filename, definePackage, definePackageManagerClient, definePathAliases, detectGlobalPackageManagers, detectLockfilePackageManagers, detectPackageManagers, filterPackageManagers, findDependencyInPackageJson, findPackageManager, findPackageManagerSafely, findResolvedModulePath, getAliasMap, getFolderByPackageName, getGitRootFolder, getPackageFolder, getPath, getWorkspaceFolder, importMap, importer, isDependencyInPackageJson, isPackageDependency, isPackageModuleFound, jsonc, packageManagerConfigs, predefinedPathAliases, project, resolveModule, resolveModulePath, resolvePackageModulePath, workspace };
1229
+ export { _dirname, _filename, defineFileSystemEntries, defineFileSystemStorage, definePackage, definePackageManagerClient, definePathAliases, detectGlobalPackageManagers, detectLockfilePackageManagers, detectPackageManagers, filterPackageManagers, findDependencyInPackageJson, findPackageManager, findPackageManagerSafely, findResolvedModulePath, getAliasMap, getFolderByPackageName, getGitRootFolder, getGlobalVersions, getPackageFolder, getPath, getWorkspaceFolder, importMap, importer, isDependencyInPackageJson, isPackageDependency, isPackageModuleFound, mapPackageManagers, modifyJSON, modifyJSONFile, packageManagerConfigs, predefinedPathAliases, project, resolveModule, resolveModulePath, resolvePackageModulePath, storage, tempFileSystem, workspace };