pm-auto 1.0.5 → 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.
- package/README.md +6 -3
- package/config.json +45 -0
- package/dist/build_command.d.ts +6 -1
- package/dist/build_command.d.ts.map +1 -1
- package/dist/build_command.js +66 -13
- package/dist/build_command.js.map +1 -1
- package/dist/config_path.d.ts +1 -0
- package/dist/config_path.d.ts.map +1 -1
- package/dist/config_path.js +60 -2
- package/dist/config_path.js.map +1 -1
- package/dist/config_reader.d.ts +2 -12
- package/dist/config_reader.d.ts.map +1 -1
- package/dist/config_reader.js +76 -92
- package/dist/config_reader.js.map +1 -1
- package/dist/display.d.ts +5 -0
- package/dist/display.d.ts.map +1 -1
- package/dist/display.js +2 -1
- package/dist/display.js.map +1 -1
- package/dist/index.js +6 -7
- package/dist/index.js.map +1 -1
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +18 -28
- package/dist/orchestrator.js.map +1 -1
- package/dist/run_commands.d.ts +6 -0
- package/dist/run_commands.d.ts.map +1 -0
- package/dist/{install.js → run_commands.js} +10 -7
- package/dist/run_commands.js.map +1 -0
- package/dist/types/index.d.ts +8 -2
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +4 -2
- package/src/build_command.ts +78 -13
- package/src/config_path.ts +63 -2
- package/src/config_reader.ts +90 -110
- package/src/display.ts +2 -2
- package/src/index.ts +8 -13
- package/src/orchestrator.ts +21 -34
- package/src/{install.ts → run_commands.ts} +10 -6
- package/src/types/index.ts +12 -3
- package/tests/build_command.test.ts +240 -30
- package/tests/config_reader.test.ts +51 -92
- package/tests/display.test.ts +42 -34
- package/tests/{install.test.ts → run_command.test.ts} +23 -23
- package/dist/install.d.ts +0 -6
- package/dist/install.d.ts.map +0 -1
- package/dist/install.js.map +0 -1
- package/test.json +0 -87
package/src/config_reader.ts
CHANGED
|
@@ -1,131 +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
|
-
*
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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[]
|
|
44
|
-
|
|
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
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
message: "Continue with installation?",
|
|
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
|
-
|
|
103
|
-
cancel("Operation cancelled.");
|
|
104
|
-
process.exit(0);
|
|
105
|
-
}
|
|
43
|
+
const configObject = JSON.parse(configContent);
|
|
106
44
|
|
|
107
|
-
|
|
108
|
-
display("Installation cancelled ", "success");
|
|
109
|
-
}
|
|
110
|
-
}
|
|
45
|
+
let result: ConfigType[] = [];
|
|
111
46
|
|
|
112
|
-
|
|
47
|
+
if (isConfigTypeArray(Object.values(configObject))) {
|
|
48
|
+
result = Object.values(configObject);
|
|
113
49
|
} else {
|
|
114
|
-
|
|
115
|
-
|
|
50
|
+
display("Invalid config file format", "error");
|
|
51
|
+
}
|
|
116
52
|
|
|
117
|
-
|
|
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
|
+
}
|
|
65
|
+
|
|
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
|
+
}
|
|
118
82
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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
|
+
}
|
|
126
101
|
|
|
127
|
-
|
|
102
|
+
if (!continuation) {
|
|
103
|
+
display("Operation cancelled. ", "success");
|
|
104
|
+
process.exit(0);
|
|
105
|
+
}
|
|
128
106
|
}
|
|
107
|
+
|
|
108
|
+
return result;
|
|
129
109
|
};
|
|
130
110
|
|
|
131
111
|
export const getConfigKeys = async (options: any) => {
|
|
@@ -172,13 +152,13 @@ export const getPackageDescription = async (packageName: string) => {
|
|
|
172
152
|
}
|
|
173
153
|
|
|
174
154
|
const configObject = JSON.parse(configContent);
|
|
175
|
-
|
|
155
|
+
const configObjectArray: ConfigType[] = Object.values(configObject);
|
|
176
156
|
|
|
177
|
-
|
|
178
|
-
if (
|
|
179
|
-
const description = !configObject
|
|
157
|
+
configObjectArray.forEach((configObject) => {
|
|
158
|
+
if (configObject.presetName === packageName) {
|
|
159
|
+
const description = !configObject.description
|
|
180
160
|
? "No description"
|
|
181
|
-
: configObject
|
|
161
|
+
: configObject.description;
|
|
182
162
|
display(`${packageName} - ${description}`, "info");
|
|
183
163
|
}
|
|
184
164
|
});
|
package/src/display.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { log, spinner } from "@clack/prompts";
|
|
|
2
2
|
import chalk from "chalk";
|
|
3
3
|
|
|
4
4
|
type DisplayType = "error" | "success" | "warning" | "info" | "loading" | "";
|
|
5
|
-
|
|
5
|
+
export const s = spinner();
|
|
6
6
|
export const display = (text: string, type: DisplayType) => {
|
|
7
7
|
switch (type) {
|
|
8
8
|
case "error":
|
|
@@ -22,7 +22,7 @@ export const display = (text: string, type: DisplayType) => {
|
|
|
22
22
|
break;
|
|
23
23
|
|
|
24
24
|
case "loading":
|
|
25
|
-
|
|
25
|
+
log.info(chalk.blue(text));
|
|
26
26
|
s.start(text);
|
|
27
27
|
return s; // Return spinner so it can be stopped later
|
|
28
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.
|
|
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-
|
|
39
|
-
"Add
|
|
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) => {
|
|
@@ -51,10 +48,8 @@ program
|
|
|
51
48
|
.description(
|
|
52
49
|
"Remove packages using the detected package manager (Aliases: remove, u, un)",
|
|
53
50
|
)
|
|
54
|
-
.option(
|
|
55
|
-
|
|
56
|
-
"Add a custom command to all installation commands from config file",
|
|
57
|
-
)
|
|
51
|
+
.option("-D, --dry-run", "Dry run - Display commands before execution")
|
|
52
|
+
|
|
58
53
|
.action((packages, options) => {
|
|
59
54
|
orchestrator("uninstall", packages, options);
|
|
60
55
|
});
|
|
@@ -64,12 +59,12 @@ program
|
|
|
64
59
|
.command("list")
|
|
65
60
|
.alias("ls")
|
|
66
61
|
.description("List all packages from the config file")
|
|
67
|
-
.option("
|
|
62
|
+
.option("--desc", "Display packages description", false)
|
|
68
63
|
.action((options) => {
|
|
69
64
|
getConfigKeys(options);
|
|
70
65
|
});
|
|
71
66
|
|
|
72
|
-
//
|
|
67
|
+
//Display a config description
|
|
73
68
|
program
|
|
74
69
|
.command("describe <package>")
|
|
75
70
|
.alias("desc")
|
package/src/orchestrator.ts
CHANGED
|
@@ -1,24 +1,14 @@
|
|
|
1
|
-
import {
|
|
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 {
|
|
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
|
-
//
|
|
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,27 +16,23 @@ export const orchestrator = (
|
|
|
26
16
|
) => {
|
|
27
17
|
if (command === "install") {
|
|
28
18
|
display(
|
|
29
|
-
`Installing packages... ${
|
|
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
|
-
|
|
40
|
-
const commands = buildCommands(config);
|
|
29
|
+
const commands = buildInstallCommands(config);
|
|
41
30
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
display("Packages from package.json installed successfully", "success");
|
|
48
|
-
outro("Done!");
|
|
49
|
-
}
|
|
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");
|
|
50
36
|
});
|
|
51
37
|
} else {
|
|
52
38
|
display(
|
|
@@ -54,18 +40,19 @@ export const orchestrator = (
|
|
|
54
40
|
"info",
|
|
55
41
|
);
|
|
56
42
|
|
|
43
|
+
const start = performance.now();
|
|
57
44
|
getConfigObject(packages, options).then(async (config) => {
|
|
58
45
|
if (config.length === 0) {
|
|
59
46
|
display("No configuration found", "error");
|
|
60
47
|
return;
|
|
61
48
|
}
|
|
62
49
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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");
|
|
69
56
|
});
|
|
70
57
|
}
|
|
71
58
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { execa } from "execa";
|
|
2
2
|
import type { CommandResult } from "./types/index.js";
|
|
3
|
-
import { display } from "./display.js";
|
|
3
|
+
import { display, s } from "./display.js";
|
|
4
4
|
|
|
5
5
|
async function runCommand(command: string, interactive: boolean = false) {
|
|
6
6
|
try {
|
|
@@ -11,6 +11,8 @@ async function runCommand(command: string, interactive: boolean = false) {
|
|
|
11
11
|
stdio: "inherit",
|
|
12
12
|
});
|
|
13
13
|
} else {
|
|
14
|
+
s.stop();
|
|
15
|
+
|
|
14
16
|
await execa(commandName as string, args, {
|
|
15
17
|
stdio: "inherit",
|
|
16
18
|
});
|
|
@@ -24,13 +26,13 @@ async function runCommand(command: string, interactive: boolean = false) {
|
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
/**
|
|
27
|
-
*
|
|
29
|
+
* Run all commands
|
|
28
30
|
*/
|
|
29
|
-
export async function
|
|
31
|
+
export async function runCommands(commands: CommandResult[]) {
|
|
30
32
|
try {
|
|
31
33
|
for (const command of commands) {
|
|
32
34
|
// Wait for all interactive commands to finish first
|
|
33
|
-
if (command.interactive) {
|
|
35
|
+
if (command.interactive.length > 0) {
|
|
34
36
|
for (const interactiveCommand of command.interactive) {
|
|
35
37
|
display(`Running interactive command: ${interactiveCommand}`, "info");
|
|
36
38
|
await runCommand(interactiveCommand, true);
|
|
@@ -40,8 +42,10 @@ export async function install(commands: CommandResult[]) {
|
|
|
40
42
|
// Then run non-interactive
|
|
41
43
|
if (command.nonInteractive.length > 0) {
|
|
42
44
|
// For non-interactive, we show a spinner
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
for (let i = 0; i < command.nonInteractive.length; i++) {
|
|
46
|
+
display(`Running command: ${command.nonInteractive[i]}`, "loading");
|
|
47
|
+
await runCommand(command.nonInteractive[i] as string, false);
|
|
48
|
+
}
|
|
45
49
|
}
|
|
46
50
|
}
|
|
47
51
|
} catch (error: any) {
|
package/src/types/index.ts
CHANGED
|
@@ -1,17 +1,26 @@
|
|
|
1
1
|
export interface ConfigType {
|
|
2
|
-
|
|
2
|
+
presetName: string;
|
|
3
3
|
description?: string;
|
|
4
4
|
packageManager: string;
|
|
5
|
-
packages: {
|
|
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
|
-
|
|
23
|
+
presetName: string;
|
|
15
24
|
interactive: string[];
|
|
16
25
|
nonInteractive: string[];
|
|
17
26
|
}
|