evophp 1.1.0 → 1.1.2

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 CHANGED
@@ -1,152 +1,177 @@
1
1
  # EvoPHP CLI - Comprehensive Guide
2
2
 
3
3
  ## Overview
4
+
4
5
  EvoPHP CLI is a command-line interface designed to simplify the development and management of projects, plugins, and themes within the EvoPHP ecosystem. With intuitive commands and shorthands, developers can quickly set up projects, manage dependencies, and handle plugin/theme creation and installation with ease.
5
6
 
6
7
  ---
7
8
 
8
9
  ## Table of Contents
9
- - [Installation](#installation)
10
- - [All Commands](#all-commands)
11
- - [Initialization](#initialization)
12
- - [Plugin/Theme Creation](#plugintheme-creation)
13
- - [Plugin/Theme Installation](#plugintheme-installation)
14
- - [Plugin/Theme Uninstallation](#plugintheme-uninstallation)
15
- - [Dependency Management](#dependency-management)
16
- - [Notes](#notes)
17
- - [Further Documentation](#further-documentation)
10
+
11
+ * [Installation](#installation)
12
+ * [All Commands](#all-commands)
13
+
14
+ * [Initialization](#initialization)
15
+ * [Plugin/Theme Creation](#plugintheme-creation)
16
+ * [Plugin/Theme Installation](#plugintheme-installation)
17
+ * [Plugin/Theme Uninstallation](#plugintheme-uninstallation)
18
+ * [Dependency Management](#dependency-management)
19
+ * [Authentication & PAT Storage](#authentication--pat-storage)
20
+ * [Further Documentation](#further-documentation)
18
21
 
19
22
  ---
20
23
 
21
24
  ## Installation
22
25
 
23
26
  ### Prerequisites
27
+
24
28
  Ensure the following are installed on your system:
25
- - **Node.js**: Verify by running `node -v` and `npm -v`.
26
- - **Composer**: For managing PHP dependencies.
29
+
30
+ * **Node.js**: Verify with `node -v` and `npm -v`
31
+ * **Composer**: Required for PHP dependencies
27
32
 
28
33
  ### Install EvoPHP
29
- To install EvoPHP globally, run:
34
+
30
35
  ```bash
31
36
  npm install -g evophp
32
37
  ```
33
38
 
34
- This command makes the `evophp` CLI available system-wide.
39
+ This makes the `evophp` CLI available globally.
35
40
 
36
41
  ---
37
42
 
38
43
  ## All Commands
39
44
 
40
45
  ### Initialization
46
+
41
47
  ```bash
42
- evophp init ?<project-name>
48
+ evophp init [project-name]
43
49
  ```
44
- - Initialize a new project.
45
- - Examples:
50
+
51
+ * Initializes a new EvoPHP project.
52
+ * Examples:
53
+
46
54
  ```bash
47
55
  evophp init
48
- evophp init example-project
56
+ evophp init my-project
49
57
  ```
50
58
 
51
59
  ---
52
60
 
53
61
  ### Plugin/Theme Creation
62
+
54
63
  ```bash
55
- evophp n | new plugin | theme <author>/<name>
64
+ evophp new plugin <name>
65
+ evophp new theme <name>
66
+ evophp n plugin <name>
67
+ evophp n theme <name>
56
68
  ```
57
- - Create a new plugin or theme.
58
- - Examples:
59
- - Plugin:
60
- ```bash
61
- evophp new plugin example-author/example-plugin
62
- evophp n plugin example-author/example-plugin
63
- ```
64
- - Theme:
65
- ```bash
66
- evophp new theme example-author/example-theme
67
- evophp n theme example-author/example-theme
68
- ```
69
+
70
+ * Creates a new plugin or theme from a template in **your own GitHub account**.
71
+
72
+ * Supports:
73
+
74
+ * Just `<name>` → Uses your GitHub account (token required)
75
+ * ⚠️ You can only create repositories under your GitHub account.
76
+
77
+ * Examples:
78
+
79
+ ```bash
80
+ evophp new plugin MyPlugin # Creates in your GitHub
81
+ evophp n theme MyTheme # Creates in your GitHub
82
+ ```
69
83
 
70
84
  ---
71
85
 
72
86
  ### Plugin/Theme Installation
87
+
73
88
  ```bash
74
- evophp i | install plugin | theme <author>/<name>
89
+ evophp install plugin <name>
90
+ evophp install theme <name>
91
+ evophp i plugin <name>
92
+ evophp i theme <name>
75
93
  ```
76
- - Install a plugin or theme.
77
- - Examples:
78
- - Plugin:
79
- ```bash
80
- evophp install plugin example-author/example-plugin
81
- evophp i plugin example-author/example-plugin
82
- ```
83
- - Theme:
84
- ```bash
85
- evophp install theme example-author/example-theme
86
- evophp i theme example-author/example-theme
87
- ```
94
+
95
+ * Installs a plugin or theme from GitHub into your project.
96
+
97
+ * Supports:
98
+
99
+ * Just `<name>` → Clones from your GitHub account (token required)
100
+ * `<author>/<name>` → Clones from public GitHub repo (no token required)
101
+
102
+ * Examples:
103
+
104
+ ```bash
105
+ evophp install plugin MyPlugin
106
+ evophp i theme johndoe/EvoTheme
107
+ ```
88
108
 
89
109
  ---
90
110
 
91
111
  ### Plugin/Theme Uninstallation
112
+
92
113
  ```bash
93
- evophp u | uninstall plugin | theme <plugin-name>
114
+ evophp uninstall plugin <name>
115
+ evophp uninstall theme <name>
116
+ evophp u plugin <name>
117
+ evophp u theme <name>
94
118
  ```
95
- - Uninstall a plugin or theme.
96
- - Examples:
97
- - Plugin:
98
- ```bash
99
- evophp uninstall plugin example-plugin
100
- evophp u plugin example-plugin
101
- ```
102
- - Theme:
103
- ```bash
104
- evophp uninstall theme example-theme
105
- evophp u theme example-theme
106
- ```
119
+
120
+ * Removes the installed plugin or theme from the project.
121
+
122
+ * Examples:
123
+
124
+ ```bash
125
+ evophp uninstall plugin MyPlugin
126
+ evophp u theme EvoTheme
127
+ ```
107
128
 
108
129
  ---
109
130
 
110
131
  ### Dependency Management
132
+
111
133
  ```bash
112
- evophp d | install-dependencies <plugin-name>
134
+ evophp install-dependencies <plugin-name>
135
+ evophp d <plugin-name>
113
136
  ```
114
- - Install npm production dependencies.
115
- - Examples:
116
- ```bash
117
- evophp install-dependencies example-plugin
118
- evophp d example-plugin
119
- ```
120
137
 
121
- #### Development Dependencies
138
+ * Adds or installs plugin dependencies.
139
+
140
+ #### Production (npm):
141
+
122
142
  ```bash
123
- evophp d | install-dependencies <plugin-name> --dev | --save-dev
143
+ evophp d MyPlugin
124
144
  ```
125
- - Install npm development dependencies.
126
- - Examples:
127
- ```bash
128
- evophp install-dependencies example-plugin --dev
129
- evophp d example-plugin --dev
130
- ```
131
145
 
132
- #### Composer Dependencies
146
+ #### Development (npm):
147
+
133
148
  ```bash
134
- evophp d | install-dependencies <plugin-name> --composer
149
+ evophp d MyPlugin --dev
150
+ ```
151
+
152
+ #### PHP (Composer):
153
+
154
+ ```bash
155
+ evophp d MyPlugin --composer
135
156
  ```
136
- - Install composer dependencies.
137
- - Examples:
138
- ```bash
139
- evophp install-dependencies example-plugin --composer
140
- evophp d example-plugin --composer
141
- ```
142
157
 
143
158
  ---
144
159
 
145
- ## Notes
146
- - `<author>` must be a valid GitHub username.
147
- - `<name>` must be a unique repository name (not already existing on GitHub).
160
+ ## Authentication & PAT Storage
161
+
162
+ When using a command with just `<name>` (e.g. `evophp new plugin MyPlugin`), EvoPHP CLI will:
163
+
164
+ * Prompt you for a **GitHub Personal Access Token** (PAT) the first time
165
+ * Automatically store it in `.env.development` for future use
166
+ * Use that token to fetch your GitHub username and manage private/public repos
167
+
168
+ > ⚠️ You can only create repositories in your own GitHub account.
169
+
170
+ > To change your token later, simply edit or delete `.env.development`.
148
171
 
149
172
  ---
150
173
 
151
174
  ## Further Documentation
152
- For additional details, best practices, and advanced usage, please refer to the [official EvoPHP documentation](#).
175
+
176
+ More advanced use cases, templates, and configuration details coming soon at:
177
+ 📘 [Official EvoPHP Documentation](#)
package/bin/evophp.js CHANGED
@@ -1,11 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const yargs = require("yargs/yargs")(process.argv.slice(2));
3
+ const yargs = require("yargs");
4
4
  const { hideBin } = require("yargs/helpers");
5
5
 
6
6
  yargs(hideBin(process.argv))
7
- .command(require("../commands/new"))
8
7
  .command(require("../commands/init"))
8
+ .command(require("../commands/new"))
9
+ .command(require("../commands/install"))
9
10
  .command(require("../commands/uninstall"))
10
11
  .command(require("../commands/dependencies"))
11
12
  .command(require("../commands/help"))
package/commands/help.js CHANGED
@@ -9,52 +9,53 @@ module.exports = {
9
9
  EvoPHP CLI - Help Guide
10
10
  ==========================================
11
11
 
12
- Initialization:
13
- evophp init [project-name]
12
+ 📦 Initialization:
13
+ evophp init [project-name]
14
14
  → Initialize a new Evolution PHP project.
15
15
  → Aliases: none
16
- → Example: evophp init my-project
16
+ → Example: evophp init my-coop-project
17
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
18
+ 🛠️ Plugin & Theme Creation:
19
+ evophp new plugin <name>
20
+ evophp new theme <name>
21
+ evophp n plugin <name>
22
+ evophp n theme <name>
23
+ → Create a plugin or theme from template repo.
24
+ → Supports:
25
+ • just <name> → uses your GitHub account
26
+ • author/name → uses any GitHub account
24
27
 
25
- evophp new theme <author>/<name>
26
- evophp n theme <author>/<name>
27
- → Create a new theme from template.
28
+ ⬇️ Plugin & Theme Installation:
29
+ evophp install plugin <name>
30
+ evophp install plugin author/name
31
+ evophp i theme <name>
32
+ evophp i theme author/name
33
+ → Install a plugin or theme from GitHub into your project.
34
+ → Format options:
35
+ • just <name> → installs from your GitHub account
36
+ • author/name → installs from public GitHub repo
28
37
 
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
38
+ 🗑️ Plugin & Theme Uninstallation:
39
+ evophp uninstall plugin <name>
40
+ evophp uninstall theme <name>
41
+ evophp u plugin <name>
42
+ evophp u theme <name>
43
+ → Remove an installed plugin or theme and update config.
34
44
 
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:
45
+ 🔧 Dependency Management:
50
46
  evophp install-dependencies <plugin>
51
47
  evophp d <plugin> [--dev|--composer]
52
- → Add and install dependencies.
53
- → JS dev: --dev
54
- → PHP: --composer
48
+ → Add and install dependencies for a plugin:
49
+ --dev → JavaScript development dependencies
50
+ --composer → PHP dependencies via Composer
55
51
  → Aliases: install-dependencies → d
56
52
 
57
- General:
53
+ 🔐 GitHub Authentication:
54
+ When installing or creating with just <name>,
55
+ the CLI will prompt for your GitHub PAT and store it
56
+ in .env.development for future runs.
57
+
58
+ ❓ General:
58
59
  evophp help
59
60
  evophp h
60
61
  → Show this help guide.
@@ -62,7 +63,7 @@ General:
62
63
 
63
64
  ==========================================
64
65
  Tip: Use --help after any command
65
- for command-specific usage.
66
+ for more usage examples.
66
67
  ==========================================
67
68
  `);
68
69
  process.exit(0);
@@ -1,22 +1,24 @@
1
1
  const path = require('path');
2
2
  const fs = require('fs');
3
3
  const { execSync } = require('child_process');
4
- const { readLineAsync, splitPluginName, mergeConfig } = require('../utils/helpers');
4
+ const { readLineAsync, mergeConfig, saveToEnv } = require('../utils/helpers');
5
+ const { getUserData } = require('../utils/github');
5
6
  const { cloneRepo } = require('../utils/git');
6
7
  const { installDependencies } = require('../utils/dependencies');
7
8
  const log = require('../utils/logger');
9
+ require("dotenv").config({ path: "./.env.development" });
8
10
 
9
11
  module.exports = {
10
12
  command: 'install [type] [name]',
11
13
  aliases: ['i'],
12
14
  describe: 'Install a plugin or theme',
15
+
13
16
  builder: yargs => yargs
14
17
  .positional('type', { describe: 'plugin or theme', type: 'string' })
15
- .positional('name', { describe: 'author/plugin-name', type: 'string' }),
18
+ .positional('name', { describe: 'name or author/name', type: 'string' }),
16
19
 
17
20
  handler: async ({ type, name }) => {
18
21
  try {
19
- // Prompt if missing
20
22
  if (!type || !['plugin', 'theme'].includes(type.toLowerCase())) {
21
23
  type = await readLineAsync("What are you installing? (plugin/theme): ");
22
24
  type = type.toLowerCase();
@@ -27,30 +29,46 @@ module.exports = {
27
29
  }
28
30
 
29
31
  if (!name) {
30
- name = await readLineAsync(`Enter the ${type} name (e.g., johndoe/example${type}): `);
32
+ name = await readLineAsync(`Enter the ${type} name (e.g., myplugin or johndoe/myplugin): `);
31
33
  }
32
34
 
33
- const [author, itemName] = await splitPluginName(name);
35
+ let author, pluginName;
36
+ let gitHubToken = process.env.GITHUB_TOKEN;
37
+
38
+ if (name.includes("/")) {
39
+ // Full author/name provided — no auth required
40
+ [author, pluginName] = name.split("/");
41
+ } else {
42
+ // Token required to determine user
43
+ if (!gitHubToken) {
44
+ gitHubToken = await readLineAsync("Enter your GitHub Personal Access Token: ");
45
+ saveToEnv("GITHUB_TOKEN", gitHubToken);
46
+ log.success("GitHub token saved to .env.development");
47
+ }
48
+ const userData = await getUserData(gitHubToken);
49
+ author = userData.login;
50
+ pluginName = name;
51
+ log.info(`Authenticated as ${author}`);
52
+ }
34
53
 
35
54
  const paths = type === 'plugin'
36
- ? [path.join('Public', 'Modules', itemName), path.join('EvoJsDev', 'Modules', itemName)]
37
- : [path.join('Public', 'Themes', itemName)];
55
+ ? [path.join('Public', 'Modules', pluginName), path.join('EvoJsDev', 'Modules', pluginName)]
56
+ : [path.join('Public', 'Themes', pluginName)];
38
57
 
39
- // Check existing
40
58
  for (const p of paths) {
41
59
  if (fs.existsSync(p)) {
42
- log.warn(`${type} "${itemName}" already exists at ${p}`);
60
+ log.warn(`${type} "${pluginName}" already exists at ${p}`);
43
61
  process.exit(0);
44
62
  }
45
63
  }
46
64
 
47
- log.info(`Installing ${type} "${itemName}" by ${author}...`);
65
+ log.info(`Installing ${type} "${pluginName}" from ${author}...`);
48
66
 
49
67
  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]);
68
+ await cloneRepo(`${author}/${pluginName}`, null, paths[0]);
69
+ await cloneRepo(`${author}/${pluginName}.js`, null, paths[1]);
52
70
 
53
- const configFile = path.resolve(`./EvoJsDev/Modules/${itemName}/config.json`);
71
+ const configFile = path.resolve(`./EvoJsDev/Modules/${pluginName}/config.json`);
54
72
  if (fs.existsSync(configFile)) {
55
73
  const pluginConfig = require(configFile);
56
74
  mergeConfig(pluginConfig);
@@ -60,10 +78,11 @@ module.exports = {
60
78
  await installDependencies(paths[0], 'php');
61
79
 
62
80
  } else if (type === 'theme') {
63
- await cloneRepo(`https://github.com/${author}/${itemName}.git`, paths[0]);
81
+ await cloneRepo(`${author}/${pluginName}`, null, paths[0]);
64
82
  }
65
83
 
66
- log.success(`The ${type} "${itemName}" has been installed successfully.`);
84
+ log.success(`The ${type} "${pluginName}" has been installed successfully.`);
85
+
67
86
  } catch (err) {
68
87
  log.error(`Install failed: ${err.message}`);
69
88
  process.exit(1);
package/commands/new.js CHANGED
@@ -1,25 +1,41 @@
1
1
  const path = require("path");
2
2
  const fs = require("fs");
3
- const { readLineAsync, splitPluginName, mergeConfig } = require("../utils/helpers");
3
+ const { readLineAsync, mergeConfig } = require("../utils/helpers");
4
4
  const { getUserData, createGitHubRepo } = require("../utils/github");
5
- const { cloneRepository } = require("../utils/git");
5
+ const { cloneRepo } = require("../utils/git");
6
6
  const { editFile, renameFile } = require("../utils/edit");
7
7
  const { test } = require("../utils/validate");
8
8
  const log = require("../utils/logger");
9
9
  require("dotenv").config({ path: "./.env.development" });
10
10
 
11
11
  module.exports = {
12
- command: "new <type> <author>/<name>",
12
+ command: "new <type> <name>",
13
13
  aliases: ["n"],
14
14
  describe: "Create a new plugin or theme from template",
15
- builder: yargs =>
15
+
16
+ builder: (yargs) =>
16
17
  yargs
17
- .positional("type", { describe: "plugin or theme", type: "string" })
18
- .positional("author/name", { describe: "GitHub format name", type: "string" }),
18
+ .positional("type", {
19
+ describe: "plugin or theme",
20
+ type: "string",
21
+ })
22
+ .positional("name", {
23
+ describe: "The plugin or theme name (without author)",
24
+ type: "string",
25
+ }),
19
26
 
20
27
  handler: async ({ type, name }) => {
21
28
  try {
22
- const gitHubToken = process.env.GITHUB_TOKEN || await readLineAsync("Enter GitHub PAT: ");
29
+ let gitHubToken = process.env.GITHUB_TOKEN;
30
+
31
+ if (!gitHubToken) {
32
+ gitHubToken = await readLineAsync(
33
+ "Enter GitHub Personal Access Token: "
34
+ );
35
+ const { saveToEnv } = require("../utils/helpers");
36
+ saveToEnv("GITHUB_TOKEN", gitHubToken);
37
+ log.success("GitHub token saved to .env.development");
38
+ }
23
39
  type = type.toLowerCase();
24
40
 
25
41
  if (!["plugin", "theme"].includes(type)) {
@@ -27,14 +43,13 @@ module.exports = {
27
43
  process.exit(1);
28
44
  }
29
45
 
30
- const [author, pluginName] = await splitPluginName(name);
46
+ // Get authenticated username from token
31
47
  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
- }
48
+ const author = userData.login;
49
+ const pluginName = name;
36
50
 
37
- log.info(`Authenticated as ${userData.login}`);
51
+ log.info(`Authenticated as ${author}`);
52
+ log.info(`Creating ${type} "${pluginName}"...`);
38
53
 
39
54
  if (type === "plugin") {
40
55
  const entry = await setupPlugin(gitHubToken, author, pluginName);
@@ -43,12 +58,11 @@ module.exports = {
43
58
  await setupTheme(gitHubToken, author, pluginName);
44
59
  log.success(`Theme "${pluginName}" created`);
45
60
  }
46
-
47
61
  } catch (err) {
48
62
  log.error(`Creation failed: ${err.message}`);
49
63
  process.exit(1);
50
64
  }
51
- }
65
+ },
52
66
  };
53
67
 
54
68
  async function setupPlugin(token, author, pluginName) {
@@ -56,32 +70,55 @@ async function setupPlugin(token, author, pluginName) {
56
70
  const pluginPrefix = entry.replace("Main", "");
57
71
 
58
72
  await editFile(`./Public/Modules/${pluginName}/Routes.php`, {
59
- pluginName, entry, entryURI: entry.toLowerCase(), pluginPrefix
73
+ pluginName,
74
+ entry,
75
+ entryURI: entry.toLowerCase(),
76
+ pluginPrefix,
60
77
  });
61
78
 
62
79
  const controllerPath = `./Public/Modules/${pluginName}/Controller.php`;
63
80
  if (fs.existsSync(controllerPath)) {
64
81
  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}`);
82
+ await renameFile(
83
+ controllerPath,
84
+ `./Public/Modules/${pluginName}/${pluginPrefix}Controller.php`
85
+ );
86
+ await renameFile(
87
+ `./Public/Modules/${pluginName}/Views/Entry`,
88
+ `./Public/Modules/${pluginName}/Views/${entry}`
89
+ );
67
90
  }
68
91
 
69
92
  return entry;
70
93
  }
71
94
 
72
95
  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());
96
+ await createGitHubRepo(token, "kinsokafor/EvoPlugin", pluginName);
97
+ await cloneRepo(
98
+ author,
99
+ pluginName,
100
+ path.join("Public", "Modules", pluginName)
101
+ );
102
+
103
+ await createGitHubRepo(token, "kinsokafor/EvoPlugin.js", `${pluginName}.js`);
104
+ await cloneRepo(
105
+ author,
106
+ `${pluginName}.js`,
107
+ path.join("EvoJsDev", "Modules", pluginName)
108
+ );
109
+
110
+ const pluginPrefix = await getValidatedInput("Enter Plugin Prefix?", 3, true);
111
+ const entryURI = await getValidatedInput("Entry URI?", 20);
81
112
  const entry = pluginPrefix + "Main";
82
113
 
83
- await editFile(`./EvoJsDev/Modules/${pluginName}/config.json`, { pluginName, entry });
84
- await renameFile(`./EvoJsDev/Modules/${pluginName}/Entry`, `./EvoJsDev/Modules/${pluginName}/${entry}`);
114
+ await editFile(`./EvoJsDev/Modules/${pluginName}/config.json`, {
115
+ pluginName,
116
+ entry,
117
+ });
118
+ await renameFile(
119
+ `./EvoJsDev/Modules/${pluginName}/Entry`,
120
+ `./EvoJsDev/Modules/${pluginName}/${entry}`
121
+ );
85
122
 
86
123
  const configPath = `./EvoJsDev/Modules/${pluginName}/config.json`;
87
124
  if (fs.existsSync(configPath)) {
@@ -93,18 +130,32 @@ async function setupPluginRepo(token, author, pluginName) {
93
130
  }
94
131
 
95
132
  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 });
133
+ await createGitHubRepo(token, "kinsokafor/EvoTheme", pluginName);
134
+ await cloneRepo(
135
+ author,
136
+ pluginName,
137
+ path.join("Public", "Themes", pluginName)
138
+ );
139
+
140
+ await editFile(`./Public/Themes/${pluginName}/Data/index.data.php`, {
141
+ pluginName,
142
+ });
143
+ await editFile(`./Public/Themes/${pluginName}/Data/login.data.php`, {
144
+ pluginName,
145
+ });
146
+ await editFile(`./Public/Themes/${pluginName}/Views/index.blade.php`, {
147
+ pluginName,
148
+ });
149
+ await editFile(`./Public/Themes/${pluginName}/Views/login.blade.php`, {
150
+ pluginName,
151
+ });
103
152
  }
104
153
 
105
154
  async function getValidatedInput(label, maxLength, caps = false) {
106
155
  let input = await readLineAsync(label);
107
- while (!test(input, maxLength)) input = await readLineAsync(label);
156
+ while (!test(input, maxLength)) {
157
+ input = await readLineAsync(label);
158
+ }
108
159
  input = input.trim().replaceAll(" ", "");
109
160
  return caps ? input.toUpperCase() : input.toLowerCase();
110
- }
161
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "evophp",
3
- "version": "1.1.0",
3
+ "version": "1.1.02",
4
4
  "description": "Command-line installer for the Evolution PHP framework",
5
5
  "bin": {
6
6
  "evophp": "./bin/evophp.js"
package/utils/git.js CHANGED
@@ -1,14 +1,46 @@
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;
1
+ const { execSync } = require("child_process");
2
+ const fs = require("fs");
3
+ const path = require("path");
4
+ const rimraf = require("rimraf");
5
+ const log = require("./logger");
6
+
7
+ /**
8
+ * Clone a GitHub repo into a destination folder.
9
+ * Supports:
10
+ * cloneRepo("author", "repo", "dest")
11
+ * cloneRepo("author/repo", null, "dest")
12
+ *
13
+ * @param {string} authorOrFull - GitHub username OR "author/repo"
14
+ * @param {string|null} repo - Optional repo name if not included in first arg
15
+ * @param {string} dest - Local destination path
16
+ */
17
+ async function cloneRepo(authorOrFull, repo, dest) {
18
+ let author = "";
19
+ let repoName = "";
20
+
21
+ if (repo === null || repo === undefined) {
22
+ // authorOrFull is in "author/repo" format
23
+ const parts = authorOrFull.split("/");
24
+ if (parts.length !== 2) {
25
+ log.error("Invalid GitHub repo format. Use 'author/repo'.");
26
+ process.exit(1);
27
+ }
28
+ [author, repoName] = parts;
29
+ } else {
30
+ // Passed separately
31
+ author = authorOrFull;
32
+ repoName = repo;
33
+ }
34
+
35
+ const cloneUrl = `https://github.com/${author}/${repoName}.git`;
36
+
37
+ if (fs.existsSync(dest)) {
38
+ log.warn(`Deleting existing folder: ${dest}`);
39
+ rimraf.sync(dest);
9
40
  }
10
- log.info(`Cloning ${repoUrl} → ${destination}`);
11
- execSync(`git clone ${repoUrl} ${destination}`, { stdio: 'inherit' });
41
+
42
+ log.info(`Cloning ${author}/${repoName} → ${dest}`);
43
+ execSync(`git clone ${cloneUrl} ${dest}`, { stdio: "inherit" });
12
44
  }
13
45
 
14
- module.exports = { cloneRepo };
46
+ module.exports = { cloneRepo };
package/utils/github.js CHANGED
@@ -0,0 +1,49 @@
1
+ // utils/github.js
2
+ const axios = require("axios");
3
+ const log = require("./logger");
4
+
5
+ async function getUserData(token) {
6
+ try {
7
+ const res = await axios.get("https://api.github.com/user", {
8
+ headers: {
9
+ Authorization: `token ${token}`,
10
+ Accept: "application/vnd.github.v3+json",
11
+ },
12
+ });
13
+ return res.data;
14
+ } catch (e) {
15
+ log.error("Failed to fetch GitHub user info.");
16
+ throw e;
17
+ }
18
+ }
19
+
20
+ async function createGitHubRepo(token, templateRepo, pluginName) {
21
+ try {
22
+ const res = await axios.post(
23
+ `https://api.github.com/repos/${templateRepo}/generate`,
24
+ {
25
+ name: pluginName,
26
+ private: true,
27
+ description: `A new ${templateRepo.split("/")[1]} created from template.`,
28
+ },
29
+ {
30
+ headers: {
31
+ Authorization: `token ${token}`,
32
+ Accept: "application/vnd.github.v3+json",
33
+ },
34
+ }
35
+ );
36
+
37
+ if (res.status === 201) {
38
+ log.success(`Created repo ${pluginName} from ${templateRepo}`);
39
+ } else {
40
+ log.error("Failed to create repo:", res.data);
41
+ process.exit(1);
42
+ }
43
+ } catch (e) {
44
+ log.error(`GitHub repo creation failed: ${e.message}`);
45
+ process.exit(1);
46
+ }
47
+ }
48
+
49
+ module.exports = { getUserData, createGitHubRepo };
package/utils/helpers.js CHANGED
@@ -122,9 +122,40 @@ function addPluginEntry(pluginName, entryName) {
122
122
  log.success(`Added entry "${entryPath}" to ${pluginName} config.`);
123
123
  }
124
124
 
125
+ const fs = require("fs");
126
+ const path = require("path");
127
+
128
+ /**
129
+ * Save a key-value pair to .env.development (creates or updates)
130
+ * @param {string} key
131
+ * @param {string} value
132
+ */
133
+ function saveToEnv(key, value) {
134
+ const envPath = path.resolve(".env.development");
135
+
136
+ let env = "";
137
+ if (fs.existsSync(envPath)) {
138
+ env = fs.readFileSync(envPath, "utf-8");
139
+ }
140
+
141
+ const regex = new RegExp(`^${key}=.*$`, "m");
142
+ const line = `${key}=${value.trim()}`;
143
+
144
+ if (regex.test(env)) {
145
+ // Update existing key
146
+ env = env.replace(regex, line);
147
+ } else {
148
+ // Append new key
149
+ env += (env.endsWith("\n") ? "" : "\n") + line + "\n";
150
+ }
151
+
152
+ fs.writeFileSync(envPath, env, "utf-8");
153
+ }
154
+
125
155
  module.exports = {
126
156
  readLineAsync,
127
157
  splitPluginName,
128
158
  mergeConfig,
129
- addPluginEntry
159
+ addPluginEntry,
160
+ saveToEnv
130
161
  };