package-management 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +314 -0
- package/dist/index.d.cts +227 -0
- package/dist/index.d.mts +227 -0
- package/dist/index.d.ts +227 -0
- package/dist/index.mjs +301 -0
- package/package.json +40 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const installPkg = require('@antfu/install-pkg');
|
|
4
|
+
require('node:fs');
|
|
5
|
+
const execa = require('execa');
|
|
6
|
+
const localPkg = require('local-pkg');
|
|
7
|
+
const asyncCacheFn = require('async-cache-fn');
|
|
8
|
+
const findUp = require('find-up');
|
|
9
|
+
const promises = require('node:fs/promises');
|
|
10
|
+
|
|
11
|
+
async function resolveModule(m) {
|
|
12
|
+
const resolved = await m;
|
|
13
|
+
return resolved.default || resolved;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function importer(imports, options) {
|
|
17
|
+
const { install = true } = options ?? {};
|
|
18
|
+
return Promise.all(
|
|
19
|
+
imports.map(async (option) => {
|
|
20
|
+
if (install && "name" in option) {
|
|
21
|
+
await ensurePackage(option.name);
|
|
22
|
+
}
|
|
23
|
+
const importStatement = getImportStatement(option);
|
|
24
|
+
return resolveModule(importStatement);
|
|
25
|
+
})
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
function getImportStatement(option) {
|
|
29
|
+
if (typeof option === "function") {
|
|
30
|
+
return option();
|
|
31
|
+
}
|
|
32
|
+
if (typeof option === "object" && "import" in option && "name" in option) {
|
|
33
|
+
return option.import();
|
|
34
|
+
}
|
|
35
|
+
return option;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function importMap(importMap2, options) {
|
|
39
|
+
const keys = Object.keys(importMap2);
|
|
40
|
+
const imported = await importer(
|
|
41
|
+
keys.map((key) => importMap2[key]),
|
|
42
|
+
options
|
|
43
|
+
);
|
|
44
|
+
return Object.fromEntries(
|
|
45
|
+
keys.map((key, index) => [key, imported[index]])
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const toArray = (data) => Array.isArray(data) ? data : [data];
|
|
50
|
+
const entriesOf = (o) => Object.entries(o);
|
|
51
|
+
const fromEntries = (entries) => Object.fromEntries(entries);
|
|
52
|
+
const notFalsy = (value) => [false, null, void 0].every((v) => v !== value);
|
|
53
|
+
const select = (obj, selection, mode) => {
|
|
54
|
+
if (!selection)
|
|
55
|
+
return obj;
|
|
56
|
+
const filtered = entriesOf(obj).filter(([key]) => {
|
|
57
|
+
return mode === "omit" ? !selection[key] : selection[key];
|
|
58
|
+
});
|
|
59
|
+
return fromEntries(filtered);
|
|
60
|
+
};
|
|
61
|
+
const invariant = (predicate, message) => {
|
|
62
|
+
if (!predicate) {
|
|
63
|
+
throw new Error(message);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
function isPackageDependency(packageName) {
|
|
68
|
+
return toArray(packageName).every((name) => localPkg.isPackageExists(name));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function ensurePackage(name, options) {
|
|
72
|
+
if (isPackageDependency(name))
|
|
73
|
+
return;
|
|
74
|
+
await installPkg.installPackage(name, options);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function definePackageManager(config) {
|
|
78
|
+
const { command, args: agentArgs, options: agentOptions } = config;
|
|
79
|
+
const findLockfilePath = asyncCacheFn.asyncCacheFn(async (options) => {
|
|
80
|
+
const { cwd } = options ?? {};
|
|
81
|
+
const lockfiles = toArray(config.meta.lockfile);
|
|
82
|
+
return await findUp.findUp(lockfiles, { cwd });
|
|
83
|
+
});
|
|
84
|
+
return {
|
|
85
|
+
id: config.id,
|
|
86
|
+
config,
|
|
87
|
+
findLockfilePath,
|
|
88
|
+
hasLockfile: asyncCacheFn.asyncCacheFn(async (...args) => {
|
|
89
|
+
const lockfilePath = await findLockfilePath.noCache(...args);
|
|
90
|
+
return Boolean(lockfilePath);
|
|
91
|
+
}),
|
|
92
|
+
readLockfile: asyncCacheFn.asyncCacheFn(async (...args) => {
|
|
93
|
+
const lockfilePath = await findLockfilePath.noCache(...args);
|
|
94
|
+
if (!lockfilePath)
|
|
95
|
+
return void 0;
|
|
96
|
+
return promises.readFile(lockfilePath, "utf8");
|
|
97
|
+
}),
|
|
98
|
+
globalVersion: asyncCacheFn.asyncCacheFn(async (...args) => {
|
|
99
|
+
const [options] = args;
|
|
100
|
+
try {
|
|
101
|
+
const { stdout } = await $$({
|
|
102
|
+
command,
|
|
103
|
+
args: [agentOptions.version],
|
|
104
|
+
...options
|
|
105
|
+
});
|
|
106
|
+
return `${stdout}`;
|
|
107
|
+
} catch (e) {
|
|
108
|
+
return void 0;
|
|
109
|
+
}
|
|
110
|
+
}),
|
|
111
|
+
installPackage: async (packageName, options) => {
|
|
112
|
+
const install = agentArgs.install;
|
|
113
|
+
const { isDevDependency, preferOffline } = select(
|
|
114
|
+
install.options,
|
|
115
|
+
options ?? {},
|
|
116
|
+
"pick"
|
|
117
|
+
);
|
|
118
|
+
const packageNames = toArray(packageName);
|
|
119
|
+
try {
|
|
120
|
+
await $$({
|
|
121
|
+
command,
|
|
122
|
+
args: [
|
|
123
|
+
install.command,
|
|
124
|
+
isDevDependency,
|
|
125
|
+
preferOffline,
|
|
126
|
+
...packageNames
|
|
127
|
+
],
|
|
128
|
+
...options
|
|
129
|
+
});
|
|
130
|
+
} catch (e) {
|
|
131
|
+
throw new Error(`Failed to install: ${packageNames.join(", ")}`);
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
uninstallPackage: async (packageName, options) => {
|
|
135
|
+
const uninstall = agentArgs.uninstall;
|
|
136
|
+
if (!isPackageDependency(packageName))
|
|
137
|
+
return;
|
|
138
|
+
await $$({
|
|
139
|
+
command,
|
|
140
|
+
args: [uninstall.command, ...toArray(packageName)],
|
|
141
|
+
...options
|
|
142
|
+
}).catch((e) => {
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
async function $$(options) {
|
|
148
|
+
const { command, args = [], silent = true, cwd, shellOptions } = options;
|
|
149
|
+
return execa.execa(command, args.filter(notFalsy), {
|
|
150
|
+
cwd,
|
|
151
|
+
...shellOptions,
|
|
152
|
+
stdio: silent ? "ignore" : "inherit"
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const bun = definePackageManager({
|
|
157
|
+
id: "bun",
|
|
158
|
+
name: "Bun",
|
|
159
|
+
command: "bun",
|
|
160
|
+
runner: "bunx",
|
|
161
|
+
meta: {
|
|
162
|
+
lockfile: "bun.lockb"
|
|
163
|
+
},
|
|
164
|
+
args: {
|
|
165
|
+
install: {
|
|
166
|
+
command: "install",
|
|
167
|
+
options: {
|
|
168
|
+
isDevDependency: "-D",
|
|
169
|
+
preferOffline: "--prefer-offline"
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
uninstall: {
|
|
173
|
+
command: "uninstall"
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
options: {
|
|
177
|
+
version: "--version"
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const npm = definePackageManager({
|
|
182
|
+
id: "npm",
|
|
183
|
+
name: "NPM",
|
|
184
|
+
command: "npm",
|
|
185
|
+
runner: "npx",
|
|
186
|
+
meta: {
|
|
187
|
+
lockfile: ["package-lock.json", "npm-shrinkwrap.json"]
|
|
188
|
+
},
|
|
189
|
+
args: {
|
|
190
|
+
install: {
|
|
191
|
+
command: "install",
|
|
192
|
+
options: {
|
|
193
|
+
isDevDependency: "-D",
|
|
194
|
+
preferOffline: "--prefer-offline"
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
uninstall: {
|
|
198
|
+
command: "uninstall"
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
options: {
|
|
202
|
+
version: "--version"
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
const pnpm = definePackageManager({
|
|
207
|
+
id: "pnpm",
|
|
208
|
+
name: "PNPM",
|
|
209
|
+
command: "pnpm",
|
|
210
|
+
runner: "pnpx",
|
|
211
|
+
meta: {
|
|
212
|
+
lockfile: "pnpm-lock.yaml"
|
|
213
|
+
},
|
|
214
|
+
args: {
|
|
215
|
+
install: {
|
|
216
|
+
command: "install",
|
|
217
|
+
options: {
|
|
218
|
+
isDevDependency: "-D",
|
|
219
|
+
preferOffline: "--prefer-offline"
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
uninstall: {
|
|
223
|
+
command: "uninstall"
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
options: {
|
|
227
|
+
version: "--version"
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
const yarn = definePackageManager({
|
|
232
|
+
id: "yarn",
|
|
233
|
+
name: "Yarn",
|
|
234
|
+
command: "yarn",
|
|
235
|
+
runner: "yarn dlx",
|
|
236
|
+
meta: {
|
|
237
|
+
lockfile: "yarn.lock"
|
|
238
|
+
},
|
|
239
|
+
args: {
|
|
240
|
+
install: {
|
|
241
|
+
command: "add",
|
|
242
|
+
options: {
|
|
243
|
+
isDevDependency: "-D",
|
|
244
|
+
preferOffline: "--prefer-offline"
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
uninstall: {
|
|
248
|
+
command: "remove"
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
options: {
|
|
252
|
+
version: "--version"
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
const packageManagers = fromEntries(
|
|
257
|
+
[pnpm, yarn, bun, npm].map((e) => [e.id, e])
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
async function findPackageManager(options) {
|
|
261
|
+
const { ...rest } = options ?? {};
|
|
262
|
+
const packageManager = await findPackageManagerSafely(rest);
|
|
263
|
+
invariant(packageManager, "No package manager found");
|
|
264
|
+
return packageManager;
|
|
265
|
+
}
|
|
266
|
+
async function findPackageManagerSafely(options) {
|
|
267
|
+
const lockfilePm = (await detectLockfilePackageManagers(options))[0];
|
|
268
|
+
if (lockfilePm) {
|
|
269
|
+
return lockfilePm;
|
|
270
|
+
}
|
|
271
|
+
const globalPm = (await detectGlobalPackageManagers(options))[0];
|
|
272
|
+
return globalPm;
|
|
273
|
+
}
|
|
274
|
+
async function detectPackageManagers(options) {
|
|
275
|
+
return [
|
|
276
|
+
...await detectLockfilePackageManagers(options),
|
|
277
|
+
...await detectGlobalPackageManagers(options)
|
|
278
|
+
];
|
|
279
|
+
}
|
|
280
|
+
async function detectLockfilePackageManagers(options) {
|
|
281
|
+
({ cwd: options?.cwd });
|
|
282
|
+
return filterPackageManagers((e) => e.hasLockfile(options), options);
|
|
283
|
+
}
|
|
284
|
+
async function detectGlobalPackageManagers(options) {
|
|
285
|
+
return filterPackageManagers(async (e) => e.globalVersion(options), options);
|
|
286
|
+
}
|
|
287
|
+
async function filterPackageManagers(filterFn, options) {
|
|
288
|
+
const allowedPackageManagers = Object.entries(packageManagers).filter(
|
|
289
|
+
([key]) => {
|
|
290
|
+
if (!options?.allowed)
|
|
291
|
+
return true;
|
|
292
|
+
return key in options.allowed;
|
|
293
|
+
}
|
|
294
|
+
);
|
|
295
|
+
return (await Promise.all(
|
|
296
|
+
allowedPackageManagers.map(async ([key, pm]) => {
|
|
297
|
+
const valid = await filterFn(pm);
|
|
298
|
+
return valid ? pm : void 0;
|
|
299
|
+
})
|
|
300
|
+
)).filter(notFalsy);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
exports.detectGlobalPackageManagers = detectGlobalPackageManagers;
|
|
304
|
+
exports.detectLockfilePackageManagers = detectLockfilePackageManagers;
|
|
305
|
+
exports.detectPackageManagers = detectPackageManagers;
|
|
306
|
+
exports.ensurePackage = ensurePackage;
|
|
307
|
+
exports.filterPackageManagers = filterPackageManagers;
|
|
308
|
+
exports.findPackageManager = findPackageManager;
|
|
309
|
+
exports.findPackageManagerSafely = findPackageManagerSafely;
|
|
310
|
+
exports.importMap = importMap;
|
|
311
|
+
exports.importer = importer;
|
|
312
|
+
exports.isPackageDependency = isPackageDependency;
|
|
313
|
+
exports.packageManagers = packageManagers;
|
|
314
|
+
exports.resolveModule = resolveModule;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { InstallPackageOptions } from '@antfu/install-pkg';
|
|
2
|
+
import { AsyncCacheFn as AsyncCacheFn$1 } from 'async-cache-fn';
|
|
3
|
+
import { Options } from 'execa';
|
|
4
|
+
|
|
5
|
+
interface ImportPackageOption<T = any> {
|
|
6
|
+
/**
|
|
7
|
+
* The name of the package to import. This should match the name used in the import statement.
|
|
8
|
+
*/
|
|
9
|
+
name: string;
|
|
10
|
+
/**
|
|
11
|
+
* When enabled, the package will be installed if it is not found
|
|
12
|
+
* @default true
|
|
13
|
+
*/
|
|
14
|
+
install?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* The import statement for the package.
|
|
17
|
+
*/
|
|
18
|
+
import: () => ImportStatement<T>;
|
|
19
|
+
/**
|
|
20
|
+
* When enabled, the package will be installed as a dev dependency
|
|
21
|
+
*/
|
|
22
|
+
isDevDependency?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Additional installation options
|
|
25
|
+
*/
|
|
26
|
+
installOptions?: Omit<InstallPackageOptions, "dev">;
|
|
27
|
+
}
|
|
28
|
+
type ImportMap = Record<string, ImportOption>;
|
|
29
|
+
type ImportList = ImportOption[];
|
|
30
|
+
type ImportOption<T = any> = ImportStatement<T> | (() => ImportStatement<T>) | ImportPackageOption<T>;
|
|
31
|
+
type ImportStatement<T = any> = Promise<T>;
|
|
32
|
+
type ResolvedImportOption<T extends ImportOption> = ResolvedPromise<ExtractImportStatement<T>>;
|
|
33
|
+
type ResolvedImportMap<$Imports extends ImportMap> = {
|
|
34
|
+
[P in keyof $Imports]: ResolvedImportOption<$Imports[P]>;
|
|
35
|
+
};
|
|
36
|
+
type ResolvedImportMapPromise<T extends ImportMap> = Promise<ResolvedImportMap<T>>;
|
|
37
|
+
type ResolvedImportList<$Imports extends ImportList> = {
|
|
38
|
+
[P in keyof $Imports]: ResolvedImportOption<$Imports[P]>;
|
|
39
|
+
};
|
|
40
|
+
type ResolvedImportListPromise<T extends ImportList> = Promise<ResolvedImportList<T>>;
|
|
41
|
+
type ExtractImportStatement<T extends ImportOption> = ExtractImport<T> extends () => infer I ? I : T;
|
|
42
|
+
type ExtractImport<T extends ImportOption> = T extends {
|
|
43
|
+
import: infer I;
|
|
44
|
+
} ? I : T;
|
|
45
|
+
|
|
46
|
+
type __<T> = {
|
|
47
|
+
[K in keyof T]: T[K];
|
|
48
|
+
} & {};
|
|
49
|
+
type Awaitable<T> = T | Promise<T>;
|
|
50
|
+
type ResolvedPromise<T> = T extends Promise<infer U> ? U : never;
|
|
51
|
+
type KeyOf<T, K> = K extends keyof T ? K : never;
|
|
52
|
+
type KeyOfValue<T, K> = T[KeyOf<T, K>];
|
|
53
|
+
type SelectionMap<T> = __<{
|
|
54
|
+
[K in keyof T]?: boolean;
|
|
55
|
+
}>;
|
|
56
|
+
type PickByValue<T, V> = {
|
|
57
|
+
[K in keyof T as T[K] extends V ? K : never]: T[K];
|
|
58
|
+
};
|
|
59
|
+
type Entry<key extends PropertyKey = PropertyKey, value = unknown> = readonly [key: key, value: value];
|
|
60
|
+
type EntryOf<O> = {
|
|
61
|
+
[k in keyof O]-?: [k, O[k] & ({} | null)];
|
|
62
|
+
}[O extends readonly unknown[] ? keyof O & number : keyof O] & unknown;
|
|
63
|
+
type FromEntries<entries extends readonly Entry[]> = {
|
|
64
|
+
[entry in entries[number] as entry[0]]: entry[1];
|
|
65
|
+
};
|
|
66
|
+
type UnionizedSelectionMap<T, TSelection extends SelectionMap<T>, V> = __<V & {
|
|
67
|
+
[K in keyof T as IsExactBoolean<TSelection[K]> extends true ? K : never]?: T[K];
|
|
68
|
+
}>;
|
|
69
|
+
type Select<T, TSelection extends SelectionMap<T>, TMode extends "pick" | "omit"> = __<UnionizedSelectionMap<T, TSelection, TMode extends "pick" ? Pick<T, KeyOf<T, keyof PickByValue<TSelection, true>>> : Omit<T, KeyOf<T, keyof PickByValue<TSelection, true>>>>>;
|
|
70
|
+
type IsExactBoolean<T> = true extends T ? false extends T ? true : false : false;
|
|
71
|
+
type IsUnion<T, U = T> = T extends U ? [U] extends [T] ? false : true : never;
|
|
72
|
+
type MergeObject<T extends object, O extends object | unknown = unknown> = __<T & (O extends object ? O : Record<never, never>)>;
|
|
73
|
+
type AsyncCacheFn<TReturn = unknown, TOption extends object | undefined = undefined, C extends "required" | "optional" = "optional"> = AsyncCacheFn$1<TReturn, C extends "optional" ? [TOption | undefined] | [] : [TOption]>;
|
|
74
|
+
|
|
75
|
+
interface ImporterOptions {
|
|
76
|
+
/**
|
|
77
|
+
* When enabled, the default behavior is to install packages that are not found.
|
|
78
|
+
* The name of the package is inferred from the key of the import map.
|
|
79
|
+
* @default true
|
|
80
|
+
*/
|
|
81
|
+
install?: boolean;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Dynamically imports modules and returns their exports in a tuple.
|
|
85
|
+
* This function ensures type safety and maintains the order of imports.
|
|
86
|
+
*
|
|
87
|
+
* @param imports An array of dynamic import promises.
|
|
88
|
+
* @returns A promise that resolves to a tuple containing the default exports of the imported modules.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```typescript
|
|
92
|
+
* // Usage example with dynamic imports
|
|
93
|
+
* const [package1, package2] = await importer([
|
|
94
|
+
* import('@antfu/eslint-config'),
|
|
95
|
+
* import('@antfu/install-pkg')
|
|
96
|
+
* ]);
|
|
97
|
+
*
|
|
98
|
+
* // package1 and package2 will be the default exports of the respective modules
|
|
99
|
+
* ```
|
|
100
|
+
*
|
|
101
|
+
* @typeparam Imports An array type representing the dynamic imports.
|
|
102
|
+
*/
|
|
103
|
+
declare function importer<T extends ImportList>(imports: [...T], options?: ImporterOptions): Promise<ResolvedImportList<T>>;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Asynchronously imports modules from a record of dynamic import promises.
|
|
107
|
+
* Returns a promise that resolves to a record with the same keys, each mapped to the resolved import.
|
|
108
|
+
* This function maintains the key-value mapping and ensures type safety.
|
|
109
|
+
*
|
|
110
|
+
* @param importMap A record where each key is associated with a dynamic import promise.
|
|
111
|
+
* @returns A promise that resolves to a record containing the default exports of the imported modules,
|
|
112
|
+
* maintaining the original key structure.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* // Usage example with a record of dynamic imports
|
|
117
|
+
*
|
|
118
|
+
* const { package1, package2 } = await importMap({
|
|
119
|
+
* package1: import('package-1'),
|
|
120
|
+
* package2: import('package-2')
|
|
121
|
+
* });
|
|
122
|
+
*
|
|
123
|
+
* // importedModules.config and importedModules.pkg will be the default exports of the respective modules
|
|
124
|
+
* ```
|
|
125
|
+
*
|
|
126
|
+
*/
|
|
127
|
+
declare function importMap<T extends ImportMap>(importMap: T, options?: ImporterOptions): Promise<ResolvedImportMap<T>>;
|
|
128
|
+
|
|
129
|
+
declare function ensurePackage(name: string | string[], options?: InstallPackageOptions): Promise<void>;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Asynchronously handles the resolution of a module, extracting its default export if available.
|
|
133
|
+
* If the module does not have a default export, it returns the module itself.
|
|
134
|
+
*
|
|
135
|
+
* @param m A promise representing a module import (either ES Module or CommonJS).
|
|
136
|
+
* @returns A promise that resolves to either the default export of the module or the module itself.
|
|
137
|
+
*
|
|
138
|
+
* @typeparam T The type of the module being imported.
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```typescript
|
|
142
|
+
* // Usage example with dynamic import
|
|
143
|
+
* const module = await interopDefault(import('some-module'));
|
|
144
|
+
*
|
|
145
|
+
* // 'module' will be either the default export of 'some-module' or the module itself if no default export exists
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
declare function resolveModule<T>(m: Awaitable<T>): Promise<T extends {
|
|
149
|
+
default: infer U;
|
|
150
|
+
} ? U : T>;
|
|
151
|
+
|
|
152
|
+
declare function isPackageDependency(packageName: string | string[]): boolean;
|
|
153
|
+
|
|
154
|
+
interface PackageManagerConfig<ID extends string = string> {
|
|
155
|
+
id: ID;
|
|
156
|
+
command: string;
|
|
157
|
+
name: string;
|
|
158
|
+
meta: {
|
|
159
|
+
lockfile: string | string[];
|
|
160
|
+
};
|
|
161
|
+
runner: string;
|
|
162
|
+
args: {
|
|
163
|
+
install: {
|
|
164
|
+
command: string;
|
|
165
|
+
options: {
|
|
166
|
+
preferOffline: string;
|
|
167
|
+
isDevDependency: string;
|
|
168
|
+
};
|
|
169
|
+
};
|
|
170
|
+
uninstall: {
|
|
171
|
+
command: string;
|
|
172
|
+
};
|
|
173
|
+
};
|
|
174
|
+
options: {
|
|
175
|
+
version: string;
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
type PackageManagerCommands = PackageManagerConfig["args"];
|
|
179
|
+
type PackageManagerCommandName = keyof PackageManagerCommands;
|
|
180
|
+
type PackageManagerCommandSpec<K> = KeyOfValue<PackageManagerCommands, K> extends {
|
|
181
|
+
options: infer O;
|
|
182
|
+
} ? SelectionMap<O> : Record<never, never>;
|
|
183
|
+
|
|
184
|
+
type ScriptOptions<K extends PackageManagerCommandName | undefined = undefined> = __<{
|
|
185
|
+
cwd?: string;
|
|
186
|
+
silent?: boolean;
|
|
187
|
+
shellOptions?: Options;
|
|
188
|
+
} & PackageManagerCommandSpec<K>>;
|
|
189
|
+
interface PackageManager<ID extends string = PackageManagerId> {
|
|
190
|
+
id: ID;
|
|
191
|
+
config: PackageManagerConfig;
|
|
192
|
+
findLockfilePath: AsyncCacheFn<string | undefined, {
|
|
193
|
+
cwd?: string;
|
|
194
|
+
}>;
|
|
195
|
+
hasLockfile: AsyncCacheFn<boolean, {
|
|
196
|
+
cwd?: string;
|
|
197
|
+
}>;
|
|
198
|
+
readLockfile: AsyncCacheFn<string | undefined, {
|
|
199
|
+
cwd?: string;
|
|
200
|
+
}>;
|
|
201
|
+
globalVersion: AsyncCacheFn<string | undefined, ScriptOptions>;
|
|
202
|
+
uninstallPackage: (packageNames: string | string[], options?: ScriptOptions<"uninstall">) => Promise<void>;
|
|
203
|
+
installPackage: (packageNames: string | string[], options?: ScriptOptions<"install">) => Promise<void>;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
type PackageManagerId = keyof typeof packageManagers;
|
|
207
|
+
declare const packageManagers: {
|
|
208
|
+
pnpm: PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">;
|
|
209
|
+
yarn: PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">;
|
|
210
|
+
bun: PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">;
|
|
211
|
+
npm: PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">;
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
interface DetectPackageManagerOptions {
|
|
215
|
+
allowed?: SelectionMap<typeof packageManagers>;
|
|
216
|
+
cwd?: string;
|
|
217
|
+
}
|
|
218
|
+
declare function findPackageManager(options?: DetectPackageManagerOptions): Promise<PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">>;
|
|
219
|
+
declare function findPackageManagerSafely<TAssert extends boolean = true>(options?: DetectPackageManagerOptions & {
|
|
220
|
+
assert?: TAssert;
|
|
221
|
+
}): Promise<PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm"> | undefined>;
|
|
222
|
+
declare function detectPackageManagers(options?: DetectPackageManagerOptions): Promise<(PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">)[]>;
|
|
223
|
+
declare function detectLockfilePackageManagers(options?: DetectPackageManagerOptions): Promise<(PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">)[]>;
|
|
224
|
+
declare function detectGlobalPackageManagers(options?: DetectPackageManagerOptions): Promise<(PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">)[]>;
|
|
225
|
+
declare function filterPackageManagers(filterFn: (packageManager: PackageManager) => Promise<unknown>, options?: DetectPackageManagerOptions): Promise<(PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">)[]>;
|
|
226
|
+
|
|
227
|
+
export { type AsyncCacheFn, type Awaitable, type Entry, type EntryOf, type FromEntries, type ImportList, type ImportMap, type ImportOption, type ImportPackageOption, type ImportStatement, type ImporterOptions, type IsExactBoolean, type IsUnion, type KeyOf, type KeyOfValue, type MergeObject, type PackageManagerCommandName, type PackageManagerCommandSpec, type PackageManagerCommands, type PackageManagerConfig, type PackageManagerId, type PickByValue, type ResolvedImportList, type ResolvedImportListPromise, type ResolvedImportMap, type ResolvedImportMapPromise, type ResolvedImportOption, type ResolvedPromise, type Select, type SelectionMap, type __, detectGlobalPackageManagers, detectLockfilePackageManagers, detectPackageManagers, ensurePackage, filterPackageManagers, findPackageManager, findPackageManagerSafely, importMap, importer, isPackageDependency, packageManagers, resolveModule };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { InstallPackageOptions } from '@antfu/install-pkg';
|
|
2
|
+
import { AsyncCacheFn as AsyncCacheFn$1 } from 'async-cache-fn';
|
|
3
|
+
import { Options } from 'execa';
|
|
4
|
+
|
|
5
|
+
interface ImportPackageOption<T = any> {
|
|
6
|
+
/**
|
|
7
|
+
* The name of the package to import. This should match the name used in the import statement.
|
|
8
|
+
*/
|
|
9
|
+
name: string;
|
|
10
|
+
/**
|
|
11
|
+
* When enabled, the package will be installed if it is not found
|
|
12
|
+
* @default true
|
|
13
|
+
*/
|
|
14
|
+
install?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* The import statement for the package.
|
|
17
|
+
*/
|
|
18
|
+
import: () => ImportStatement<T>;
|
|
19
|
+
/**
|
|
20
|
+
* When enabled, the package will be installed as a dev dependency
|
|
21
|
+
*/
|
|
22
|
+
isDevDependency?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Additional installation options
|
|
25
|
+
*/
|
|
26
|
+
installOptions?: Omit<InstallPackageOptions, "dev">;
|
|
27
|
+
}
|
|
28
|
+
type ImportMap = Record<string, ImportOption>;
|
|
29
|
+
type ImportList = ImportOption[];
|
|
30
|
+
type ImportOption<T = any> = ImportStatement<T> | (() => ImportStatement<T>) | ImportPackageOption<T>;
|
|
31
|
+
type ImportStatement<T = any> = Promise<T>;
|
|
32
|
+
type ResolvedImportOption<T extends ImportOption> = ResolvedPromise<ExtractImportStatement<T>>;
|
|
33
|
+
type ResolvedImportMap<$Imports extends ImportMap> = {
|
|
34
|
+
[P in keyof $Imports]: ResolvedImportOption<$Imports[P]>;
|
|
35
|
+
};
|
|
36
|
+
type ResolvedImportMapPromise<T extends ImportMap> = Promise<ResolvedImportMap<T>>;
|
|
37
|
+
type ResolvedImportList<$Imports extends ImportList> = {
|
|
38
|
+
[P in keyof $Imports]: ResolvedImportOption<$Imports[P]>;
|
|
39
|
+
};
|
|
40
|
+
type ResolvedImportListPromise<T extends ImportList> = Promise<ResolvedImportList<T>>;
|
|
41
|
+
type ExtractImportStatement<T extends ImportOption> = ExtractImport<T> extends () => infer I ? I : T;
|
|
42
|
+
type ExtractImport<T extends ImportOption> = T extends {
|
|
43
|
+
import: infer I;
|
|
44
|
+
} ? I : T;
|
|
45
|
+
|
|
46
|
+
type __<T> = {
|
|
47
|
+
[K in keyof T]: T[K];
|
|
48
|
+
} & {};
|
|
49
|
+
type Awaitable<T> = T | Promise<T>;
|
|
50
|
+
type ResolvedPromise<T> = T extends Promise<infer U> ? U : never;
|
|
51
|
+
type KeyOf<T, K> = K extends keyof T ? K : never;
|
|
52
|
+
type KeyOfValue<T, K> = T[KeyOf<T, K>];
|
|
53
|
+
type SelectionMap<T> = __<{
|
|
54
|
+
[K in keyof T]?: boolean;
|
|
55
|
+
}>;
|
|
56
|
+
type PickByValue<T, V> = {
|
|
57
|
+
[K in keyof T as T[K] extends V ? K : never]: T[K];
|
|
58
|
+
};
|
|
59
|
+
type Entry<key extends PropertyKey = PropertyKey, value = unknown> = readonly [key: key, value: value];
|
|
60
|
+
type EntryOf<O> = {
|
|
61
|
+
[k in keyof O]-?: [k, O[k] & ({} | null)];
|
|
62
|
+
}[O extends readonly unknown[] ? keyof O & number : keyof O] & unknown;
|
|
63
|
+
type FromEntries<entries extends readonly Entry[]> = {
|
|
64
|
+
[entry in entries[number] as entry[0]]: entry[1];
|
|
65
|
+
};
|
|
66
|
+
type UnionizedSelectionMap<T, TSelection extends SelectionMap<T>, V> = __<V & {
|
|
67
|
+
[K in keyof T as IsExactBoolean<TSelection[K]> extends true ? K : never]?: T[K];
|
|
68
|
+
}>;
|
|
69
|
+
type Select<T, TSelection extends SelectionMap<T>, TMode extends "pick" | "omit"> = __<UnionizedSelectionMap<T, TSelection, TMode extends "pick" ? Pick<T, KeyOf<T, keyof PickByValue<TSelection, true>>> : Omit<T, KeyOf<T, keyof PickByValue<TSelection, true>>>>>;
|
|
70
|
+
type IsExactBoolean<T> = true extends T ? false extends T ? true : false : false;
|
|
71
|
+
type IsUnion<T, U = T> = T extends U ? [U] extends [T] ? false : true : never;
|
|
72
|
+
type MergeObject<T extends object, O extends object | unknown = unknown> = __<T & (O extends object ? O : Record<never, never>)>;
|
|
73
|
+
type AsyncCacheFn<TReturn = unknown, TOption extends object | undefined = undefined, C extends "required" | "optional" = "optional"> = AsyncCacheFn$1<TReturn, C extends "optional" ? [TOption | undefined] | [] : [TOption]>;
|
|
74
|
+
|
|
75
|
+
interface ImporterOptions {
|
|
76
|
+
/**
|
|
77
|
+
* When enabled, the default behavior is to install packages that are not found.
|
|
78
|
+
* The name of the package is inferred from the key of the import map.
|
|
79
|
+
* @default true
|
|
80
|
+
*/
|
|
81
|
+
install?: boolean;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Dynamically imports modules and returns their exports in a tuple.
|
|
85
|
+
* This function ensures type safety and maintains the order of imports.
|
|
86
|
+
*
|
|
87
|
+
* @param imports An array of dynamic import promises.
|
|
88
|
+
* @returns A promise that resolves to a tuple containing the default exports of the imported modules.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```typescript
|
|
92
|
+
* // Usage example with dynamic imports
|
|
93
|
+
* const [package1, package2] = await importer([
|
|
94
|
+
* import('@antfu/eslint-config'),
|
|
95
|
+
* import('@antfu/install-pkg')
|
|
96
|
+
* ]);
|
|
97
|
+
*
|
|
98
|
+
* // package1 and package2 will be the default exports of the respective modules
|
|
99
|
+
* ```
|
|
100
|
+
*
|
|
101
|
+
* @typeparam Imports An array type representing the dynamic imports.
|
|
102
|
+
*/
|
|
103
|
+
declare function importer<T extends ImportList>(imports: [...T], options?: ImporterOptions): Promise<ResolvedImportList<T>>;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Asynchronously imports modules from a record of dynamic import promises.
|
|
107
|
+
* Returns a promise that resolves to a record with the same keys, each mapped to the resolved import.
|
|
108
|
+
* This function maintains the key-value mapping and ensures type safety.
|
|
109
|
+
*
|
|
110
|
+
* @param importMap A record where each key is associated with a dynamic import promise.
|
|
111
|
+
* @returns A promise that resolves to a record containing the default exports of the imported modules,
|
|
112
|
+
* maintaining the original key structure.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* // Usage example with a record of dynamic imports
|
|
117
|
+
*
|
|
118
|
+
* const { package1, package2 } = await importMap({
|
|
119
|
+
* package1: import('package-1'),
|
|
120
|
+
* package2: import('package-2')
|
|
121
|
+
* });
|
|
122
|
+
*
|
|
123
|
+
* // importedModules.config and importedModules.pkg will be the default exports of the respective modules
|
|
124
|
+
* ```
|
|
125
|
+
*
|
|
126
|
+
*/
|
|
127
|
+
declare function importMap<T extends ImportMap>(importMap: T, options?: ImporterOptions): Promise<ResolvedImportMap<T>>;
|
|
128
|
+
|
|
129
|
+
declare function ensurePackage(name: string | string[], options?: InstallPackageOptions): Promise<void>;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Asynchronously handles the resolution of a module, extracting its default export if available.
|
|
133
|
+
* If the module does not have a default export, it returns the module itself.
|
|
134
|
+
*
|
|
135
|
+
* @param m A promise representing a module import (either ES Module or CommonJS).
|
|
136
|
+
* @returns A promise that resolves to either the default export of the module or the module itself.
|
|
137
|
+
*
|
|
138
|
+
* @typeparam T The type of the module being imported.
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```typescript
|
|
142
|
+
* // Usage example with dynamic import
|
|
143
|
+
* const module = await interopDefault(import('some-module'));
|
|
144
|
+
*
|
|
145
|
+
* // 'module' will be either the default export of 'some-module' or the module itself if no default export exists
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
declare function resolveModule<T>(m: Awaitable<T>): Promise<T extends {
|
|
149
|
+
default: infer U;
|
|
150
|
+
} ? U : T>;
|
|
151
|
+
|
|
152
|
+
declare function isPackageDependency(packageName: string | string[]): boolean;
|
|
153
|
+
|
|
154
|
+
interface PackageManagerConfig<ID extends string = string> {
|
|
155
|
+
id: ID;
|
|
156
|
+
command: string;
|
|
157
|
+
name: string;
|
|
158
|
+
meta: {
|
|
159
|
+
lockfile: string | string[];
|
|
160
|
+
};
|
|
161
|
+
runner: string;
|
|
162
|
+
args: {
|
|
163
|
+
install: {
|
|
164
|
+
command: string;
|
|
165
|
+
options: {
|
|
166
|
+
preferOffline: string;
|
|
167
|
+
isDevDependency: string;
|
|
168
|
+
};
|
|
169
|
+
};
|
|
170
|
+
uninstall: {
|
|
171
|
+
command: string;
|
|
172
|
+
};
|
|
173
|
+
};
|
|
174
|
+
options: {
|
|
175
|
+
version: string;
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
type PackageManagerCommands = PackageManagerConfig["args"];
|
|
179
|
+
type PackageManagerCommandName = keyof PackageManagerCommands;
|
|
180
|
+
type PackageManagerCommandSpec<K> = KeyOfValue<PackageManagerCommands, K> extends {
|
|
181
|
+
options: infer O;
|
|
182
|
+
} ? SelectionMap<O> : Record<never, never>;
|
|
183
|
+
|
|
184
|
+
type ScriptOptions<K extends PackageManagerCommandName | undefined = undefined> = __<{
|
|
185
|
+
cwd?: string;
|
|
186
|
+
silent?: boolean;
|
|
187
|
+
shellOptions?: Options;
|
|
188
|
+
} & PackageManagerCommandSpec<K>>;
|
|
189
|
+
interface PackageManager<ID extends string = PackageManagerId> {
|
|
190
|
+
id: ID;
|
|
191
|
+
config: PackageManagerConfig;
|
|
192
|
+
findLockfilePath: AsyncCacheFn<string | undefined, {
|
|
193
|
+
cwd?: string;
|
|
194
|
+
}>;
|
|
195
|
+
hasLockfile: AsyncCacheFn<boolean, {
|
|
196
|
+
cwd?: string;
|
|
197
|
+
}>;
|
|
198
|
+
readLockfile: AsyncCacheFn<string | undefined, {
|
|
199
|
+
cwd?: string;
|
|
200
|
+
}>;
|
|
201
|
+
globalVersion: AsyncCacheFn<string | undefined, ScriptOptions>;
|
|
202
|
+
uninstallPackage: (packageNames: string | string[], options?: ScriptOptions<"uninstall">) => Promise<void>;
|
|
203
|
+
installPackage: (packageNames: string | string[], options?: ScriptOptions<"install">) => Promise<void>;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
type PackageManagerId = keyof typeof packageManagers;
|
|
207
|
+
declare const packageManagers: {
|
|
208
|
+
pnpm: PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">;
|
|
209
|
+
yarn: PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">;
|
|
210
|
+
bun: PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">;
|
|
211
|
+
npm: PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">;
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
interface DetectPackageManagerOptions {
|
|
215
|
+
allowed?: SelectionMap<typeof packageManagers>;
|
|
216
|
+
cwd?: string;
|
|
217
|
+
}
|
|
218
|
+
declare function findPackageManager(options?: DetectPackageManagerOptions): Promise<PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">>;
|
|
219
|
+
declare function findPackageManagerSafely<TAssert extends boolean = true>(options?: DetectPackageManagerOptions & {
|
|
220
|
+
assert?: TAssert;
|
|
221
|
+
}): Promise<PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm"> | undefined>;
|
|
222
|
+
declare function detectPackageManagers(options?: DetectPackageManagerOptions): Promise<(PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">)[]>;
|
|
223
|
+
declare function detectLockfilePackageManagers(options?: DetectPackageManagerOptions): Promise<(PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">)[]>;
|
|
224
|
+
declare function detectGlobalPackageManagers(options?: DetectPackageManagerOptions): Promise<(PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">)[]>;
|
|
225
|
+
declare function filterPackageManagers(filterFn: (packageManager: PackageManager) => Promise<unknown>, options?: DetectPackageManagerOptions): Promise<(PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">)[]>;
|
|
226
|
+
|
|
227
|
+
export { type AsyncCacheFn, type Awaitable, type Entry, type EntryOf, type FromEntries, type ImportList, type ImportMap, type ImportOption, type ImportPackageOption, type ImportStatement, type ImporterOptions, type IsExactBoolean, type IsUnion, type KeyOf, type KeyOfValue, type MergeObject, type PackageManagerCommandName, type PackageManagerCommandSpec, type PackageManagerCommands, type PackageManagerConfig, type PackageManagerId, type PickByValue, type ResolvedImportList, type ResolvedImportListPromise, type ResolvedImportMap, type ResolvedImportMapPromise, type ResolvedImportOption, type ResolvedPromise, type Select, type SelectionMap, type __, detectGlobalPackageManagers, detectLockfilePackageManagers, detectPackageManagers, ensurePackage, filterPackageManagers, findPackageManager, findPackageManagerSafely, importMap, importer, isPackageDependency, packageManagers, resolveModule };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { InstallPackageOptions } from '@antfu/install-pkg';
|
|
2
|
+
import { AsyncCacheFn as AsyncCacheFn$1 } from 'async-cache-fn';
|
|
3
|
+
import { Options } from 'execa';
|
|
4
|
+
|
|
5
|
+
interface ImportPackageOption<T = any> {
|
|
6
|
+
/**
|
|
7
|
+
* The name of the package to import. This should match the name used in the import statement.
|
|
8
|
+
*/
|
|
9
|
+
name: string;
|
|
10
|
+
/**
|
|
11
|
+
* When enabled, the package will be installed if it is not found
|
|
12
|
+
* @default true
|
|
13
|
+
*/
|
|
14
|
+
install?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* The import statement for the package.
|
|
17
|
+
*/
|
|
18
|
+
import: () => ImportStatement<T>;
|
|
19
|
+
/**
|
|
20
|
+
* When enabled, the package will be installed as a dev dependency
|
|
21
|
+
*/
|
|
22
|
+
isDevDependency?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Additional installation options
|
|
25
|
+
*/
|
|
26
|
+
installOptions?: Omit<InstallPackageOptions, "dev">;
|
|
27
|
+
}
|
|
28
|
+
type ImportMap = Record<string, ImportOption>;
|
|
29
|
+
type ImportList = ImportOption[];
|
|
30
|
+
type ImportOption<T = any> = ImportStatement<T> | (() => ImportStatement<T>) | ImportPackageOption<T>;
|
|
31
|
+
type ImportStatement<T = any> = Promise<T>;
|
|
32
|
+
type ResolvedImportOption<T extends ImportOption> = ResolvedPromise<ExtractImportStatement<T>>;
|
|
33
|
+
type ResolvedImportMap<$Imports extends ImportMap> = {
|
|
34
|
+
[P in keyof $Imports]: ResolvedImportOption<$Imports[P]>;
|
|
35
|
+
};
|
|
36
|
+
type ResolvedImportMapPromise<T extends ImportMap> = Promise<ResolvedImportMap<T>>;
|
|
37
|
+
type ResolvedImportList<$Imports extends ImportList> = {
|
|
38
|
+
[P in keyof $Imports]: ResolvedImportOption<$Imports[P]>;
|
|
39
|
+
};
|
|
40
|
+
type ResolvedImportListPromise<T extends ImportList> = Promise<ResolvedImportList<T>>;
|
|
41
|
+
type ExtractImportStatement<T extends ImportOption> = ExtractImport<T> extends () => infer I ? I : T;
|
|
42
|
+
type ExtractImport<T extends ImportOption> = T extends {
|
|
43
|
+
import: infer I;
|
|
44
|
+
} ? I : T;
|
|
45
|
+
|
|
46
|
+
type __<T> = {
|
|
47
|
+
[K in keyof T]: T[K];
|
|
48
|
+
} & {};
|
|
49
|
+
type Awaitable<T> = T | Promise<T>;
|
|
50
|
+
type ResolvedPromise<T> = T extends Promise<infer U> ? U : never;
|
|
51
|
+
type KeyOf<T, K> = K extends keyof T ? K : never;
|
|
52
|
+
type KeyOfValue<T, K> = T[KeyOf<T, K>];
|
|
53
|
+
type SelectionMap<T> = __<{
|
|
54
|
+
[K in keyof T]?: boolean;
|
|
55
|
+
}>;
|
|
56
|
+
type PickByValue<T, V> = {
|
|
57
|
+
[K in keyof T as T[K] extends V ? K : never]: T[K];
|
|
58
|
+
};
|
|
59
|
+
type Entry<key extends PropertyKey = PropertyKey, value = unknown> = readonly [key: key, value: value];
|
|
60
|
+
type EntryOf<O> = {
|
|
61
|
+
[k in keyof O]-?: [k, O[k] & ({} | null)];
|
|
62
|
+
}[O extends readonly unknown[] ? keyof O & number : keyof O] & unknown;
|
|
63
|
+
type FromEntries<entries extends readonly Entry[]> = {
|
|
64
|
+
[entry in entries[number] as entry[0]]: entry[1];
|
|
65
|
+
};
|
|
66
|
+
type UnionizedSelectionMap<T, TSelection extends SelectionMap<T>, V> = __<V & {
|
|
67
|
+
[K in keyof T as IsExactBoolean<TSelection[K]> extends true ? K : never]?: T[K];
|
|
68
|
+
}>;
|
|
69
|
+
type Select<T, TSelection extends SelectionMap<T>, TMode extends "pick" | "omit"> = __<UnionizedSelectionMap<T, TSelection, TMode extends "pick" ? Pick<T, KeyOf<T, keyof PickByValue<TSelection, true>>> : Omit<T, KeyOf<T, keyof PickByValue<TSelection, true>>>>>;
|
|
70
|
+
type IsExactBoolean<T> = true extends T ? false extends T ? true : false : false;
|
|
71
|
+
type IsUnion<T, U = T> = T extends U ? [U] extends [T] ? false : true : never;
|
|
72
|
+
type MergeObject<T extends object, O extends object | unknown = unknown> = __<T & (O extends object ? O : Record<never, never>)>;
|
|
73
|
+
type AsyncCacheFn<TReturn = unknown, TOption extends object | undefined = undefined, C extends "required" | "optional" = "optional"> = AsyncCacheFn$1<TReturn, C extends "optional" ? [TOption | undefined] | [] : [TOption]>;
|
|
74
|
+
|
|
75
|
+
interface ImporterOptions {
|
|
76
|
+
/**
|
|
77
|
+
* When enabled, the default behavior is to install packages that are not found.
|
|
78
|
+
* The name of the package is inferred from the key of the import map.
|
|
79
|
+
* @default true
|
|
80
|
+
*/
|
|
81
|
+
install?: boolean;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Dynamically imports modules and returns their exports in a tuple.
|
|
85
|
+
* This function ensures type safety and maintains the order of imports.
|
|
86
|
+
*
|
|
87
|
+
* @param imports An array of dynamic import promises.
|
|
88
|
+
* @returns A promise that resolves to a tuple containing the default exports of the imported modules.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```typescript
|
|
92
|
+
* // Usage example with dynamic imports
|
|
93
|
+
* const [package1, package2] = await importer([
|
|
94
|
+
* import('@antfu/eslint-config'),
|
|
95
|
+
* import('@antfu/install-pkg')
|
|
96
|
+
* ]);
|
|
97
|
+
*
|
|
98
|
+
* // package1 and package2 will be the default exports of the respective modules
|
|
99
|
+
* ```
|
|
100
|
+
*
|
|
101
|
+
* @typeparam Imports An array type representing the dynamic imports.
|
|
102
|
+
*/
|
|
103
|
+
declare function importer<T extends ImportList>(imports: [...T], options?: ImporterOptions): Promise<ResolvedImportList<T>>;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Asynchronously imports modules from a record of dynamic import promises.
|
|
107
|
+
* Returns a promise that resolves to a record with the same keys, each mapped to the resolved import.
|
|
108
|
+
* This function maintains the key-value mapping and ensures type safety.
|
|
109
|
+
*
|
|
110
|
+
* @param importMap A record where each key is associated with a dynamic import promise.
|
|
111
|
+
* @returns A promise that resolves to a record containing the default exports of the imported modules,
|
|
112
|
+
* maintaining the original key structure.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* // Usage example with a record of dynamic imports
|
|
117
|
+
*
|
|
118
|
+
* const { package1, package2 } = await importMap({
|
|
119
|
+
* package1: import('package-1'),
|
|
120
|
+
* package2: import('package-2')
|
|
121
|
+
* });
|
|
122
|
+
*
|
|
123
|
+
* // importedModules.config and importedModules.pkg will be the default exports of the respective modules
|
|
124
|
+
* ```
|
|
125
|
+
*
|
|
126
|
+
*/
|
|
127
|
+
declare function importMap<T extends ImportMap>(importMap: T, options?: ImporterOptions): Promise<ResolvedImportMap<T>>;
|
|
128
|
+
|
|
129
|
+
declare function ensurePackage(name: string | string[], options?: InstallPackageOptions): Promise<void>;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Asynchronously handles the resolution of a module, extracting its default export if available.
|
|
133
|
+
* If the module does not have a default export, it returns the module itself.
|
|
134
|
+
*
|
|
135
|
+
* @param m A promise representing a module import (either ES Module or CommonJS).
|
|
136
|
+
* @returns A promise that resolves to either the default export of the module or the module itself.
|
|
137
|
+
*
|
|
138
|
+
* @typeparam T The type of the module being imported.
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```typescript
|
|
142
|
+
* // Usage example with dynamic import
|
|
143
|
+
* const module = await interopDefault(import('some-module'));
|
|
144
|
+
*
|
|
145
|
+
* // 'module' will be either the default export of 'some-module' or the module itself if no default export exists
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
declare function resolveModule<T>(m: Awaitable<T>): Promise<T extends {
|
|
149
|
+
default: infer U;
|
|
150
|
+
} ? U : T>;
|
|
151
|
+
|
|
152
|
+
declare function isPackageDependency(packageName: string | string[]): boolean;
|
|
153
|
+
|
|
154
|
+
interface PackageManagerConfig<ID extends string = string> {
|
|
155
|
+
id: ID;
|
|
156
|
+
command: string;
|
|
157
|
+
name: string;
|
|
158
|
+
meta: {
|
|
159
|
+
lockfile: string | string[];
|
|
160
|
+
};
|
|
161
|
+
runner: string;
|
|
162
|
+
args: {
|
|
163
|
+
install: {
|
|
164
|
+
command: string;
|
|
165
|
+
options: {
|
|
166
|
+
preferOffline: string;
|
|
167
|
+
isDevDependency: string;
|
|
168
|
+
};
|
|
169
|
+
};
|
|
170
|
+
uninstall: {
|
|
171
|
+
command: string;
|
|
172
|
+
};
|
|
173
|
+
};
|
|
174
|
+
options: {
|
|
175
|
+
version: string;
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
type PackageManagerCommands = PackageManagerConfig["args"];
|
|
179
|
+
type PackageManagerCommandName = keyof PackageManagerCommands;
|
|
180
|
+
type PackageManagerCommandSpec<K> = KeyOfValue<PackageManagerCommands, K> extends {
|
|
181
|
+
options: infer O;
|
|
182
|
+
} ? SelectionMap<O> : Record<never, never>;
|
|
183
|
+
|
|
184
|
+
type ScriptOptions<K extends PackageManagerCommandName | undefined = undefined> = __<{
|
|
185
|
+
cwd?: string;
|
|
186
|
+
silent?: boolean;
|
|
187
|
+
shellOptions?: Options;
|
|
188
|
+
} & PackageManagerCommandSpec<K>>;
|
|
189
|
+
interface PackageManager<ID extends string = PackageManagerId> {
|
|
190
|
+
id: ID;
|
|
191
|
+
config: PackageManagerConfig;
|
|
192
|
+
findLockfilePath: AsyncCacheFn<string | undefined, {
|
|
193
|
+
cwd?: string;
|
|
194
|
+
}>;
|
|
195
|
+
hasLockfile: AsyncCacheFn<boolean, {
|
|
196
|
+
cwd?: string;
|
|
197
|
+
}>;
|
|
198
|
+
readLockfile: AsyncCacheFn<string | undefined, {
|
|
199
|
+
cwd?: string;
|
|
200
|
+
}>;
|
|
201
|
+
globalVersion: AsyncCacheFn<string | undefined, ScriptOptions>;
|
|
202
|
+
uninstallPackage: (packageNames: string | string[], options?: ScriptOptions<"uninstall">) => Promise<void>;
|
|
203
|
+
installPackage: (packageNames: string | string[], options?: ScriptOptions<"install">) => Promise<void>;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
type PackageManagerId = keyof typeof packageManagers;
|
|
207
|
+
declare const packageManagers: {
|
|
208
|
+
pnpm: PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">;
|
|
209
|
+
yarn: PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">;
|
|
210
|
+
bun: PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">;
|
|
211
|
+
npm: PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">;
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
interface DetectPackageManagerOptions {
|
|
215
|
+
allowed?: SelectionMap<typeof packageManagers>;
|
|
216
|
+
cwd?: string;
|
|
217
|
+
}
|
|
218
|
+
declare function findPackageManager(options?: DetectPackageManagerOptions): Promise<PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">>;
|
|
219
|
+
declare function findPackageManagerSafely<TAssert extends boolean = true>(options?: DetectPackageManagerOptions & {
|
|
220
|
+
assert?: TAssert;
|
|
221
|
+
}): Promise<PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm"> | undefined>;
|
|
222
|
+
declare function detectPackageManagers(options?: DetectPackageManagerOptions): Promise<(PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">)[]>;
|
|
223
|
+
declare function detectLockfilePackageManagers(options?: DetectPackageManagerOptions): Promise<(PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">)[]>;
|
|
224
|
+
declare function detectGlobalPackageManagers(options?: DetectPackageManagerOptions): Promise<(PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">)[]>;
|
|
225
|
+
declare function filterPackageManagers(filterFn: (packageManager: PackageManager) => Promise<unknown>, options?: DetectPackageManagerOptions): Promise<(PackageManager<"pnpm"> | PackageManager<"yarn"> | PackageManager<"bun"> | PackageManager<"npm">)[]>;
|
|
226
|
+
|
|
227
|
+
export { type AsyncCacheFn, type Awaitable, type Entry, type EntryOf, type FromEntries, type ImportList, type ImportMap, type ImportOption, type ImportPackageOption, type ImportStatement, type ImporterOptions, type IsExactBoolean, type IsUnion, type KeyOf, type KeyOfValue, type MergeObject, type PackageManagerCommandName, type PackageManagerCommandSpec, type PackageManagerCommands, type PackageManagerConfig, type PackageManagerId, type PickByValue, type ResolvedImportList, type ResolvedImportListPromise, type ResolvedImportMap, type ResolvedImportMapPromise, type ResolvedImportOption, type ResolvedPromise, type Select, type SelectionMap, type __, detectGlobalPackageManagers, detectLockfilePackageManagers, detectPackageManagers, ensurePackage, filterPackageManagers, findPackageManager, findPackageManagerSafely, importMap, importer, isPackageDependency, packageManagers, resolveModule };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { installPackage } from '@antfu/install-pkg';
|
|
2
|
+
import 'node:fs';
|
|
3
|
+
import { execa } from 'execa';
|
|
4
|
+
import { isPackageExists } from 'local-pkg';
|
|
5
|
+
import { asyncCacheFn } from 'async-cache-fn';
|
|
6
|
+
import { findUp } from 'find-up';
|
|
7
|
+
import { readFile } from 'node:fs/promises';
|
|
8
|
+
|
|
9
|
+
async function resolveModule(m) {
|
|
10
|
+
const resolved = await m;
|
|
11
|
+
return resolved.default || resolved;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function importer(imports, options) {
|
|
15
|
+
const { install = true } = options ?? {};
|
|
16
|
+
return Promise.all(
|
|
17
|
+
imports.map(async (option) => {
|
|
18
|
+
if (install && "name" in option) {
|
|
19
|
+
await ensurePackage(option.name);
|
|
20
|
+
}
|
|
21
|
+
const importStatement = getImportStatement(option);
|
|
22
|
+
return resolveModule(importStatement);
|
|
23
|
+
})
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
function getImportStatement(option) {
|
|
27
|
+
if (typeof option === "function") {
|
|
28
|
+
return option();
|
|
29
|
+
}
|
|
30
|
+
if (typeof option === "object" && "import" in option && "name" in option) {
|
|
31
|
+
return option.import();
|
|
32
|
+
}
|
|
33
|
+
return option;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function importMap(importMap2, options) {
|
|
37
|
+
const keys = Object.keys(importMap2);
|
|
38
|
+
const imported = await importer(
|
|
39
|
+
keys.map((key) => importMap2[key]),
|
|
40
|
+
options
|
|
41
|
+
);
|
|
42
|
+
return Object.fromEntries(
|
|
43
|
+
keys.map((key, index) => [key, imported[index]])
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const toArray = (data) => Array.isArray(data) ? data : [data];
|
|
48
|
+
const entriesOf = (o) => Object.entries(o);
|
|
49
|
+
const fromEntries = (entries) => Object.fromEntries(entries);
|
|
50
|
+
const notFalsy = (value) => [false, null, void 0].every((v) => v !== value);
|
|
51
|
+
const select = (obj, selection, mode) => {
|
|
52
|
+
if (!selection)
|
|
53
|
+
return obj;
|
|
54
|
+
const filtered = entriesOf(obj).filter(([key]) => {
|
|
55
|
+
return mode === "omit" ? !selection[key] : selection[key];
|
|
56
|
+
});
|
|
57
|
+
return fromEntries(filtered);
|
|
58
|
+
};
|
|
59
|
+
const invariant = (predicate, message) => {
|
|
60
|
+
if (!predicate) {
|
|
61
|
+
throw new Error(message);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
function isPackageDependency(packageName) {
|
|
66
|
+
return toArray(packageName).every((name) => isPackageExists(name));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function ensurePackage(name, options) {
|
|
70
|
+
if (isPackageDependency(name))
|
|
71
|
+
return;
|
|
72
|
+
await installPackage(name, options);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function definePackageManager(config) {
|
|
76
|
+
const { command, args: agentArgs, options: agentOptions } = config;
|
|
77
|
+
const findLockfilePath = asyncCacheFn(async (options) => {
|
|
78
|
+
const { cwd } = options ?? {};
|
|
79
|
+
const lockfiles = toArray(config.meta.lockfile);
|
|
80
|
+
return await findUp(lockfiles, { cwd });
|
|
81
|
+
});
|
|
82
|
+
return {
|
|
83
|
+
id: config.id,
|
|
84
|
+
config,
|
|
85
|
+
findLockfilePath,
|
|
86
|
+
hasLockfile: asyncCacheFn(async (...args) => {
|
|
87
|
+
const lockfilePath = await findLockfilePath.noCache(...args);
|
|
88
|
+
return Boolean(lockfilePath);
|
|
89
|
+
}),
|
|
90
|
+
readLockfile: asyncCacheFn(async (...args) => {
|
|
91
|
+
const lockfilePath = await findLockfilePath.noCache(...args);
|
|
92
|
+
if (!lockfilePath)
|
|
93
|
+
return void 0;
|
|
94
|
+
return readFile(lockfilePath, "utf8");
|
|
95
|
+
}),
|
|
96
|
+
globalVersion: asyncCacheFn(async (...args) => {
|
|
97
|
+
const [options] = args;
|
|
98
|
+
try {
|
|
99
|
+
const { stdout } = await $$({
|
|
100
|
+
command,
|
|
101
|
+
args: [agentOptions.version],
|
|
102
|
+
...options
|
|
103
|
+
});
|
|
104
|
+
return `${stdout}`;
|
|
105
|
+
} catch (e) {
|
|
106
|
+
return void 0;
|
|
107
|
+
}
|
|
108
|
+
}),
|
|
109
|
+
installPackage: async (packageName, options) => {
|
|
110
|
+
const install = agentArgs.install;
|
|
111
|
+
const { isDevDependency, preferOffline } = select(
|
|
112
|
+
install.options,
|
|
113
|
+
options ?? {},
|
|
114
|
+
"pick"
|
|
115
|
+
);
|
|
116
|
+
const packageNames = toArray(packageName);
|
|
117
|
+
try {
|
|
118
|
+
await $$({
|
|
119
|
+
command,
|
|
120
|
+
args: [
|
|
121
|
+
install.command,
|
|
122
|
+
isDevDependency,
|
|
123
|
+
preferOffline,
|
|
124
|
+
...packageNames
|
|
125
|
+
],
|
|
126
|
+
...options
|
|
127
|
+
});
|
|
128
|
+
} catch (e) {
|
|
129
|
+
throw new Error(`Failed to install: ${packageNames.join(", ")}`);
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
uninstallPackage: async (packageName, options) => {
|
|
133
|
+
const uninstall = agentArgs.uninstall;
|
|
134
|
+
if (!isPackageDependency(packageName))
|
|
135
|
+
return;
|
|
136
|
+
await $$({
|
|
137
|
+
command,
|
|
138
|
+
args: [uninstall.command, ...toArray(packageName)],
|
|
139
|
+
...options
|
|
140
|
+
}).catch((e) => {
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
async function $$(options) {
|
|
146
|
+
const { command, args = [], silent = true, cwd, shellOptions } = options;
|
|
147
|
+
return execa(command, args.filter(notFalsy), {
|
|
148
|
+
cwd,
|
|
149
|
+
...shellOptions,
|
|
150
|
+
stdio: silent ? "ignore" : "inherit"
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const bun = definePackageManager({
|
|
155
|
+
id: "bun",
|
|
156
|
+
name: "Bun",
|
|
157
|
+
command: "bun",
|
|
158
|
+
runner: "bunx",
|
|
159
|
+
meta: {
|
|
160
|
+
lockfile: "bun.lockb"
|
|
161
|
+
},
|
|
162
|
+
args: {
|
|
163
|
+
install: {
|
|
164
|
+
command: "install",
|
|
165
|
+
options: {
|
|
166
|
+
isDevDependency: "-D",
|
|
167
|
+
preferOffline: "--prefer-offline"
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
uninstall: {
|
|
171
|
+
command: "uninstall"
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
options: {
|
|
175
|
+
version: "--version"
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
const npm = definePackageManager({
|
|
180
|
+
id: "npm",
|
|
181
|
+
name: "NPM",
|
|
182
|
+
command: "npm",
|
|
183
|
+
runner: "npx",
|
|
184
|
+
meta: {
|
|
185
|
+
lockfile: ["package-lock.json", "npm-shrinkwrap.json"]
|
|
186
|
+
},
|
|
187
|
+
args: {
|
|
188
|
+
install: {
|
|
189
|
+
command: "install",
|
|
190
|
+
options: {
|
|
191
|
+
isDevDependency: "-D",
|
|
192
|
+
preferOffline: "--prefer-offline"
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
uninstall: {
|
|
196
|
+
command: "uninstall"
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
options: {
|
|
200
|
+
version: "--version"
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
const pnpm = definePackageManager({
|
|
205
|
+
id: "pnpm",
|
|
206
|
+
name: "PNPM",
|
|
207
|
+
command: "pnpm",
|
|
208
|
+
runner: "pnpx",
|
|
209
|
+
meta: {
|
|
210
|
+
lockfile: "pnpm-lock.yaml"
|
|
211
|
+
},
|
|
212
|
+
args: {
|
|
213
|
+
install: {
|
|
214
|
+
command: "install",
|
|
215
|
+
options: {
|
|
216
|
+
isDevDependency: "-D",
|
|
217
|
+
preferOffline: "--prefer-offline"
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
uninstall: {
|
|
221
|
+
command: "uninstall"
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
options: {
|
|
225
|
+
version: "--version"
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
const yarn = definePackageManager({
|
|
230
|
+
id: "yarn",
|
|
231
|
+
name: "Yarn",
|
|
232
|
+
command: "yarn",
|
|
233
|
+
runner: "yarn dlx",
|
|
234
|
+
meta: {
|
|
235
|
+
lockfile: "yarn.lock"
|
|
236
|
+
},
|
|
237
|
+
args: {
|
|
238
|
+
install: {
|
|
239
|
+
command: "add",
|
|
240
|
+
options: {
|
|
241
|
+
isDevDependency: "-D",
|
|
242
|
+
preferOffline: "--prefer-offline"
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
uninstall: {
|
|
246
|
+
command: "remove"
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
options: {
|
|
250
|
+
version: "--version"
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
const packageManagers = fromEntries(
|
|
255
|
+
[pnpm, yarn, bun, npm].map((e) => [e.id, e])
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
async function findPackageManager(options) {
|
|
259
|
+
const { ...rest } = options ?? {};
|
|
260
|
+
const packageManager = await findPackageManagerSafely(rest);
|
|
261
|
+
invariant(packageManager, "No package manager found");
|
|
262
|
+
return packageManager;
|
|
263
|
+
}
|
|
264
|
+
async function findPackageManagerSafely(options) {
|
|
265
|
+
const lockfilePm = (await detectLockfilePackageManagers(options))[0];
|
|
266
|
+
if (lockfilePm) {
|
|
267
|
+
return lockfilePm;
|
|
268
|
+
}
|
|
269
|
+
const globalPm = (await detectGlobalPackageManagers(options))[0];
|
|
270
|
+
return globalPm;
|
|
271
|
+
}
|
|
272
|
+
async function detectPackageManagers(options) {
|
|
273
|
+
return [
|
|
274
|
+
...await detectLockfilePackageManagers(options),
|
|
275
|
+
...await detectGlobalPackageManagers(options)
|
|
276
|
+
];
|
|
277
|
+
}
|
|
278
|
+
async function detectLockfilePackageManagers(options) {
|
|
279
|
+
({ cwd: options?.cwd });
|
|
280
|
+
return filterPackageManagers((e) => e.hasLockfile(options), options);
|
|
281
|
+
}
|
|
282
|
+
async function detectGlobalPackageManagers(options) {
|
|
283
|
+
return filterPackageManagers(async (e) => e.globalVersion(options), options);
|
|
284
|
+
}
|
|
285
|
+
async function filterPackageManagers(filterFn, options) {
|
|
286
|
+
const allowedPackageManagers = Object.entries(packageManagers).filter(
|
|
287
|
+
([key]) => {
|
|
288
|
+
if (!options?.allowed)
|
|
289
|
+
return true;
|
|
290
|
+
return key in options.allowed;
|
|
291
|
+
}
|
|
292
|
+
);
|
|
293
|
+
return (await Promise.all(
|
|
294
|
+
allowedPackageManagers.map(async ([key, pm]) => {
|
|
295
|
+
const valid = await filterFn(pm);
|
|
296
|
+
return valid ? pm : void 0;
|
|
297
|
+
})
|
|
298
|
+
)).filter(notFalsy);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
export { detectGlobalPackageManagers, detectLockfilePackageManagers, detectPackageManagers, ensurePackage, filterPackageManagers, findPackageManager, findPackageManagerSafely, importMap, importer, isPackageDependency, packageManagers, resolveModule };
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "package-management",
|
|
3
|
+
"description": "Simple type-safe utilities for programatically installing and importing packages",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"private": false,
|
|
6
|
+
"files": [
|
|
7
|
+
"dist/**"
|
|
8
|
+
],
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.mjs",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "unbuild",
|
|
18
|
+
"build:watch": "tsc --watch --preserveWatchOutput",
|
|
19
|
+
"dev": "unbuild --stub",
|
|
20
|
+
"lint": "eslint",
|
|
21
|
+
"test": "vitest",
|
|
22
|
+
"typecheck": "tsc --noEmit",
|
|
23
|
+
"clean": "rm -rf .tsbuildinfo .turbo coverage dist node_modules",
|
|
24
|
+
"npm-publish": "pnpm run build && npm publish --access public --no-git-checks"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/node": "20.5.9",
|
|
28
|
+
"typescript": "^5.3.2",
|
|
29
|
+
"unbuild": "^2.0.0",
|
|
30
|
+
"vite-tsconfig-paths": "^4.3.1",
|
|
31
|
+
"vitest": "^0.34.6"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@antfu/install-pkg": "^0.3.1",
|
|
35
|
+
"async-cache-fn": "^0.0.3",
|
|
36
|
+
"execa": "^8.0.1",
|
|
37
|
+
"find-up": "^7.0.0",
|
|
38
|
+
"local-pkg": "^0.5.0"
|
|
39
|
+
}
|
|
40
|
+
}
|