evophp 1.0.30 → 1.1.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.
- package/bin/evophp.js +15 -0
- package/commands/dependencies.js +80 -0
- package/commands/help.js +70 -0
- package/commands/init.js +57 -0
- package/commands/install.js +72 -0
- package/commands/new.js +110 -0
- package/commands/uninstall.js +81 -0
- package/package.json +24 -17
- package/utils/config.js +20 -0
- package/utils/dependencies.js +33 -0
- package/utils/edit.js +42 -0
- package/utils/git.js +14 -0
- package/utils/github.js +0 -0
- package/utils/helpers.js +130 -0
- package/utils/logger.js +6 -0
- package/utils/validate.js +16 -0
- package/helpers.js +0 -101
- package/install-dependencies.js +0 -149
- package/install-plugin.js +0 -118
- package/installer.js +0 -223
- package/new-plugin.js +0 -298
- package/uninstall.js +0 -65
package/bin/evophp.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const yargs = require("yargs/yargs")(process.argv.slice(2));
|
|
4
|
+
const { hideBin } = require("yargs/helpers");
|
|
5
|
+
|
|
6
|
+
yargs(hideBin(process.argv))
|
|
7
|
+
.command(require("../commands/new"))
|
|
8
|
+
.command(require("../commands/init"))
|
|
9
|
+
.command(require("../commands/uninstall"))
|
|
10
|
+
.command(require("../commands/dependencies"))
|
|
11
|
+
.command(require("../commands/help"))
|
|
12
|
+
.demandCommand(1, "Please specify a valid command. Use --help to see available commands.")
|
|
13
|
+
.help()
|
|
14
|
+
.argv;
|
|
15
|
+
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const { execSync } = require("child_process");
|
|
4
|
+
const { readLineAsync } = require("../utils/helpers");
|
|
5
|
+
const log = require("../utils/logger");
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
command: "install-dependencies <plugin> [--dev|--composer]",
|
|
9
|
+
aliases: ["d"],
|
|
10
|
+
describe: "Add and install plugin or theme dependencies",
|
|
11
|
+
|
|
12
|
+
builder: yargs =>
|
|
13
|
+
yargs
|
|
14
|
+
.positional("plugin", { describe: "Plugin or theme name", type: "string" })
|
|
15
|
+
.option("dev", { describe: "Install as dev dependency (JS)", type: "boolean" })
|
|
16
|
+
.option("composer", { describe: "Use composer for PHP", type: "boolean" }),
|
|
17
|
+
|
|
18
|
+
handler: async ({ plugin, dev, composer }) => {
|
|
19
|
+
try {
|
|
20
|
+
const depType = dev ? "dev" : "prod";
|
|
21
|
+
|
|
22
|
+
const isPHP = !!composer;
|
|
23
|
+
const baseDir = isPHP
|
|
24
|
+
? path.join("Public", "Modules", plugin)
|
|
25
|
+
: path.join("EvoJsDev", "Modules", plugin);
|
|
26
|
+
|
|
27
|
+
if (!fs.existsSync(baseDir)) {
|
|
28
|
+
log.error(`Plugin not found at ${baseDir}`);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const dependenciesFile = path.join(baseDir, "dependencies.json");
|
|
33
|
+
let dependencies = fs.existsSync(dependenciesFile)
|
|
34
|
+
? JSON.parse(fs.readFileSync(dependenciesFile, "utf-8"))
|
|
35
|
+
: {};
|
|
36
|
+
|
|
37
|
+
log.info(`Existing ${isPHP ? "PHP" : "JS"} dependencies:`);
|
|
38
|
+
log.info("Production:", dependencies.prod || "None");
|
|
39
|
+
if (!isPHP) log.info("Development:", dependencies.dev || "None");
|
|
40
|
+
|
|
41
|
+
const additionalDeps = await readLineAsync(
|
|
42
|
+
`Enter additional ${depType} dependencies (space separated): `
|
|
43
|
+
);
|
|
44
|
+
const newDeps = additionalDeps
|
|
45
|
+
.split(" ")
|
|
46
|
+
.map(dep => dep.trim())
|
|
47
|
+
.filter(Boolean);
|
|
48
|
+
|
|
49
|
+
if (newDeps.length === 0) {
|
|
50
|
+
log.warn("No dependencies provided.");
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Merge and deduplicate
|
|
55
|
+
const depField = isPHP || depType === "prod" ? "prod" : "dev";
|
|
56
|
+
dependencies[depField] = (
|
|
57
|
+
(dependencies[depField] || "") + " " + newDeps.join(" ")
|
|
58
|
+
)
|
|
59
|
+
.trim()
|
|
60
|
+
.split(" ")
|
|
61
|
+
.filter((value, i, arr) => arr.indexOf(value) === i)
|
|
62
|
+
.join(" ");
|
|
63
|
+
|
|
64
|
+
fs.writeFileSync(dependenciesFile, JSON.stringify(dependencies, null, 2));
|
|
65
|
+
log.success("Updated dependencies.json");
|
|
66
|
+
|
|
67
|
+
// Install
|
|
68
|
+
const installCmd = isPHP
|
|
69
|
+
? `composer require ${newDeps.join(" ")}`
|
|
70
|
+
: `npm install ${newDeps.join(" ")} ${dev ? "--save-dev" : "--save"}`;
|
|
71
|
+
|
|
72
|
+
log.info("Installing dependencies...");
|
|
73
|
+
execSync(installCmd, { stdio: "inherit" });
|
|
74
|
+
log.success("Installation complete.");
|
|
75
|
+
} catch (err) {
|
|
76
|
+
log.error("Error installing dependencies: " + err.message);
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
};
|
package/commands/help.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
command: "help",
|
|
3
|
+
aliases: ["h"],
|
|
4
|
+
describe: "Show all available EvoPHP CLI commands",
|
|
5
|
+
|
|
6
|
+
handler: () => {
|
|
7
|
+
console.log(`
|
|
8
|
+
==========================================
|
|
9
|
+
EvoPHP CLI - Help Guide
|
|
10
|
+
==========================================
|
|
11
|
+
|
|
12
|
+
Initialization:
|
|
13
|
+
evophp init [project-name]
|
|
14
|
+
→ Initialize a new Evolution PHP project.
|
|
15
|
+
→ Aliases: none
|
|
16
|
+
→ Example: evophp init my-project
|
|
17
|
+
|
|
18
|
+
Plugin/Theme Creation:
|
|
19
|
+
evophp new plugin <author>/<name>
|
|
20
|
+
evophp n plugin <author>/<name>
|
|
21
|
+
→ Create a new plugin from template.
|
|
22
|
+
→ Aliases: new → n
|
|
23
|
+
→ Example: evophp n plugin johndoe/exampleplugin
|
|
24
|
+
|
|
25
|
+
evophp new theme <author>/<name>
|
|
26
|
+
evophp n theme <author>/<name>
|
|
27
|
+
→ Create a new theme from template.
|
|
28
|
+
|
|
29
|
+
Plugin/Theme Installation:
|
|
30
|
+
evophp install plugin <author>/<name>
|
|
31
|
+
evophp i plugin <author>/<name>
|
|
32
|
+
→ Install a plugin from GitHub.
|
|
33
|
+
→ Aliases: install → i
|
|
34
|
+
|
|
35
|
+
evophp install theme <author>/<name>
|
|
36
|
+
evophp i theme <author>/<name>
|
|
37
|
+
→ Install a theme from GitHub.
|
|
38
|
+
|
|
39
|
+
Plugin/Theme Uninstallation:
|
|
40
|
+
evophp uninstall plugin <name>
|
|
41
|
+
evophp u plugin <name>
|
|
42
|
+
→ Remove installed plugin.
|
|
43
|
+
→ Aliases: uninstall → u
|
|
44
|
+
|
|
45
|
+
evophp uninstall theme <name>
|
|
46
|
+
evophp u theme <name>
|
|
47
|
+
→ Remove installed theme.
|
|
48
|
+
|
|
49
|
+
Dependency Management:
|
|
50
|
+
evophp install-dependencies <plugin>
|
|
51
|
+
evophp d <plugin> [--dev|--composer]
|
|
52
|
+
→ Add and install dependencies.
|
|
53
|
+
→ JS dev: --dev
|
|
54
|
+
→ PHP: --composer
|
|
55
|
+
→ Aliases: install-dependencies → d
|
|
56
|
+
|
|
57
|
+
General:
|
|
58
|
+
evophp help
|
|
59
|
+
evophp h
|
|
60
|
+
→ Show this help guide.
|
|
61
|
+
→ Aliases: help → h
|
|
62
|
+
|
|
63
|
+
==========================================
|
|
64
|
+
Tip: Use --help after any command
|
|
65
|
+
for command-specific usage.
|
|
66
|
+
==========================================
|
|
67
|
+
`);
|
|
68
|
+
process.exit(0);
|
|
69
|
+
}
|
|
70
|
+
};
|
package/commands/init.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const { execSync } = require("child_process");
|
|
4
|
+
const { readLineAsync } = require("../utils/helpers");
|
|
5
|
+
const log = require("../utils/logger");
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
command: "init [name]",
|
|
9
|
+
describe: "Initialize a new EvoPHP project",
|
|
10
|
+
|
|
11
|
+
builder: yargs =>
|
|
12
|
+
yargs
|
|
13
|
+
.positional("name", {
|
|
14
|
+
describe: "Project folder name (optional)",
|
|
15
|
+
type: "string",
|
|
16
|
+
default: "",
|
|
17
|
+
}),
|
|
18
|
+
|
|
19
|
+
handler: async ({ name }) => {
|
|
20
|
+
try {
|
|
21
|
+
if (!name) {
|
|
22
|
+
name = await readLineAsync("Enter the name of the project: ");
|
|
23
|
+
if (!name.trim()) {
|
|
24
|
+
log.error("You must enter a valid project name.");
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const repoUrl = "https://github.com/kinsokafor/evolution.git";
|
|
30
|
+
const projectPath = path.join(process.cwd(), name);
|
|
31
|
+
|
|
32
|
+
log.info(`Cloning Evolution repo to "${name}"...`);
|
|
33
|
+
execSync(`git clone ${repoUrl} ${name}`, { stdio: "inherit" });
|
|
34
|
+
|
|
35
|
+
process.chdir(projectPath);
|
|
36
|
+
|
|
37
|
+
log.info(`Running bootstrap script: node evolution ${name}`);
|
|
38
|
+
execSync(`node evolution ${name}`, { stdio: "inherit" });
|
|
39
|
+
|
|
40
|
+
if (fs.existsSync("composer.json")) {
|
|
41
|
+
log.info("Installing Composer dependencies...");
|
|
42
|
+
execSync("composer install", { stdio: "inherit" });
|
|
43
|
+
} else {
|
|
44
|
+
log.info("No composer.json found. Skipping Composer installation.");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
log.info("Installing NPM dependencies...");
|
|
48
|
+
execSync("npm install", { stdio: "inherit" });
|
|
49
|
+
|
|
50
|
+
log.success("Project setup complete!");
|
|
51
|
+
log.info(`Navigate into your project:\n cd ${name}`);
|
|
52
|
+
} catch (err) {
|
|
53
|
+
log.error("Project initialization failed: " + err.message);
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const { execSync } = require('child_process');
|
|
4
|
+
const { readLineAsync, splitPluginName, mergeConfig } = require('../utils/helpers');
|
|
5
|
+
const { cloneRepo } = require('../utils/git');
|
|
6
|
+
const { installDependencies } = require('../utils/dependencies');
|
|
7
|
+
const log = require('../utils/logger');
|
|
8
|
+
|
|
9
|
+
module.exports = {
|
|
10
|
+
command: 'install [type] [name]',
|
|
11
|
+
aliases: ['i'],
|
|
12
|
+
describe: 'Install a plugin or theme',
|
|
13
|
+
builder: yargs => yargs
|
|
14
|
+
.positional('type', { describe: 'plugin or theme', type: 'string' })
|
|
15
|
+
.positional('name', { describe: 'author/plugin-name', type: 'string' }),
|
|
16
|
+
|
|
17
|
+
handler: async ({ type, name }) => {
|
|
18
|
+
try {
|
|
19
|
+
// Prompt if missing
|
|
20
|
+
if (!type || !['plugin', 'theme'].includes(type.toLowerCase())) {
|
|
21
|
+
type = await readLineAsync("What are you installing? (plugin/theme): ");
|
|
22
|
+
type = type.toLowerCase();
|
|
23
|
+
if (!['plugin', 'theme'].includes(type)) {
|
|
24
|
+
log.error("Invalid type.");
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!name) {
|
|
30
|
+
name = await readLineAsync(`Enter the ${type} name (e.g., johndoe/example${type}): `);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const [author, itemName] = await splitPluginName(name);
|
|
34
|
+
|
|
35
|
+
const paths = type === 'plugin'
|
|
36
|
+
? [path.join('Public', 'Modules', itemName), path.join('EvoJsDev', 'Modules', itemName)]
|
|
37
|
+
: [path.join('Public', 'Themes', itemName)];
|
|
38
|
+
|
|
39
|
+
// Check existing
|
|
40
|
+
for (const p of paths) {
|
|
41
|
+
if (fs.existsSync(p)) {
|
|
42
|
+
log.warn(`${type} "${itemName}" already exists at ${p}`);
|
|
43
|
+
process.exit(0);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
log.info(`Installing ${type} "${itemName}" by ${author}...`);
|
|
48
|
+
|
|
49
|
+
if (type === 'plugin') {
|
|
50
|
+
await cloneRepo(`https://github.com/${author}/${itemName}.git`, paths[0]);
|
|
51
|
+
await cloneRepo(`https://github.com/${author}/${itemName}.js.git`, paths[1]);
|
|
52
|
+
|
|
53
|
+
const configFile = path.resolve(`./EvoJsDev/Modules/${itemName}/config.json`);
|
|
54
|
+
if (fs.existsSync(configFile)) {
|
|
55
|
+
const pluginConfig = require(configFile);
|
|
56
|
+
mergeConfig(pluginConfig);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
await installDependencies(paths[1], 'js');
|
|
60
|
+
await installDependencies(paths[0], 'php');
|
|
61
|
+
|
|
62
|
+
} else if (type === 'theme') {
|
|
63
|
+
await cloneRepo(`https://github.com/${author}/${itemName}.git`, paths[0]);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
log.success(`The ${type} "${itemName}" has been installed successfully.`);
|
|
67
|
+
} catch (err) {
|
|
68
|
+
log.error(`Install failed: ${err.message}`);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
};
|
package/commands/new.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const { readLineAsync, splitPluginName, mergeConfig } = require("../utils/helpers");
|
|
4
|
+
const { getUserData, createGitHubRepo } = require("../utils/github");
|
|
5
|
+
const { cloneRepository } = require("../utils/git");
|
|
6
|
+
const { editFile, renameFile } = require("../utils/edit");
|
|
7
|
+
const { test } = require("../utils/validate");
|
|
8
|
+
const log = require("../utils/logger");
|
|
9
|
+
require("dotenv").config({ path: "./.env.development" });
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
command: "new <type> <author>/<name>",
|
|
13
|
+
aliases: ["n"],
|
|
14
|
+
describe: "Create a new plugin or theme from template",
|
|
15
|
+
builder: yargs =>
|
|
16
|
+
yargs
|
|
17
|
+
.positional("type", { describe: "plugin or theme", type: "string" })
|
|
18
|
+
.positional("author/name", { describe: "GitHub format name", type: "string" }),
|
|
19
|
+
|
|
20
|
+
handler: async ({ type, name }) => {
|
|
21
|
+
try {
|
|
22
|
+
const gitHubToken = process.env.GITHUB_TOKEN || await readLineAsync("Enter GitHub PAT: ");
|
|
23
|
+
type = type.toLowerCase();
|
|
24
|
+
|
|
25
|
+
if (!["plugin", "theme"].includes(type)) {
|
|
26
|
+
log.error("Invalid type. Must be plugin or theme.");
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const [author, pluginName] = await splitPluginName(name);
|
|
31
|
+
const userData = await getUserData(gitHubToken);
|
|
32
|
+
if (userData.login !== author) {
|
|
33
|
+
log.error(`Token belongs to ${userData.login}, expected ${author}`);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
log.info(`Authenticated as ${userData.login}`);
|
|
38
|
+
|
|
39
|
+
if (type === "plugin") {
|
|
40
|
+
const entry = await setupPlugin(gitHubToken, author, pluginName);
|
|
41
|
+
log.success(`Plugin "${pluginName}" created with entry "${entry}"`);
|
|
42
|
+
} else {
|
|
43
|
+
await setupTheme(gitHubToken, author, pluginName);
|
|
44
|
+
log.success(`Theme "${pluginName}" created`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
} catch (err) {
|
|
48
|
+
log.error(`Creation failed: ${err.message}`);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
async function setupPlugin(token, author, pluginName) {
|
|
55
|
+
const entry = await setupPluginRepo(token, author, pluginName);
|
|
56
|
+
const pluginPrefix = entry.replace("Main", "");
|
|
57
|
+
|
|
58
|
+
await editFile(`./Public/Modules/${pluginName}/Routes.php`, {
|
|
59
|
+
pluginName, entry, entryURI: entry.toLowerCase(), pluginPrefix
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const controllerPath = `./Public/Modules/${pluginName}/Controller.php`;
|
|
63
|
+
if (fs.existsSync(controllerPath)) {
|
|
64
|
+
await editFile(controllerPath, { pluginName, pluginPrefix });
|
|
65
|
+
await renameFile(controllerPath, `./Public/Modules/${pluginName}/${pluginPrefix}Controller.php`);
|
|
66
|
+
await renameFile(`./Public/Modules/${pluginName}/Views/Entry`, `./Public/Modules/${pluginName}/Views/${entry}`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return entry;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function setupPluginRepo(token, author, pluginName) {
|
|
73
|
+
await createGitHubRepo(token, 'kinsokafor/EvoPlugin', pluginName);
|
|
74
|
+
await cloneRepository(author, pluginName, path.join('Public', 'Modules', pluginName));
|
|
75
|
+
|
|
76
|
+
await createGitHubRepo(token, 'kinsokafor/EvoPlugin.js', `${pluginName}.js`);
|
|
77
|
+
await cloneRepository(author, `${pluginName}.js`, path.join('EvoJsDev', 'Modules', pluginName));
|
|
78
|
+
|
|
79
|
+
const pluginPrefix = await getValidatedInput("Enter Plugin Prefix?", 3, true).then(x => x.toUpperCase());
|
|
80
|
+
const entryURI = await getValidatedInput("Entry URI?", 20).then(x => x.toLowerCase());
|
|
81
|
+
const entry = pluginPrefix + "Main";
|
|
82
|
+
|
|
83
|
+
await editFile(`./EvoJsDev/Modules/${pluginName}/config.json`, { pluginName, entry });
|
|
84
|
+
await renameFile(`./EvoJsDev/Modules/${pluginName}/Entry`, `./EvoJsDev/Modules/${pluginName}/${entry}`);
|
|
85
|
+
|
|
86
|
+
const configPath = `./EvoJsDev/Modules/${pluginName}/config.json`;
|
|
87
|
+
if (fs.existsSync(configPath)) {
|
|
88
|
+
const pluginConfig = require(path.resolve(configPath));
|
|
89
|
+
mergeConfig(pluginConfig);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return entry;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async function setupTheme(token, author, pluginName) {
|
|
96
|
+
await createGitHubRepo(token, 'kinsokafor/EvoTheme', pluginName);
|
|
97
|
+
await cloneRepository(author, pluginName, path.join('Public', 'Themes', pluginName));
|
|
98
|
+
|
|
99
|
+
await editFile(`./Public/Themes/${pluginName}/Data/index.data.php`, { pluginName });
|
|
100
|
+
await editFile(`./Public/Themes/${pluginName}/Data/login.data.php`, { pluginName });
|
|
101
|
+
await editFile(`./Public/Themes/${pluginName}/Views/index.blade.php`, { pluginName });
|
|
102
|
+
await editFile(`./Public/Themes/${pluginName}/Views/login.blade.php`, { pluginName });
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function getValidatedInput(label, maxLength, caps = false) {
|
|
106
|
+
let input = await readLineAsync(label);
|
|
107
|
+
while (!test(input, maxLength)) input = await readLineAsync(label);
|
|
108
|
+
input = input.trim().replaceAll(" ", "");
|
|
109
|
+
return caps ? input.toUpperCase() : input.toLowerCase();
|
|
110
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const rimraf = require("rimraf");
|
|
4
|
+
const editJsonFile = require("edit-json-file");
|
|
5
|
+
const { readLineAsync } = require("../utils/helpers");
|
|
6
|
+
const log = require("../utils/logger");
|
|
7
|
+
|
|
8
|
+
module.exports = {
|
|
9
|
+
command: "uninstall [type] [name]",
|
|
10
|
+
aliases: ["u"],
|
|
11
|
+
describe: "Uninstall a plugin or theme",
|
|
12
|
+
|
|
13
|
+
builder: yargs =>
|
|
14
|
+
yargs
|
|
15
|
+
.positional("type", { describe: "plugin or theme", type: "string" })
|
|
16
|
+
.positional("name", { describe: "The plugin or theme name", type: "string" }),
|
|
17
|
+
|
|
18
|
+
handler: async ({ type, name }) => {
|
|
19
|
+
try {
|
|
20
|
+
// Prompt type if missing
|
|
21
|
+
if (!type || !["plugin", "theme"].includes(type.toLowerCase())) {
|
|
22
|
+
type = await readLineAsync("What are you uninstalling? (plugin/theme): ");
|
|
23
|
+
type = type.toLowerCase();
|
|
24
|
+
if (!["plugin", "theme"].includes(type)) {
|
|
25
|
+
log.error("Invalid type. Must be 'plugin' or 'theme'.");
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Prompt name if missing
|
|
31
|
+
if (!name) {
|
|
32
|
+
name = await readLineAsync(`Enter the ${type} name (e.g., example${type}): `);
|
|
33
|
+
if (!name) {
|
|
34
|
+
log.error("You must provide a name.");
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const paths =
|
|
40
|
+
type === "plugin"
|
|
41
|
+
? [path.join("Public", "Modules", name), path.join("EvoJsDev", "Modules", name)]
|
|
42
|
+
: [path.join("Public", "Themes", name)];
|
|
43
|
+
|
|
44
|
+
const existing = paths.filter(fs.existsSync);
|
|
45
|
+
|
|
46
|
+
if (existing.length === 0) {
|
|
47
|
+
log.warn(`No matching ${type} found for "${name}".`);
|
|
48
|
+
process.exit(0);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
log.info(`Preparing to uninstall ${type} "${name}" from:`);
|
|
52
|
+
existing.forEach(p => log.info(" - " + p));
|
|
53
|
+
|
|
54
|
+
const confirm = await readLineAsync("Are you sure you want to proceed? (y/n): ");
|
|
55
|
+
if (!["y", "yes"].includes(confirm.trim().toLowerCase())) {
|
|
56
|
+
log.warn("Uninstallation cancelled.");
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
for (const dir of existing) {
|
|
61
|
+
rimraf.sync(dir);
|
|
62
|
+
log.success(`Deleted: ${dir}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (type === "plugin") {
|
|
66
|
+
const configPath = path.resolve("config.json");
|
|
67
|
+
if (fs.existsSync(configPath)) {
|
|
68
|
+
let file = editJsonFile(configPath);
|
|
69
|
+
file.unset(`modules.${name}`);
|
|
70
|
+
file.save();
|
|
71
|
+
log.success(`Removed '${name}' from config.json`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
log.success(`The ${type} "${name}" has been uninstalled successfully.`);
|
|
76
|
+
} catch (err) {
|
|
77
|
+
log.error("Error during uninstall: " + err.message);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
};
|
package/package.json
CHANGED
|
@@ -1,26 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "evophp",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "
|
|
5
|
-
"main": "installer.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"start": "node installer.js"
|
|
8
|
-
},
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Command-line installer for the Evolution PHP framework",
|
|
9
5
|
"bin": {
|
|
10
|
-
"evophp": "
|
|
6
|
+
"evophp": "./bin/evophp.js"
|
|
7
|
+
},
|
|
8
|
+
"main": "bin/evophp.js",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node bin/evophp.js"
|
|
11
11
|
},
|
|
12
|
+
"files": [
|
|
13
|
+
"bin/",
|
|
14
|
+
"commands/",
|
|
15
|
+
"utils/"
|
|
16
|
+
],
|
|
12
17
|
"dependencies": {
|
|
13
18
|
"axios": "^1.7.9",
|
|
14
19
|
"dotenv": "^16.4.7",
|
|
15
20
|
"edit-json-file": "^1.8.0",
|
|
16
|
-
"rimraf": "^6.0.1"
|
|
21
|
+
"rimraf": "^6.0.1",
|
|
22
|
+
"yargs": "^17.7.2"
|
|
17
23
|
},
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
"keywords": [
|
|
25
|
+
"cli",
|
|
26
|
+
"evophp",
|
|
27
|
+
"installer",
|
|
28
|
+
"php-framework",
|
|
29
|
+
"evolution"
|
|
30
|
+
],
|
|
31
|
+
"author": "Kingsley Okafor",
|
|
32
|
+
"license": "MIT"
|
|
33
|
+
}
|
package/utils/config.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const configPath = path.join(require('os').homedir(), '.evophp-cli.json');
|
|
4
|
+
|
|
5
|
+
function loadConfig() {
|
|
6
|
+
if (fs.existsSync(configPath)) {
|
|
7
|
+
return JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
8
|
+
}
|
|
9
|
+
return {};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function saveConfig(data) {
|
|
13
|
+
fs.writeFileSync(configPath, JSON.stringify(data, null, 2));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
module.exports = {
|
|
17
|
+
loadConfig,
|
|
18
|
+
saveConfig,
|
|
19
|
+
configPath
|
|
20
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { execSync } = require('child_process');
|
|
4
|
+
const log = require('./logger');
|
|
5
|
+
|
|
6
|
+
async function installDependencies(dir, type) {
|
|
7
|
+
const dependenciesFile = path.join(dir, 'dependencies.json');
|
|
8
|
+
if (!fs.existsSync(dependenciesFile)) {
|
|
9
|
+
log.info(`No ${type} dependencies.json found in ${dir}`);
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const deps = JSON.parse(fs.readFileSync(dependenciesFile, 'utf-8'));
|
|
14
|
+
const cwd = process.cwd();
|
|
15
|
+
|
|
16
|
+
if (type === 'js') {
|
|
17
|
+
if (deps.prod) {
|
|
18
|
+
log.info("Installing JS production dependencies...");
|
|
19
|
+
execSync(`npm install ${deps.prod}`, { cwd, stdio: 'inherit' });
|
|
20
|
+
}
|
|
21
|
+
if (deps.dev) {
|
|
22
|
+
log.info("Installing JS development dependencies...");
|
|
23
|
+
execSync(`npm install ${deps.dev} --save-dev`, { cwd, stdio: 'inherit' });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (type === 'php' && deps.prod) {
|
|
28
|
+
log.info("Installing PHP dependencies...");
|
|
29
|
+
execSync(`composer require ${deps.prod}`, { cwd, stdio: 'inherit' });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
module.exports = { installDependencies };
|
package/utils/edit.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const log = require("./logger");
|
|
4
|
+
|
|
5
|
+
async function editFile(file, data) {
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
fs.readFile(file, "utf8", (err, fileData) => {
|
|
8
|
+
if (err) {
|
|
9
|
+
log.error(`Failed to read file ${file}`);
|
|
10
|
+
return reject(err);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
for (const key in data) {
|
|
14
|
+
fileData = fileData.replaceAll(`<${key}>`, data[key]);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
fs.writeFile(file, fileData, "utf8", err => {
|
|
18
|
+
if (err) {
|
|
19
|
+
log.error(`Failed to write file ${file}`);
|
|
20
|
+
return reject(err);
|
|
21
|
+
}
|
|
22
|
+
log.success(`${file} updated.`);
|
|
23
|
+
resolve(file);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function renameFile(oldPath, newPath) {
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
fs.rename(oldPath, newPath, err => {
|
|
32
|
+
if (err) {
|
|
33
|
+
log.error(`Failed to rename ${oldPath}`);
|
|
34
|
+
return reject(err);
|
|
35
|
+
}
|
|
36
|
+
log.success(`Renamed: ${path.basename(oldPath)} → ${path.basename(newPath)}`);
|
|
37
|
+
resolve();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
module.exports = { editFile, renameFile };
|
package/utils/git.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const { execSync } = require('child_process');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const log = require('./logger');
|
|
4
|
+
|
|
5
|
+
async function cloneRepo(repoUrl, destination) {
|
|
6
|
+
if (fs.existsSync(destination)) {
|
|
7
|
+
log.warn(`Path already exists: ${destination}`);
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
log.info(`Cloning ${repoUrl} → ${destination}`);
|
|
11
|
+
execSync(`git clone ${repoUrl} ${destination}`, { stdio: 'inherit' });
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
module.exports = { cloneRepo };
|
package/utils/github.js
ADDED
|
File without changes
|