pm-auto 1.0.6 → 1.0.7

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.
Files changed (43) hide show
  1. package/config.json +45 -0
  2. package/dist/build_command.d.ts +6 -1
  3. package/dist/build_command.d.ts.map +1 -1
  4. package/dist/build_command.js +61 -22
  5. package/dist/build_command.js.map +1 -1
  6. package/dist/config_path.d.ts +1 -0
  7. package/dist/config_path.d.ts.map +1 -1
  8. package/dist/config_path.js +60 -2
  9. package/dist/config_path.js.map +1 -1
  10. package/dist/config_reader.d.ts +2 -12
  11. package/dist/config_reader.d.ts.map +1 -1
  12. package/dist/config_reader.js +72 -89
  13. package/dist/config_reader.js.map +1 -1
  14. package/dist/display.d.ts.map +1 -1
  15. package/dist/display.js +1 -0
  16. package/dist/display.js.map +1 -1
  17. package/dist/index.js +5 -6
  18. package/dist/index.js.map +1 -1
  19. package/dist/orchestrator.d.ts.map +1 -1
  20. package/dist/orchestrator.js +18 -28
  21. package/dist/orchestrator.js.map +1 -1
  22. package/dist/run_commands.d.ts +6 -0
  23. package/dist/run_commands.d.ts.map +1 -0
  24. package/dist/{install.js → run_commands.js} +4 -4
  25. package/dist/run_commands.js.map +1 -0
  26. package/dist/types/index.d.ts +8 -2
  27. package/dist/types/index.d.ts.map +1 -1
  28. package/package.json +3 -1
  29. package/src/build_command.ts +73 -23
  30. package/src/config_path.ts +63 -2
  31. package/src/config_reader.ts +86 -107
  32. package/src/display.ts +1 -0
  33. package/src/index.ts +6 -9
  34. package/src/orchestrator.ts +21 -36
  35. package/src/{install.ts → run_commands.ts} +3 -3
  36. package/src/types/index.ts +12 -3
  37. package/tests/build_command.test.ts +239 -41
  38. package/tests/config_reader.test.ts +51 -92
  39. package/tests/{install.test.ts → run_command.test.ts} +23 -23
  40. package/dist/install.d.ts +0 -6
  41. package/dist/install.d.ts.map +0 -1
  42. package/dist/install.js.map +0 -1
  43. package/test.json +0 -87
@@ -1,132 +1,111 @@
1
1
  import fs from "fs/promises";
2
2
  import { getConfigPath } from "./config_path.js";
3
-
4
- import * as fsd from "fs";
5
- import * as path from "path";
6
3
  import type { CommandResult, ConfigType } from "./types/index.js";
7
4
  import { display } from "./display.js";
8
5
  import { confirm, isCancel, cancel } from "@clack/prompts";
9
6
 
10
- type PackageManager = "npm" | "yarn" | "pnpm";
11
-
12
7
  /**
13
- * Detect the package manager used in the project.
8
+ * Gets the required packages from the config file, transforms into a js object and with the options given
9
+ * it modifies the object and returns it
14
10
  */
15
11
 
16
- export function detectPackageManager(
17
- projectPath: string = process.cwd(),
18
- ): PackageManager | void {
19
- // Check for lock files in order of specificity
20
- if (fsd.existsSync(path.join(projectPath, "pnpm-lock.yaml"))) {
21
- return "pnpm";
22
- }
23
-
24
- if (fsd.existsSync(path.join(projectPath, "yarn.lock"))) {
25
- return "yarn";
26
- }
27
-
28
- if (fsd.existsSync(path.join(projectPath, "package-lock.json"))) {
29
- return "npm";
30
- }
31
-
32
- // Default to npm if no lock file found
33
- display("No Lock File Found", "error");
12
+ //Check if the value is an array of ConfigType objects
13
+ function isConfigTypeArray(value: unknown): value is ConfigType[] {
14
+ return (
15
+ Array.isArray(value) &&
16
+ value.every(
17
+ (item) =>
18
+ typeof item === "object" &&
19
+ item !== null &&
20
+ "packages" in item &&
21
+ Array.isArray((item as any).packages),
22
+ )
23
+ );
34
24
  }
35
25
 
36
- /**
37
- * Gets the required packages from the config file, transforms into a js object and with the options given
38
- * it modifies the object and returns it
39
- */
40
26
  export const getConfigObject = async (
41
27
  packages: string[],
42
28
  options?: any,
43
- ): Promise<ConfigType[] | CommandResult[]> => {
44
- if (!options.pkgJson) {
45
- const configPath = getConfigPath();
46
-
47
- //read config file content
48
- let configContent = "";
49
- try {
50
- configContent = await fs.readFile(configPath as string, "utf8");
51
- } catch (error) {
52
- display(
53
- `File not found ${error} Try updating the config file path`,
54
- "error",
55
- );
56
- }
57
-
58
- const configObject = JSON.parse(configContent);
59
- let result: ConfigType[] = Object.values(configObject);
60
-
61
- //filter the packages the user wants to install
62
- if (packages.length > 0) {
63
- result = packages
64
- .map((pkgName) => {
65
- const found = result.find((pkg) => pkg.name === pkgName);
66
- if (!found) {
67
- display(`Package '${pkgName}' not found in config`, "warning");
68
- }
69
- return found;
70
- })
71
- .filter((pkg) => pkg !== undefined);
72
- }
73
-
74
- /*
75
- * Config object modification with the options given
76
- */
77
- //Add command to previous configured commands (-A/-add-command)
78
- if (options.addCommand) {
79
- result.forEach((config) => {
80
- config.packages.forEach((pkg) => {
81
- pkg.command = pkg.interactive
82
- ? pkg.command
83
- : pkg.command + " " + options.addCommand;
84
- });
85
- });
86
- }
29
+ ): Promise<ConfigType[]> => {
30
+ const configPath = getConfigPath();
87
31
 
88
- //Dry run - Display commands before execution
89
- if (options.dryRun) {
90
- display("Dry Run:", "info");
91
- result.forEach((config) => {
92
- display(`Package name -> ${config.name}`, "info");
93
- config.packages.forEach((pkg) => {
94
- display(`running ${pkg.command}`, "info");
95
- });
96
- });
97
- const continuation = await confirm({
98
- message: "Continue?",
99
- initialValue: true,
100
- });
32
+ //read config file content
33
+ let configContent = "";
34
+ try {
35
+ configContent = await fs.readFile(configPath as string, "utf8");
36
+ } catch (error) {
37
+ display(
38
+ `File not found ${error} Try updating the config file path`,
39
+ "error",
40
+ );
41
+ }
101
42
 
102
- if (isCancel(continuation)) {
103
- cancel("Operation cancelled.");
104
- process.exit(0);
105
- }
43
+ const configObject = JSON.parse(configContent);
106
44
 
107
- if (!continuation) {
108
- display("Operation cancelled. ", "success");
109
- process.exit(0);
110
- }
111
- }
45
+ let result: ConfigType[] = [];
112
46
 
113
- return result;
47
+ if (isConfigTypeArray(Object.values(configObject))) {
48
+ result = Object.values(configObject);
114
49
  } else {
115
- //generate command for package.json
116
- const pm = detectPackageManager();
50
+ display("Invalid config file format", "error");
51
+ }
117
52
 
118
- const command = pm + " install";
53
+ //filter the packages the user wants to install
54
+ if (packages.length > 0 && result.length > 0) {
55
+ result = packages
56
+ .map((pkgName) => {
57
+ const found = result.find((pkg) => pkg.presetName === pkgName);
58
+ if (!found) {
59
+ display(`Package '${pkgName}' not found in config`, "warning");
60
+ }
61
+ return found;
62
+ })
63
+ .filter((pkg) => pkg !== undefined);
64
+ }
119
65
 
120
- const result: CommandResult[] = [
121
- {
122
- name: "package.json",
123
- interactive: [],
124
- nonInteractive: [command],
125
- },
126
- ];
66
+ /*
67
+ * Config object modification with the options given
68
+ */
69
+
70
+ //Add flags to previous configured flags (-A/-add-flags)
71
+ if (options.addFlags) {
72
+ result.forEach((config) => {
73
+ config.packages.forEach((pkg) => {
74
+ if (pkg.flags) {
75
+ pkg.flags.push(pkg.interactive ? "" : options.addFlags);
76
+ } else {
77
+ pkg.flags = [pkg.interactive ? "" : options.addFlags];
78
+ }
79
+ });
80
+ });
81
+ }
127
82
 
128
- return result;
83
+ //Dry run - Display commands before execution
84
+ if (options.dryRun) {
85
+ display("Dry Run:", "info");
86
+ result.forEach((config) => {
87
+ display(`Package name -> ${config.presetName}`, "info");
88
+ config.packages.forEach((pkg) => {
89
+ display(`running ${pkg.command}`, "info");
90
+ });
91
+ });
92
+ const continuation = await confirm({
93
+ message: "Continue?",
94
+ initialValue: true,
95
+ });
96
+
97
+ if (isCancel(continuation)) {
98
+ cancel("Operation cancelled.");
99
+ process.exit(0);
100
+ }
101
+
102
+ if (!continuation) {
103
+ display("Operation cancelled. ", "success");
104
+ process.exit(0);
105
+ }
129
106
  }
107
+
108
+ return result;
130
109
  };
131
110
 
132
111
  export const getConfigKeys = async (options: any) => {
@@ -176,7 +155,7 @@ export const getPackageDescription = async (packageName: string) => {
176
155
  const configObjectArray: ConfigType[] = Object.values(configObject);
177
156
 
178
157
  configObjectArray.forEach((configObject) => {
179
- if (configObject.name === packageName) {
158
+ if (configObject.presetName === packageName) {
180
159
  const description = !configObject.description
181
160
  ? "No description"
182
161
  : configObject.description;
package/src/display.ts CHANGED
@@ -22,6 +22,7 @@ export const display = (text: string, type: DisplayType) => {
22
22
  break;
23
23
 
24
24
  case "loading":
25
+ log.info(chalk.blue(text));
25
26
  s.start(text);
26
27
  return s; // Return spinner so it can be stopped later
27
28
 
package/src/index.ts CHANGED
@@ -14,10 +14,8 @@ const program = new Command();
14
14
 
15
15
  program
16
16
  .name("pm-auto")
17
- .version("1.0.6")
18
- .description(
19
- "A CLI tool to define and install your tech stack presets with one command.",
20
- );
17
+ .version("1.0.7")
18
+ .description("Automate your project setup with one command");
21
19
 
22
20
  program
23
21
  .command("config <path>")
@@ -33,10 +31,9 @@ program
33
31
  .description(
34
32
  "Install packages using the detected package manager (Aliases: add, i)",
35
33
  )
36
- .option("-p, --pkg-json", "Install packages from package.json")
37
34
  .option(
38
- "-A, --add-command <command>",
39
- "Add a custom command to all installation commands from config file",
35
+ "-A, --add-flags <flags>",
36
+ "Add custom flags to already defined flags from config file",
40
37
  )
41
38
  .option("-D, --dry-run", "Dry run - Display commands before execution")
42
39
  .action((packages, options) => {
@@ -62,12 +59,12 @@ program
62
59
  .command("list")
63
60
  .alias("ls")
64
61
  .description("List all packages from the config file")
65
- .option("-D, --desc", "Display packages description", false)
62
+ .option("--desc", "Display packages description", false)
66
63
  .action((options) => {
67
64
  getConfigKeys(options);
68
65
  });
69
66
 
70
- //Displaying config details
67
+ //Display a config description
71
68
  program
72
69
  .command("describe <package>")
73
70
  .alias("desc")
@@ -1,24 +1,14 @@
1
- import { buildCommands, buildUninstallCommands } from "./build_command.js";
1
+ import {
2
+ buildInstallCommands,
3
+ buildUninstallCommands,
4
+ } from "./build_command.js";
2
5
  import { getConfigObject } from "./config_reader.js";
3
6
  import { display } from "./display.js";
4
- import { install } from "./install.js";
7
+ import { runCommands } from "./run_commands.js";
5
8
  import type { ConfigType } from "./types/index.js";
6
9
  import { outro } from "@clack/prompts";
7
10
 
8
- //Check if the value is an array of ConfigType objects
9
- function isConfigTypeArray(value: unknown): value is ConfigType[] {
10
- return (
11
- Array.isArray(value) &&
12
- value.every(
13
- (item) =>
14
- typeof item === "object" &&
15
- item !== null &&
16
- "packages" in item &&
17
- Array.isArray((item as any).packages),
18
- )
19
- );
20
- }
21
-
11
+ //Controls installation and uninstallation of packages
22
12
  export const orchestrator = (
23
13
  command: string,
24
14
  packages: string[],
@@ -26,28 +16,23 @@ export const orchestrator = (
26
16
  ) => {
27
17
  if (command === "install") {
28
18
  display(
29
- `Installing packages... ${options.pkgJson ? "from package.json" : (packages as string[]).join(", ")}`,
19
+ `Installing packages... ${(packages as string[]).join(", ")}`,
30
20
  "info",
31
21
  );
32
-
22
+ const start = performance.now();
33
23
  getConfigObject(packages, options).then(async (config) => {
34
24
  if (config.length === 0) {
35
25
  display("No configuration found", "error");
36
26
  return;
37
27
  }
38
28
 
39
- if (isConfigTypeArray(config)) {
40
- const commands = buildCommands(config);
41
-
42
- await install(commands);
43
- outro("Done!");
29
+ const commands = buildInstallCommands(config);
44
30
 
45
- display("Packages installed successfully", "success");
46
- } else {
47
- await install(config);
48
- outro("Done!");
49
- display("Packages from package.json installed successfully", "success");
50
- }
31
+ await runCommands(commands);
32
+ outro("Done!");
33
+ const end = performance.now();
34
+ display(`Installation took ${Math.round((end - start) / 1000)}s`, "info");
35
+ display("Packages installed successfully", "success");
51
36
  });
52
37
  } else {
53
38
  display(
@@ -55,19 +40,19 @@ export const orchestrator = (
55
40
  "info",
56
41
  );
57
42
 
43
+ const start = performance.now();
58
44
  getConfigObject(packages, options).then(async (config) => {
59
45
  if (config.length === 0) {
60
46
  display("No configuration found", "error");
61
47
  return;
62
48
  }
63
49
 
64
- if (isConfigTypeArray(config)) {
65
- const commands = buildUninstallCommands(config);
66
- await install(commands);
67
- outro("Done!");
68
-
69
- display("Packages uninstalled successfully", "success");
70
- }
50
+ const commands = buildUninstallCommands(config);
51
+ await runCommands(commands);
52
+ outro("Done!");
53
+ const end = performance.now();
54
+ display(`Uninstallation took ${end - start}ms`, "info");
55
+ display("Packages uninstalled successfully", "success");
71
56
  });
72
57
  }
73
58
  };
@@ -26,13 +26,13 @@ async function runCommand(command: string, interactive: boolean = false) {
26
26
  }
27
27
 
28
28
  /**
29
- * Install all commands
29
+ * Run all commands
30
30
  */
31
- export async function install(commands: CommandResult[]) {
31
+ export async function runCommands(commands: CommandResult[]) {
32
32
  try {
33
33
  for (const command of commands) {
34
34
  // Wait for all interactive commands to finish first
35
- if (command.interactive) {
35
+ if (command.interactive.length > 0) {
36
36
  for (const interactiveCommand of command.interactive) {
37
37
  display(`Running interactive command: ${interactiveCommand}`, "info");
38
38
  await runCommand(interactiveCommand, true);
@@ -1,17 +1,26 @@
1
1
  export interface ConfigType {
2
- name: string;
2
+ presetName: string;
3
3
  description?: string;
4
4
  packageManager: string;
5
- packages: { command: string; interactive: boolean }[];
5
+ packages: {
6
+ command: string;
7
+ interactive: boolean;
8
+ dev?: boolean;
9
+ flags?: string[];
10
+ version?: string;
11
+ }[];
6
12
  }
7
13
 
8
14
  export interface PackageType {
9
15
  command: string;
10
16
  interactive: boolean;
17
+ dev?: boolean;
18
+ flags?: string[];
19
+ version?: string;
11
20
  }
12
21
 
13
22
  export interface CommandResult {
14
- name: string;
23
+ presetName: string;
15
24
  interactive: string[];
16
25
  nonInteractive: string[];
17
26
  }