@adonisjs/assembler 7.8.1 → 8.0.0-next.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.
@@ -1,20 +1,41 @@
1
1
  import type tsStatic from 'typescript';
2
- import { type Logger } from '@poppinss/cliui';
3
- import type { BundlerOptions } from './types.js';
4
- type SupportedPackageManager = 'npm' | 'yarn' | 'yarn@berry' | 'pnpm' | 'bun';
2
+ import type { BundlerOptions } from './types/common.ts';
3
+ import { type SupportedPackageManager } from './types/code_transformer.ts';
5
4
  /**
6
5
  * The bundler class exposes the API to build an AdonisJS project.
7
6
  */
8
7
  export declare class Bundler {
9
8
  #private;
10
- constructor(cwd: URL, ts: typeof tsStatic, options: BundlerOptions);
9
+ cwd: URL;
10
+ options: BundlerOptions;
11
+ ui: {
12
+ colors: import("@poppinss/colors/types").Colors;
13
+ logger: import("@poppinss/cliui").Logger;
14
+ table: (tableOptions?: Partial<import("@poppinss/cliui/types").TableOptions>) => import("@poppinss/cliui").Table;
15
+ tasks: (tasksOptions?: Partial<import("@poppinss/cliui/types").TaskManagerOptions>) => import("@poppinss/cliui").TaskManager;
16
+ icons: {
17
+ tick: string;
18
+ cross: string;
19
+ bullet: string;
20
+ nodejs: string;
21
+ pointer: string;
22
+ info: string;
23
+ warning: string;
24
+ squareSmallFilled: string;
25
+ };
26
+ sticker: () => import("@poppinss/cliui").Instructions;
27
+ instructions: () => import("@poppinss/cliui").Instructions;
28
+ switchMode(modeToUse: "raw" | "silent" | "normal"): void;
29
+ useRenderer(rendererToUse: import("@poppinss/cliui/types").RendererContract): void;
30
+ useColors(colorsToUse: import("@poppinss/colors/types").Colors): void;
31
+ };
11
32
  /**
12
- * Set a custom CLI UI logger
33
+ * Package manager detect from the project environment
13
34
  */
14
- setLogger(logger: Logger): this;
35
+ packageManager: SupportedPackageManager;
36
+ constructor(cwd: URL, ts: typeof tsStatic, options: BundlerOptions);
15
37
  /**
16
38
  * Bundles the application to be run in production
17
39
  */
18
40
  bundle(stopOnError?: boolean, client?: SupportedPackageManager): Promise<boolean>;
19
41
  }
20
- export {};
@@ -1,7 +1,8 @@
1
+ import { type OneOrMore } from '@poppinss/utils/types';
1
2
  import { installPackage, detectPackageManager } from '@antfu/install-pkg';
2
3
  import { Project } from 'ts-morph';
3
- import { RcFileTransformer } from './rc_file_transformer.js';
4
- import type { MiddlewareNode, EnvValidationNode, BouncerPolicyNode } from '../types.js';
4
+ import { RcFileTransformer } from './rc_file_transformer.ts';
5
+ import type { MiddlewareNode, EnvValidationNode, BouncerPolicyNode } from '../types/code_transformer.ts';
5
6
  /**
6
7
  * This class is responsible for updating
7
8
  */
@@ -57,4 +58,31 @@ export declare class CodeTransformer {
57
58
  * inside the `app/policies/main.ts` file.
58
59
  */
59
60
  addPolicies(policies: BouncerPolicyNode[]): Promise<void>;
61
+ /**
62
+ * Creates an index file that exports an object in which the key is the PascalCase
63
+ * name of the entity and the value is a dynamic import.
64
+ *
65
+ * For example, in case of controllers, the index file will be the list of controller
66
+ * names pointing a dynamically imported controller file.
67
+ *
68
+ * ```ts
69
+ * export const controllers = {
70
+ * Login: () => import('#controllers/login_controller'),
71
+ * Login: () => import('#controllers/login_controller'),
72
+ * }
73
+ * ```
74
+ *
75
+ * @param source
76
+ * @param outputPath
77
+ * @param importAlias
78
+ */
79
+ makeEntityIndex(input: OneOrMore<{
80
+ source: string;
81
+ importAlias?: string;
82
+ }>, output: {
83
+ destination: string;
84
+ exportName?: string;
85
+ transformName?: (name: string) => string;
86
+ transformImport?: (modulePath: string) => string;
87
+ }): Promise<void>;
60
88
  }
@@ -1,20 +1,30 @@
1
+ import {
2
+ debug_default
3
+ } from "../../chunk-RR4HCA4M.js";
4
+
1
5
  // src/code_transformer/main.ts
2
- import { join } from "node:path";
3
- import { fileURLToPath as fileURLToPath2 } from "node:url";
6
+ import { fileURLToPath as fileURLToPath2 } from "url";
7
+ import string from "@poppinss/utils/string";
8
+ import { isScriptFile } from "@poppinss/utils";
9
+ import { fsReadAll } from "@poppinss/utils/fs";
10
+ import { mkdir, writeFile } from "fs/promises";
11
+ import StringBuilder from "@poppinss/utils/string_builder";
12
+ import { basename, dirname, join, relative } from "path";
4
13
  import { installPackage, detectPackageManager } from "@antfu/install-pkg";
5
14
  import {
6
15
  Node as Node2,
7
- Project as Project2,
16
+ Project,
8
17
  QuoteKind,
9
18
  SyntaxKind as SyntaxKind2
10
19
  } from "ts-morph";
11
20
 
12
21
  // src/code_transformer/rc_file_transformer.ts
13
- import { fileURLToPath } from "node:url";
22
+ import { fileURLToPath } from "url";
14
23
  import {
15
24
  Node,
16
25
  SyntaxKind
17
26
  } from "ts-morph";
27
+ var ALLOWED_ENVIRONMENTS = ["web", "console", "test", "repl"];
18
28
  var RcFileTransformer = class {
19
29
  #cwd;
20
30
  #project;
@@ -48,9 +58,7 @@ var RcFileTransformer = class {
48
58
  if (!environments) {
49
59
  return false;
50
60
  }
51
- return !!["web", "console", "test", "repl"].find(
52
- (env) => !environments.includes(env)
53
- );
61
+ return !!ALLOWED_ENVIRONMENTS.find((env) => !environments.includes(env));
54
62
  }
55
63
  /**
56
64
  * Locate the `defineConfig` call inside the `adonisrc.ts` file
@@ -287,6 +295,7 @@ var CodeTransformer = class {
287
295
  * Directory of the adonisjs project
288
296
  */
289
297
  #cwd;
298
+ #cwdPath;
290
299
  /**
291
300
  * The TsMorph project
292
301
  */
@@ -305,7 +314,8 @@ var CodeTransformer = class {
305
314
  };
306
315
  constructor(cwd) {
307
316
  this.#cwd = cwd;
308
- this.project = new Project2({
317
+ this.#cwdPath = fileURLToPath2(this.#cwd);
318
+ this.project = new Project({
309
319
  tsConfigFilePath: join(fileURLToPath2(this.#cwd), "tsconfig.json"),
310
320
  manipulationSettings: { quoteKind: QuoteKind.Single }
311
321
  });
@@ -404,7 +414,7 @@ var CodeTransformer = class {
404
414
  * `env.ts` file
405
415
  */
406
416
  async defineEnvValidations(definition) {
407
- const kernelUrl = fileURLToPath2(new URL("./start/env.ts", this.#cwd));
417
+ const kernelUrl = join(this.#cwdPath, "./start/env.ts");
408
418
  const file = this.project.getSourceFileOrThrow(kernelUrl);
409
419
  const callExpressions = file.getDescendantsOfKind(SyntaxKind2.CallExpression).filter((statement) => statement.getExpression().getText() === "Env.create");
410
420
  if (!callExpressions.length) {
@@ -446,7 +456,7 @@ var CodeTransformer = class {
446
456
  * your `start/kernel.ts` file.
447
457
  */
448
458
  async addMiddlewareToStack(stack, middleware) {
449
- const kernelUrl = fileURLToPath2(new URL("./start/kernel.ts", this.#cwd));
459
+ const kernelUrl = join(this.#cwdPath, "./start/kernel.ts");
450
460
  const file = this.project.getSourceFileOrThrow(kernelUrl);
451
461
  for (const middlewareEntry of middleware) {
452
462
  if (stack === "named") {
@@ -470,7 +480,7 @@ var CodeTransformer = class {
470
480
  * Add a new Japa plugin in the `tests/bootstrap.ts` file
471
481
  */
472
482
  async addJapaPlugin(pluginCall, importDeclarations) {
473
- const testBootstrapUrl = fileURLToPath2(new URL("./tests/bootstrap.ts", this.#cwd));
483
+ const testBootstrapUrl = join(this.#cwdPath, "./tests/bootstrap.ts");
474
484
  const file = this.project.getSourceFileOrThrow(testBootstrapUrl);
475
485
  this.#addImportDeclarations(file, importDeclarations);
476
486
  const pluginsArray = file.getVariableDeclaration("plugins")?.getInitializerIfKind(SyntaxKind2.ArrayLiteralExpression);
@@ -486,7 +496,7 @@ var CodeTransformer = class {
486
496
  * Add a new Vite plugin
487
497
  */
488
498
  async addVitePlugin(pluginCall, importDeclarations) {
489
- const viteConfigTsUrl = fileURLToPath2(new URL("./vite.config.ts", this.#cwd));
499
+ const viteConfigTsUrl = join(this.#cwdPath, "./vite.config.ts");
490
500
  const file = this.project.getSourceFile(viteConfigTsUrl);
491
501
  if (!file) {
492
502
  throw new Error(
@@ -512,7 +522,7 @@ var CodeTransformer = class {
512
522
  * inside the `app/policies/main.ts` file.
513
523
  */
514
524
  async addPolicies(policies) {
515
- const kernelUrl = fileURLToPath2(new URL("./app/policies/main.ts", this.#cwd));
525
+ const kernelUrl = join(this.#cwdPath, "./app/policies/main.ts");
516
526
  const file = this.project.getSourceFileOrThrow(kernelUrl);
517
527
  for (const policy of policies) {
518
528
  this.#addToPoliciesList(file, policy);
@@ -520,8 +530,64 @@ var CodeTransformer = class {
520
530
  file.formatText(this.#editorSettings);
521
531
  await file.save();
522
532
  }
533
+ /**
534
+ * Creates an index file that exports an object in which the key is the PascalCase
535
+ * name of the entity and the value is a dynamic import.
536
+ *
537
+ * For example, in case of controllers, the index file will be the list of controller
538
+ * names pointing a dynamically imported controller file.
539
+ *
540
+ * ```ts
541
+ * export const controllers = {
542
+ * Login: () => import('#controllers/login_controller'),
543
+ * Login: () => import('#controllers/login_controller'),
544
+ * }
545
+ * ```
546
+ *
547
+ * @param source
548
+ * @param outputPath
549
+ * @param importAlias
550
+ */
551
+ async makeEntityIndex(input, output) {
552
+ const inputs = Array.isArray(input) ? input : [input];
553
+ const outputPath = join(this.#cwdPath, output.destination);
554
+ const outputDir = dirname(outputPath);
555
+ const exportName = output.exportName ?? new StringBuilder(basename(output.destination)).removeExtension().camelCase();
556
+ debug_default(
557
+ 'creating index for "%s" at destination "%s" using sources %O',
558
+ exportName,
559
+ outputPath,
560
+ inputs
561
+ );
562
+ const entries = await Promise.all(
563
+ inputs.map(async ({ source, importAlias }) => {
564
+ const sourcePath = join(this.#cwdPath, source);
565
+ const filesList = await fsReadAll(sourcePath, {
566
+ filter: isScriptFile,
567
+ pathType: "absolute"
568
+ });
569
+ return filesList.map((filePath) => {
570
+ const name = new StringBuilder(string.toUnixSlash(relative(sourcePath, filePath))).removeExtension().pascalCase().toString();
571
+ const importPath = importAlias ? `${importAlias}/${new StringBuilder(string.toUnixSlash(relative(sourcePath, filePath))).removeExtension().toString()}` : string.toUnixSlash(relative(outputDir, filePath));
572
+ return {
573
+ name: output.transformName?.(name) ?? name,
574
+ importPath: output.transformImport?.(importPath) ?? importPath
575
+ };
576
+ });
577
+ })
578
+ );
579
+ const outputContents = entries.flat(2).reduce(
580
+ (result, entry) => {
581
+ debug_default('adding "%O" to the index', entry);
582
+ result.push(` ${entry.name}: () => import('${entry.importPath}'),`);
583
+ return result;
584
+ },
585
+ [`export const ${exportName} = {`]
586
+ ).concat("}");
587
+ await mkdir(outputDir, { recursive: true });
588
+ await writeFile(outputPath, outputContents.join("\n"));
589
+ }
523
590
  };
524
591
  export {
525
592
  CodeTransformer
526
593
  };
527
- //# sourceMappingURL=main.js.map
@@ -1,5 +1,6 @@
1
- import type { AppEnvironments, RcFile } from '@adonisjs/application/types';
2
- import { Project } from 'ts-morph';
1
+ import { type Project } from 'ts-morph';
2
+ import { type AssemblerRcFile } from '../types/common.ts';
3
+ declare const ALLOWED_ENVIRONMENTS: readonly ["web", "console", "test", "repl"];
3
4
  /**
4
5
  * RcFileTransformer is used to transform the `adonisrc.ts` file
5
6
  * for adding new commands, providers, meta files etc
@@ -14,11 +15,11 @@ export declare class RcFileTransformer {
14
15
  /**
15
16
  * Add a new preloaded file to the rcFile
16
17
  */
17
- addPreloadFile(modulePath: string, environments?: AppEnvironments[]): this;
18
+ addPreloadFile(modulePath: string, environments?: (typeof ALLOWED_ENVIRONMENTS)[number][]): this;
18
19
  /**
19
20
  * Add a new provider to the rcFile
20
21
  */
21
- addProvider(providerPath: string, environments?: AppEnvironments[]): this;
22
+ addProvider(providerPath: string, environments?: (typeof ALLOWED_ENVIRONMENTS)[number][]): this;
22
23
  /**
23
24
  * Add a new meta file to the rcFile
24
25
  */
@@ -38,9 +39,10 @@ export declare class RcFileTransformer {
38
39
  /**
39
40
  * Add a new assembler hook
40
41
  */
41
- addAssemblerHook(type: keyof NonNullable<RcFile['hooks']>, path: string): this;
42
+ addAssemblerHook(type: keyof Exclude<AssemblerRcFile['hooks'], undefined>, path: string): this;
42
43
  /**
43
44
  * Save the adonisrc.ts file
44
45
  */
45
46
  save(): Promise<void>;
46
47
  }
48
+ export {};
@@ -1,24 +1,52 @@
1
1
  import type tsStatic from 'typescript';
2
- import { type Logger } from '@poppinss/cliui';
3
- import type { DevServerOptions } from './types.js';
2
+ import type { DevServerOptions } from './types/common.ts';
4
3
  /**
5
- * Exposes the API to start the development. Optionally, the watch API can be
6
- * used to watch for file changes and restart the development server.
4
+ * Exposes the API to start the development server in HMR, watch or static mode.
7
5
  *
8
- * The Dev server performs the following actions
6
+ * In HMR mode, the DevServer will exec the "bin/server.ts" file and let hot-hook
7
+ * manage the changes using hot module reloading.
9
8
  *
10
- * - Assigns a random PORT, when PORT inside .env file is in use.
11
- * - Uses tsconfig.json file to collect a list of files to watch.
12
- * - Uses metaFiles from adonisrc.ts file to collect a list of files to watch.
13
- * - Restart HTTP server on every file change.
9
+ * In watch mode, the DevServer will start an internal watcher and restarts the after
10
+ * every file change. The files must be part of the TypeScript project (via tsconfig.json),
11
+ * or registered as metaFiles.
14
12
  */
15
13
  export declare class DevServer {
16
14
  #private;
17
- constructor(cwd: URL, options: DevServerOptions);
15
+ cwd: URL;
16
+ options: DevServerOptions;
17
+ /**
18
+ * CLI UI to log colorful messages
19
+ */
20
+ ui: {
21
+ colors: import("@poppinss/colors/types").Colors;
22
+ logger: import("@poppinss/cliui").Logger;
23
+ table: (tableOptions?: Partial<import("@poppinss/cliui/types").TableOptions>) => import("@poppinss/cliui").Table;
24
+ tasks: (tasksOptions?: Partial<import("@poppinss/cliui/types").TaskManagerOptions>) => import("@poppinss/cliui").TaskManager;
25
+ icons: {
26
+ tick: string;
27
+ cross: string;
28
+ bullet: string;
29
+ nodejs: string;
30
+ pointer: string;
31
+ info: string;
32
+ warning: string;
33
+ squareSmallFilled: string;
34
+ };
35
+ sticker: () => import("@poppinss/cliui").Instructions;
36
+ instructions: () => import("@poppinss/cliui").Instructions;
37
+ switchMode(modeToUse: "raw" | "silent" | "normal"): void;
38
+ useRenderer(rendererToUse: import("@poppinss/cliui/types").RendererContract): void;
39
+ useColors(colorsToUse: import("@poppinss/colors/types").Colors): void;
40
+ };
18
41
  /**
19
- * Set a custom CLI UI logger
42
+ * The mode in which the DevServer is running.
20
43
  */
21
- setLogger(logger: Logger): this;
44
+ get mode(): "hmr" | "watch" | "static";
45
+ /**
46
+ * Script file to start the development server
47
+ */
48
+ scriptFile: string;
49
+ constructor(cwd: URL, options: DevServerOptions);
22
50
  /**
23
51
  * Add listener to get notified when dev server is
24
52
  * closed
@@ -30,13 +58,13 @@ export declare class DevServer {
30
58
  */
31
59
  onError(callback: (error: any) => any): this;
32
60
  /**
33
- * Close watchers and running child processes
61
+ * Close watchers and the running child process
34
62
  */
35
63
  close(): Promise<void>;
36
64
  /**
37
65
  * Start the development server
38
66
  */
39
- start(): Promise<void>;
67
+ start(ts: typeof tsStatic): Promise<void>;
40
68
  /**
41
69
  * Start the development server in watch mode
42
70
  */
@@ -0,0 +1,60 @@
1
+ import type tsStatic from 'typescript';
2
+ import { type InspectedFile, type AssemblerRcFile } from './types/common.ts';
3
+ /**
4
+ * Exposes an intutive API to run actions when different kind of files
5
+ * are changed. The FileSystem is built around the vocabulary used by
6
+ * AdonisJS. Which includes:
7
+ *
8
+ * - Source files: TypeScript, JavaScript, JSON, JSX, TSX files that are included
9
+ * inside the "tsconfig.json" file are considered as source files.
10
+ * - Meta files: Files registered under the "metaFiles" array of "adonisrc.ts" file
11
+ * are called meta files.
12
+ * - Meta restart files: Meta files with "restart: true" enabled are called meta restart
13
+ * files.
14
+ *
15
+ * Using FileSystem you can register actions to be executed when a file changes in
16
+ * one of the above categories.
17
+ */
18
+ export declare class FileSystem {
19
+ #private;
20
+ /**
21
+ * Includes glob patterns extracted from "tsconfig.json" file.
22
+ * Defaults to: ["**\/*"]
23
+ */
24
+ get includes(): string[];
25
+ /**
26
+ * Excludes glob patterns extracted from "tsconfig.json" file.
27
+ *
28
+ * Defaults to: [
29
+ * 'node_modules/**',
30
+ * 'bower_components/**',
31
+ * 'jspm_packages/**,
32
+ * ]
33
+ *
34
+ * Following patterns are always ignored
35
+ *
36
+ * '.git/**', 'coverage/**', '.github/**'
37
+ */
38
+ get excludes(): string[];
39
+ /**
40
+ * Inspect a relative path to find its source in the project
41
+ */
42
+ inspect: (input: string) => InspectedFile | null;
43
+ /**
44
+ * Returns true if the directory should be watched. Chokidar sends
45
+ * absolute unix paths to the ignored callback.
46
+ *
47
+ * You must use "shouldWatchFile" method for files and call this method
48
+ * for directories only.
49
+ */
50
+ shouldWatchDirectory: (input: string) => unknown;
51
+ constructor(cwd: URL | string, tsConfig: tsStatic.ParsedCommandLine, rcFile: AssemblerRcFile);
52
+ /**
53
+ * Returns true if the file should be watched. Chokidar sends
54
+ * absolute unix paths to the ignored callback.
55
+ *
56
+ * You must use "shouldWatchDirectory" method for directories and call
57
+ * this method for files only.
58
+ */
59
+ shouldWatchFile(absolutePath: string): boolean;
60
+ }
@@ -1,6 +1,5 @@
1
1
  import type tsStatic from 'typescript';
2
- import { type Logger } from '@poppinss/cliui';
3
- import type { TestRunnerOptions } from './types.js';
2
+ import type { TestRunnerOptions } from './types/common.ts';
4
3
  /**
5
4
  * Exposes the API to run Japa tests and optionally watch for file
6
5
  * changes to re-run the tests.
@@ -11,15 +10,40 @@ import type { TestRunnerOptions } from './types.js';
11
10
  * will be re-run.
12
11
  * - Otherwise, all tests will re-run with respect to the initial
13
12
  * filters applied when running the `node ace test` command.
14
- *
15
13
  */
16
14
  export declare class TestRunner {
17
15
  #private;
18
- constructor(cwd: URL, options: TestRunnerOptions);
16
+ cwd: URL;
17
+ options: TestRunnerOptions;
19
18
  /**
20
- * Set a custom CLI UI logger
19
+ * CLI UI to log colorful messages
21
20
  */
22
- setLogger(logger: Logger): this;
21
+ ui: {
22
+ colors: import("@poppinss/colors/types").Colors;
23
+ logger: import("@poppinss/cliui").Logger;
24
+ table: (tableOptions?: Partial<import("@poppinss/cliui/types").TableOptions>) => import("@poppinss/cliui").Table;
25
+ tasks: (tasksOptions?: Partial<import("@poppinss/cliui/types").TaskManagerOptions>) => import("@poppinss/cliui").TaskManager;
26
+ icons: {
27
+ tick: string;
28
+ cross: string;
29
+ bullet: string;
30
+ nodejs: string;
31
+ pointer: string;
32
+ info: string;
33
+ warning: string;
34
+ squareSmallFilled: string;
35
+ };
36
+ sticker: () => import("@poppinss/cliui").Instructions;
37
+ instructions: () => import("@poppinss/cliui").Instructions;
38
+ switchMode(modeToUse: "raw" | "silent" | "normal"): void;
39
+ useRenderer(rendererToUse: import("@poppinss/cliui/types").RendererContract): void;
40
+ useColors(colorsToUse: import("@poppinss/colors/types").Colors): void;
41
+ };
42
+ /**
43
+ * The script file to run as a child process
44
+ */
45
+ scriptFile: string;
46
+ constructor(cwd: URL, options: TestRunnerOptions);
23
47
  /**
24
48
  * Add listener to get notified when dev server is
25
49
  * closed
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Entry to add a middleware to a given middleware stack
3
+ * via the CodeTransformer
4
+ */
5
+ export type MiddlewareNode = {
6
+ /**
7
+ * If you are adding a named middleware, then you must
8
+ * define the name.
9
+ */
10
+ name?: string;
11
+ /**
12
+ * The path to the middleware file
13
+ *
14
+ * @example
15
+ * `@adonisjs/static/static_middleware`
16
+ * `#middlewares/silent_auth.js`
17
+ */
18
+ path: string;
19
+ /**
20
+ * The position to add the middleware. If `before`
21
+ * middleware will be added at the first position and
22
+ * therefore will be run before all others
23
+ *
24
+ * @default 'after'
25
+ */
26
+ position?: 'before' | 'after';
27
+ };
28
+ /**
29
+ * Policy node to be added to the list of policies.
30
+ */
31
+ export type BouncerPolicyNode = {
32
+ /**
33
+ * Policy name
34
+ */
35
+ name: string;
36
+ /**
37
+ * Policy import path
38
+ */
39
+ path: string;
40
+ };
41
+ /**
42
+ * Defines the structure of an environment variable validation
43
+ * definition
44
+ */
45
+ export type EnvValidationNode = {
46
+ /**
47
+ * Write a leading comment on top of your variables
48
+ */
49
+ leadingComment?: string;
50
+ /**
51
+ * A key-value pair of env variables and their validation
52
+ *
53
+ * @example
54
+ * MY_VAR: 'Env.schema.string.optional()'
55
+ */
56
+ variables: Record<string, string>;
57
+ };
58
+ /**
59
+ * The supported package managers for installing packages
60
+ */
61
+ export type SupportedPackageManager = 'npm' | 'yarn' | 'yarn@berry' | 'pnpm' | 'bun';