@artilingo/artiframe-cli 1.0.3 → 1.0.4
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/artiframe.js +248 -39
- package/package.json +1 -1
package/bin/artiframe.js
CHANGED
|
@@ -3,55 +3,264 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* ArtiFrame CLI — Node.js wrapper
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* Handles:
|
|
7
|
+
* 1. PHP 8.1+ availability check
|
|
8
|
+
* 2. --version / -v flag: shows current + latest version, optional self-update
|
|
9
|
+
* 3. Delegates all other args to the PHP bootstrap
|
|
8
10
|
*/
|
|
9
11
|
|
|
10
|
-
const {
|
|
11
|
-
const path
|
|
12
|
-
const fs
|
|
12
|
+
const { spawnSync } = require('child_process');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
const https = require('https');
|
|
16
|
+
const readline = require('readline');
|
|
13
17
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
const PACKAGE_NAME = '@artilingo/artiframe-cli';
|
|
19
|
+
const PKG = require(path.join(__dirname, '..', 'package.json'));
|
|
20
|
+
const CURRENT_VERSION = PKG.version;
|
|
21
|
+
|
|
22
|
+
// ── ANSI colour helpers ─────────────────────────────────────────
|
|
23
|
+
const G = '\x1b[38;2;0;157;108m'; // ArtiFrame green
|
|
24
|
+
const W = '\x1b[1;37m'; // white bold
|
|
25
|
+
const D = '\x1b[38;2;100;100;100m'; // dim gray
|
|
26
|
+
const Y = '\x1b[38;5;220m'; // yellow
|
|
27
|
+
const R = '\x1b[0m'; // reset
|
|
28
|
+
|
|
29
|
+
// ── Language detection (mirrors PHP App.php logic) ──────────────
|
|
30
|
+
function getLanguage() {
|
|
31
|
+
for (const arg of process.argv.slice(2)) {
|
|
32
|
+
if (arg.startsWith('--lang=')) {
|
|
33
|
+
const code = arg.slice(7, 9).toLowerCase();
|
|
34
|
+
if (['tr', 'en', 'de', 'fr', 'es'].includes(code)) return code;
|
|
35
|
+
}
|
|
20
36
|
}
|
|
21
|
-
|
|
37
|
+
const home = process.env.HOME || process.env.USERPROFILE;
|
|
38
|
+
const configFile = home ? path.join(home, '.artiframe_lang') : null;
|
|
39
|
+
if (configFile && fs.existsSync(configFile)) {
|
|
40
|
+
const lang = fs.readFileSync(configFile, 'utf8').trim();
|
|
41
|
+
if (['tr', 'en', 'de', 'fr', 'es'].includes(lang)) return lang;
|
|
42
|
+
}
|
|
43
|
+
return 'en';
|
|
22
44
|
}
|
|
23
45
|
|
|
24
|
-
|
|
46
|
+
// ── Inline translations for the version/update screen ───────────
|
|
47
|
+
const MESSAGES = {
|
|
48
|
+
tr: {
|
|
49
|
+
currentVersion : 'Mevcut sürüm ',
|
|
50
|
+
latestVersion : 'Son sürüm ',
|
|
51
|
+
checking : 'Güncelleme kontrol ediliyor...',
|
|
52
|
+
upToDate : '✅ Güncel — Yeni sürüm bulunmuyor.',
|
|
53
|
+
updateAvail : '🔔 Güncelleme mevcut!',
|
|
54
|
+
updatePrompt : 'Şimdi güncellemek ister misiniz? [e/H]: ',
|
|
55
|
+
yesKeys : ['e', 'y'],
|
|
56
|
+
updating : '📦 Güncelleniyor...',
|
|
57
|
+
updateSuccess : '✅ Güncelleme tamamlandı! Terminali yeniden başlatın.',
|
|
58
|
+
updateCancelled: 'Güncelleme iptal edildi.',
|
|
59
|
+
updateFailed : '❌ Güncelleme başarısız oldu.',
|
|
60
|
+
networkError : '⚠️ Sürüm kontrolü yapılamadı (ağ hatası).',
|
|
61
|
+
},
|
|
62
|
+
en: {
|
|
63
|
+
currentVersion : 'Current version',
|
|
64
|
+
latestVersion : 'Latest version ',
|
|
65
|
+
checking : 'Checking for updates...',
|
|
66
|
+
upToDate : '✅ Up to date — No new version available.',
|
|
67
|
+
updateAvail : '🔔 Update available!',
|
|
68
|
+
updatePrompt : 'Would you like to update now? [y/N]: ',
|
|
69
|
+
yesKeys : ['y'],
|
|
70
|
+
updating : '📦 Updating...',
|
|
71
|
+
updateSuccess : '✅ Update complete! Please restart your terminal.',
|
|
72
|
+
updateCancelled: 'Update cancelled.',
|
|
73
|
+
updateFailed : '❌ Update failed.',
|
|
74
|
+
networkError : '⚠️ Could not check for updates (network error).',
|
|
75
|
+
},
|
|
76
|
+
de: {
|
|
77
|
+
currentVersion : 'Aktuelle Version',
|
|
78
|
+
latestVersion : 'Neueste Version ',
|
|
79
|
+
checking : 'Nach Updates suchen...',
|
|
80
|
+
upToDate : '✅ Aktuell — Keine neue Version verfügbar.',
|
|
81
|
+
updateAvail : '🔔 Update verfügbar!',
|
|
82
|
+
updatePrompt : 'Möchten Sie jetzt aktualisieren? [j/N]: ',
|
|
83
|
+
yesKeys : ['j', 'y'],
|
|
84
|
+
updating : '📦 Wird aktualisiert...',
|
|
85
|
+
updateSuccess : '✅ Update abgeschlossen! Bitte Terminal neu starten.',
|
|
86
|
+
updateCancelled: 'Update abgebrochen.',
|
|
87
|
+
updateFailed : '❌ Update fehlgeschlagen.',
|
|
88
|
+
networkError : '⚠️ Keine Verbindung zum Update-Server (Netzwerkfehler).',
|
|
89
|
+
},
|
|
90
|
+
fr: {
|
|
91
|
+
currentVersion : 'Version actuelle',
|
|
92
|
+
latestVersion : 'Dernière version',
|
|
93
|
+
checking : 'Vérification des mises à jour...',
|
|
94
|
+
upToDate : '✅ À jour — Aucune nouvelle version disponible.',
|
|
95
|
+
updateAvail : '🔔 Mise à jour disponible !',
|
|
96
|
+
updatePrompt : 'Mettre à jour maintenant ? [o/N] : ',
|
|
97
|
+
yesKeys : ['o', 'y'],
|
|
98
|
+
updating : '📦 Mise à jour en cours...',
|
|
99
|
+
updateSuccess : '✅ Mise à jour terminée ! Veuillez redémarrer votre terminal.',
|
|
100
|
+
updateCancelled: 'Mise à jour annulée.',
|
|
101
|
+
updateFailed : '❌ Échec de la mise à jour.',
|
|
102
|
+
networkError : '⚠️ Impossible de vérifier les mises à jour (erreur réseau).',
|
|
103
|
+
},
|
|
104
|
+
es: {
|
|
105
|
+
currentVersion : 'Versión actual ',
|
|
106
|
+
latestVersion : 'Última versión ',
|
|
107
|
+
checking : 'Verificando actualizaciones...',
|
|
108
|
+
upToDate : '✅ Al día — No hay nueva versión disponible.',
|
|
109
|
+
updateAvail : '🔔 ¡Actualización disponible!',
|
|
110
|
+
updatePrompt : '¿Actualizar ahora? [s/N]: ',
|
|
111
|
+
yesKeys : ['s', 'y'],
|
|
112
|
+
updating : '📦 Actualizando...',
|
|
113
|
+
updateSuccess : '✅ ¡Actualización completa! Por favor reinicie su terminal.',
|
|
114
|
+
updateCancelled: 'Actualización cancelada.',
|
|
115
|
+
updateFailed : '❌ Error en la actualización.',
|
|
116
|
+
networkError : '⚠️ No se pudo verificar las actualizaciones (error de red).',
|
|
117
|
+
},
|
|
118
|
+
};
|
|
25
119
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
120
|
+
// ── npm registry fetch ──────────────────────────────────────────
|
|
121
|
+
function fetchLatestVersion() {
|
|
122
|
+
return new Promise((resolve, reject) => {
|
|
123
|
+
const req = https.request({
|
|
124
|
+
hostname: 'registry.npmjs.org',
|
|
125
|
+
path : '/' + encodeURIComponent(PACKAGE_NAME) + '/latest',
|
|
126
|
+
method : 'GET',
|
|
127
|
+
headers : { Accept: 'application/json' },
|
|
128
|
+
timeout : 6000,
|
|
129
|
+
}, (res) => {
|
|
130
|
+
let raw = '';
|
|
131
|
+
res.on('data', c => raw += c);
|
|
132
|
+
res.on('end', () => {
|
|
133
|
+
try { resolve(JSON.parse(raw).version); }
|
|
134
|
+
catch { reject(new Error('parse')); }
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
req.on('timeout', () => { req.destroy(); reject(new Error('timeout')); });
|
|
138
|
+
req.on('error', reject);
|
|
139
|
+
req.end();
|
|
140
|
+
});
|
|
34
141
|
}
|
|
35
142
|
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
console.error('\n\x1b[1;31m[ArtiFrame] PHP version too old!\x1b[0m');
|
|
45
|
-
console.error(`\x1b[33mFound PHP ${major}.${minor} — ArtiFrame requires PHP 8.1+\x1b[0m\n`);
|
|
46
|
-
process.exit(1);
|
|
143
|
+
function compareVersions(a, b) {
|
|
144
|
+
const pa = a.split('.').map(Number);
|
|
145
|
+
const pb = b.split('.').map(Number);
|
|
146
|
+
for (let i = 0; i < 3; i++) {
|
|
147
|
+
if (pa[i] > pb[i]) return 1;
|
|
148
|
+
if (pa[i] < pb[i]) return -1;
|
|
149
|
+
}
|
|
150
|
+
return 0;
|
|
47
151
|
}
|
|
48
152
|
|
|
49
|
-
// ──
|
|
50
|
-
|
|
153
|
+
// ── --version handler ───────────────────────────────────────────
|
|
154
|
+
async function handleVersion() {
|
|
155
|
+
const lang = getLanguage();
|
|
156
|
+
const m = MESSAGES[lang] || MESSAGES.en;
|
|
157
|
+
|
|
158
|
+
console.log();
|
|
159
|
+
console.log(` ${W}${m.currentVersion}:${R} ${G}v${CURRENT_VERSION}${R}`);
|
|
160
|
+
process.stdout.write(` ${D}${m.checking}${R}`);
|
|
161
|
+
|
|
162
|
+
let latest;
|
|
163
|
+
try {
|
|
164
|
+
latest = await fetchLatestVersion();
|
|
165
|
+
} catch {
|
|
166
|
+
console.log();
|
|
167
|
+
console.log(` ${Y}${m.networkError}${R}`);
|
|
168
|
+
console.log();
|
|
169
|
+
process.exit(0);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Clear the "checking..." line by overwriting with spaces then reprint
|
|
173
|
+
process.stdout.write('\r' + ' '.repeat(60) + '\r');
|
|
174
|
+
console.log(` ${W}${m.latestVersion}:${R} ${G}v${latest}${R}`);
|
|
175
|
+
console.log();
|
|
176
|
+
|
|
177
|
+
if (compareVersions(latest, CURRENT_VERSION) <= 0) {
|
|
178
|
+
console.log(` ${m.upToDate}`);
|
|
179
|
+
console.log();
|
|
180
|
+
process.exit(0);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// ── Update available ─────────────────────────────────────────
|
|
184
|
+
console.log(` ${Y}${m.updateAvail}${R} ${D}v${CURRENT_VERSION}${R} → ${G}v${latest}${R}`);
|
|
185
|
+
console.log();
|
|
186
|
+
process.stdout.write(` ${m.updatePrompt}`);
|
|
187
|
+
|
|
188
|
+
const rl = readline.createInterface({ input: process.stdin, terminal: false });
|
|
189
|
+
|
|
190
|
+
rl.once('line', (answer) => {
|
|
191
|
+
rl.close();
|
|
192
|
+
const yes = m.yesKeys.includes(answer.trim().toLowerCase());
|
|
193
|
+
|
|
194
|
+
if (!yes) {
|
|
195
|
+
console.log();
|
|
196
|
+
console.log(` ${D}${m.updateCancelled}${R}`);
|
|
197
|
+
console.log();
|
|
198
|
+
process.exit(0);
|
|
199
|
+
}
|
|
51
200
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
});
|
|
201
|
+
console.log();
|
|
202
|
+
console.log(` ${m.updating}`);
|
|
203
|
+
console.log();
|
|
56
204
|
|
|
57
|
-
|
|
205
|
+
const result = spawnSync('npm', ['install', '-g', PACKAGE_NAME], {
|
|
206
|
+
stdio: 'inherit',
|
|
207
|
+
shell: true,
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
console.log();
|
|
211
|
+
if (result.status === 0) {
|
|
212
|
+
console.log(` ${G}${m.updateSuccess}${R}`);
|
|
213
|
+
} else {
|
|
214
|
+
console.log(` ${m.updateFailed}`);
|
|
215
|
+
}
|
|
216
|
+
console.log();
|
|
217
|
+
process.exit(result.status ?? 1);
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// ── PHP availability check ──────────────────────────────────────
|
|
222
|
+
function findPhp() {
|
|
223
|
+
for (const bin of ['php', 'php8', 'php81', 'php82', 'php83', 'php84']) {
|
|
224
|
+
const r = spawnSync(bin, ['--version'], { encoding: 'utf8', shell: true });
|
|
225
|
+
if (r.status === 0) return bin;
|
|
226
|
+
}
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// ── Entry point ─────────────────────────────────────────────────
|
|
231
|
+
const args = process.argv.slice(2);
|
|
232
|
+
|
|
233
|
+
if (args.includes('--version') || args.includes('-v')) {
|
|
234
|
+
handleVersion().catch(() => process.exit(1));
|
|
235
|
+
} else {
|
|
236
|
+
// Normal PHP delegation
|
|
237
|
+
const php = findPhp();
|
|
238
|
+
|
|
239
|
+
if (!php) {
|
|
240
|
+
const lang = getLanguage();
|
|
241
|
+
console.error(`\n\x1b[1;31m[ArtiFrame] PHP Not Found!\x1b[0m`);
|
|
242
|
+
console.error(`\x1b[33mArtiFrame CLI requires PHP 8.1 or higher.\x1b[0m\n`);
|
|
243
|
+
console.error('Install PHP:');
|
|
244
|
+
console.error(' Windows : https://windows.php.net/download/');
|
|
245
|
+
console.error(' macOS : brew install php');
|
|
246
|
+
console.error(' Linux : sudo apt install php8.2-cli\n');
|
|
247
|
+
process.exit(1);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const vr = spawnSync(php, ['-r', 'echo PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION;'], {
|
|
251
|
+
encoding: 'utf8', shell: true,
|
|
252
|
+
});
|
|
253
|
+
const [major, minor] = (vr.stdout || '0.0').split('.').map(Number);
|
|
254
|
+
if (major < 8 || (major === 8 && minor < 1)) {
|
|
255
|
+
console.error(`\n\x1b[1;31m[ArtiFrame] PHP version too old!\x1b[0m`);
|
|
256
|
+
console.error(`\x1b[33mFound PHP ${major}.${minor} — ArtiFrame requires PHP 8.1+\x1b[0m\n`);
|
|
257
|
+
process.exit(1);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const phpScript = path.join(__dirname, 'artiframe.php');
|
|
261
|
+
const result = spawnSync(php, [phpScript, ...args], {
|
|
262
|
+
stdio: 'inherit',
|
|
263
|
+
shell: false,
|
|
264
|
+
});
|
|
265
|
+
process.exit(result.status ?? 1);
|
|
266
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@artilingo/artiframe-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "ArtiFrame — Zero-dependency native PHP framework with a powerful multilingual CLI. Scaffold projects, generate views, APIs and classes instantly.",
|
|
5
5
|
"main": "bin/artiframe.js",
|
|
6
6
|
"bin": {
|