nlfts-cli 2.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/Readme.md +92 -0
- package/bin/index.js +238 -0
- package/package.json +41 -0
package/Readme.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# 🚀 NL FTS CLI
|
|
2
|
+
|
|
3
|
+
**Fast Template Starter (FTS)** adalah tool CLI premium yang dirancang untuk membantu developer melakukan scaffolding project starter kit dengan cepat, cerdas, dan transparan.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/nlfts-cli)
|
|
6
|
+
[](https://github.com/davingm/nlfts-cli)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## ✨ Fitur Utama
|
|
11
|
+
|
|
12
|
+
- **⚡ Cepat & Ringan**: Download template dalam hitungan detik menggunakan `degit`.
|
|
13
|
+
- **📦 Smart Auto-Install**: Mendeteksi secara otomatis `npm`, `yarn`, atau `pnpm` dan menginstal dependensi segera setelah project dibuat.
|
|
14
|
+
- **📊 Real-time Progress**: Log instalasi yang transparan, tidak akan membuat Anda bingung apakah proses sedang berjalan atau tidak.
|
|
15
|
+
- **🎨 UI Premium**: Tampilan terminal yang bersih, berwarna, dan informatif terinspirasi dari tool kelas dunia seperti Laravel.
|
|
16
|
+
- **🛠 Koleksi Template**: Mendukung berbagai framework populer (Nuxt, Next.js, Express, Vue).
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 📥 Instalasi
|
|
21
|
+
|
|
22
|
+
Pasang secara global melalui npm:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install -g nlfts-cli
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
*Atau jalankan langsung tanpa instalasi:*
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx nlfts-cli <perintah>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 🛠 Penggunaan
|
|
37
|
+
|
|
38
|
+
Setelah terinstal, Anda bisa menggunakan perintah `fts`.
|
|
39
|
+
|
|
40
|
+
### 1. Melihat Daftar Template
|
|
41
|
+
Tampilkan semua starter kit yang tersedia beserta deskripsi dan tagnya.
|
|
42
|
+
```bash
|
|
43
|
+
fts list
|
|
44
|
+
# atau
|
|
45
|
+
fts ls
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 2. Membuat Project Baru
|
|
49
|
+
Inisialisasi project baru dari koleksi starter kit kami.
|
|
50
|
+
```bash
|
|
51
|
+
fts install <nama-template> [nama-folder-project]
|
|
52
|
+
# atau lebih singkat
|
|
53
|
+
fts i <nama-template> [nama-folder-project]
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Contoh:**
|
|
57
|
+
```bash
|
|
58
|
+
# Membuat project Nuxt di folder 'nuxt' (default)
|
|
59
|
+
fts i nuxt
|
|
60
|
+
|
|
61
|
+
# Membuat project Next.js di folder 'aplikasi-saya'
|
|
62
|
+
fts i next aplikasi-saya
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 📋 Daftar Template Tersedia
|
|
68
|
+
|
|
69
|
+
| Nama | Deskripsi | Tags |
|
|
70
|
+
| :--- | :--- | :--- |
|
|
71
|
+
| `nuxt` | Nuxt 3 + TailwindCSS Premium Starter | `fullstack`, `ssr` |
|
|
72
|
+
| `next` | Next.js 14 + Shadcn UI + Lucide Icons | `react`, `ui` |
|
|
73
|
+
| `express` | Express.js + Prisma + JWT + TypeScript | `backend`, `api` |
|
|
74
|
+
| `vue` | Vue 3 + Vite + Pinia Starter Kit | `frontend`, `vite` |
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## 🛠 Pengembangan (Local Development)
|
|
79
|
+
|
|
80
|
+
Jika Anda ingin memodifikasi CLI ini secara lokal:
|
|
81
|
+
|
|
82
|
+
1. Clone repository ini.
|
|
83
|
+
2. Jalankan `npm link` di dalam folder project.
|
|
84
|
+
3. Gunakan perintah `fts` untuk mencoba perubahan Anda.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## 📄 Lisensi
|
|
89
|
+
|
|
90
|
+
Project ini dilisensikan di bawah **MIT License**.
|
|
91
|
+
|
|
92
|
+
Dibuat dengan ❤️ oleh [davingm](https://github.com/davingm).
|
package/bin/index.js
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* FTS CLI - Installer Starter Kit Berperforma Tinggi
|
|
5
|
+
* Versi: 2.1.0
|
|
6
|
+
* Penulis: davingm
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Command } from 'commander';
|
|
10
|
+
import degit from 'degit';
|
|
11
|
+
import ora from 'ora';
|
|
12
|
+
import chalk from 'chalk';
|
|
13
|
+
import { spawn } from 'node:child_process';
|
|
14
|
+
import path from 'node:path';
|
|
15
|
+
import fs from 'node:fs';
|
|
16
|
+
import { fileURLToPath } from 'node:url';
|
|
17
|
+
|
|
18
|
+
// --- Konfigurasi & Konstanta ---
|
|
19
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
20
|
+
const __dirname = path.dirname(__filename);
|
|
21
|
+
|
|
22
|
+
// Daftar template yang tersedia
|
|
23
|
+
const TEMPLATES = {
|
|
24
|
+
'nuxt': {
|
|
25
|
+
repo: 'github:davingm/MyStudio',
|
|
26
|
+
desc: 'Nuxt 3 + TailwindCSS Starter Kit Premium',
|
|
27
|
+
tags: ['fullstack', 'frontend', 'ssr']
|
|
28
|
+
},
|
|
29
|
+
'next': {
|
|
30
|
+
repo: 'github:davinalifp/next-starter',
|
|
31
|
+
desc: 'Next.js 14 + Shadcn UI + Lucide Icons',
|
|
32
|
+
tags: ['react', 'nextjs', 'ui']
|
|
33
|
+
},
|
|
34
|
+
'express': {
|
|
35
|
+
repo: 'github:davinalifp/express-api-starter',
|
|
36
|
+
desc: 'Express.js + Prisma + JWT + TypeScript',
|
|
37
|
+
tags: ['backend', 'api', 'database']
|
|
38
|
+
},
|
|
39
|
+
'vue': {
|
|
40
|
+
repo: 'github:vuejs/starter-vite',
|
|
41
|
+
desc: 'Vue 3 + Vite + Pinia Starter Kit',
|
|
42
|
+
tags: ['frontend', 'vite', 'vue']
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const UI = {
|
|
47
|
+
// Garis pembatas untuk kerapihan terminal
|
|
48
|
+
divider: () => console.log(chalk.dim('─'.repeat(Math.min(process.stdout.columns || 80, 80)))),
|
|
49
|
+
spacer: () => console.log(''),
|
|
50
|
+
// Banner utama CLI
|
|
51
|
+
banner: () => {
|
|
52
|
+
console.clear();
|
|
53
|
+
console.log(chalk.bold.cyan(`
|
|
54
|
+
███████╗████████╗███████╗
|
|
55
|
+
██╔════╝╚══██╔══╝██╔════╝
|
|
56
|
+
█████╗ ██║ ███████╗
|
|
57
|
+
██╔══╝ ██║ ╚════██║
|
|
58
|
+
██║ ██║ ███████║
|
|
59
|
+
╚═╝ ╚═╝ ╚══════╝ `));
|
|
60
|
+
console.log(chalk.cyan.bold(' Fast Template Starter CLI v2.1'));
|
|
61
|
+
console.log(chalk.dim(' "Membangun masa depan, satu perintah sekaligus."\n'));
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// --- Fungsi Pembantu (Helpers) ---
|
|
66
|
+
|
|
67
|
+
// Mendeteksi package manager yang digunakan user
|
|
68
|
+
const getPackageManager = () => {
|
|
69
|
+
const userAgent = process.env.npm_config_user_agent || '';
|
|
70
|
+
if (userAgent.includes('yarn')) return 'yarn';
|
|
71
|
+
if (userAgent.includes('pnpm')) return 'pnpm';
|
|
72
|
+
if (userAgent.includes('bun')) return 'bun';
|
|
73
|
+
return 'npm';
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Menjalankan perintah terminal dan mengalirkan output secara real-time
|
|
78
|
+
*/
|
|
79
|
+
const runCommand = (command, args, cwd) => {
|
|
80
|
+
return new Promise((resolve, reject) => {
|
|
81
|
+
const isWindows = process.platform === 'win32';
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
// Mengatasi DEP0190: Menggunakan shell string tunggal untuk Windows
|
|
85
|
+
const child = isWindows
|
|
86
|
+
? spawn(`${command} ${args.join(' ')}`, { cwd, shell: true, stdio: ['inherit', 'pipe', 'pipe'] })
|
|
87
|
+
: spawn(command, args, { cwd, shell: false, stdio: ['inherit', 'pipe', 'pipe'] });
|
|
88
|
+
|
|
89
|
+
child.stdout.on('data', (data) => {
|
|
90
|
+
const lines = data.toString().split('\n');
|
|
91
|
+
lines.forEach(line => {
|
|
92
|
+
if (line.trim()) {
|
|
93
|
+
process.stdout.write(chalk.dim(` ⚡ ${line.trim()}\n`));
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
child.stderr.on('data', (data) => {
|
|
99
|
+
const line = data.toString().trim();
|
|
100
|
+
if (line) {
|
|
101
|
+
process.stdout.write(chalk.dim(` ⚡ ${line}\n`));
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
child.on('error', (err) => {
|
|
106
|
+
reject(err);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
child.on('close', (code) => {
|
|
110
|
+
if (code === 0) resolve();
|
|
111
|
+
else reject(new Error(`Proses berhenti dengan kode ${code}`));
|
|
112
|
+
});
|
|
113
|
+
} catch (e) {
|
|
114
|
+
reject(e);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// --- Logika Utama Aplikasi ---
|
|
120
|
+
|
|
121
|
+
const program = new Command();
|
|
122
|
+
|
|
123
|
+
program
|
|
124
|
+
.name('fts')
|
|
125
|
+
.description('Tools CLI Premium untuk scaffolding project Anda')
|
|
126
|
+
.version('2.1.0');
|
|
127
|
+
|
|
128
|
+
// PERINTAH: LIST (Melihat daftar template)
|
|
129
|
+
program
|
|
130
|
+
.command('list')
|
|
131
|
+
.alias('ls')
|
|
132
|
+
.description('Tampilkan semua starter kit yang tersedia')
|
|
133
|
+
.action(() => {
|
|
134
|
+
UI.banner();
|
|
135
|
+
console.log(chalk.bold('Daftar Template Tersedia:'));
|
|
136
|
+
UI.spacer();
|
|
137
|
+
|
|
138
|
+
Object.entries(TEMPLATES).forEach(([name, info]) => {
|
|
139
|
+
const namePath = chalk.green.bold(name.padEnd(12));
|
|
140
|
+
const tags = info.tags.map(t => chalk.bgCyan.black(` ${t} `)).join(' ');
|
|
141
|
+
console.log(` ${chalk.cyan('➜')} ${namePath} ${tags}`);
|
|
142
|
+
console.log(` ${chalk.dim(info.desc)}`);
|
|
143
|
+
UI.spacer();
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
UI.divider();
|
|
147
|
+
console.log(chalk.dim(` Jalankan ${chalk.yellow('fts install <nama>')} untuk mulai membangun.`));
|
|
148
|
+
UI.spacer();
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// PERINTAH: INSTALL (Membuat project baru)
|
|
152
|
+
program
|
|
153
|
+
.command('install <template> [project-name]')
|
|
154
|
+
.alias('i')
|
|
155
|
+
.description('Inisialisasi project baru dari starter kit')
|
|
156
|
+
.action(async (template, projectName) => {
|
|
157
|
+
UI.banner();
|
|
158
|
+
|
|
159
|
+
const selectedTemplate = TEMPLATES[template.toLowerCase()];
|
|
160
|
+
if (!selectedTemplate) {
|
|
161
|
+
console.log(chalk.red(` [ERROR] Template "${template}" tidak ditemukan dalam koleksi.`));
|
|
162
|
+
console.log(chalk.dim(` Coba jalankan ${chalk.cyan('fts list')} untuk melihat pilihan.\n`));
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const targetDir = projectName || template;
|
|
167
|
+
const fullPath = path.join(process.cwd(), targetDir);
|
|
168
|
+
|
|
169
|
+
// Validasi: Cek apakah folder tujuan sudah ada
|
|
170
|
+
if (fs.existsSync(fullPath)) {
|
|
171
|
+
console.log(chalk.red(` [ERROR] Folder "${targetDir}" sudah ada.`));
|
|
172
|
+
console.log(chalk.dim(` Silakan gunakan nama lain atau hapus folder tersebut terlebih dahulu.\n`));
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
console.log(chalk.bold.blue(` ✨ Persiapan: ${chalk.white(selectedTemplate.desc)}`));
|
|
177
|
+
console.log(chalk.dim(` 📍 Lokasi: ${fullPath}`));
|
|
178
|
+
UI.spacer();
|
|
179
|
+
|
|
180
|
+
const spinner = ora({
|
|
181
|
+
text: 'Mengambil artifacts template...',
|
|
182
|
+
color: 'cyan',
|
|
183
|
+
spinner: 'dots12'
|
|
184
|
+
}).start();
|
|
185
|
+
|
|
186
|
+
try {
|
|
187
|
+
// LANGKAH 1: Download Template menggunakan degit
|
|
188
|
+
const emitter = degit(selectedTemplate.repo, { cache: false, force: true });
|
|
189
|
+
await emitter.clone(targetDir);
|
|
190
|
+
spinner.succeed(chalk.green(' Berhasil mendownload artifacts template.'));
|
|
191
|
+
|
|
192
|
+
// LANGKAH 2: Menginstall Dependensi
|
|
193
|
+
const pkgManager = getPackageManager();
|
|
194
|
+
UI.spacer();
|
|
195
|
+
console.log(chalk.bold.yellow(` 📦 Menginstal dependensi melalui ${pkgManager}...`));
|
|
196
|
+
UI.divider();
|
|
197
|
+
|
|
198
|
+
try {
|
|
199
|
+
// Parameter tambahan untuk mempercepat & memperbersih log
|
|
200
|
+
const args = pkgManager === 'yarn' ? [] : ['install', '--no-audit', '--no-fund'];
|
|
201
|
+
await runCommand(pkgManager, args, fullPath);
|
|
202
|
+
|
|
203
|
+
UI.divider();
|
|
204
|
+
console.log(chalk.green(` ✅ Semua dependensi berhasil terinstall.`));
|
|
205
|
+
} catch (err) {
|
|
206
|
+
UI.divider();
|
|
207
|
+
console.log(chalk.red(` ⚠️ Gagal menginstal otomatis. Silakan jalankan "${pkgManager} install" secara manual.`));
|
|
208
|
+
console.log(chalk.dim(` Alasan: ${err.message}`));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// RINGKASAN SUKSES
|
|
212
|
+
UI.spacer();
|
|
213
|
+
console.log(chalk.bgGreen.black.bold(' SUKSES ') + chalk.green(' Project Anda siap untuk dikembangkan!'));
|
|
214
|
+
UI.spacer();
|
|
215
|
+
|
|
216
|
+
console.log(chalk.white(' Ikuti langkah berikut untuk memulai:'));
|
|
217
|
+
console.log(chalk.cyan(` 1. cd ${targetDir}`));
|
|
218
|
+
if (pkgManager === 'npm') {
|
|
219
|
+
console.log(chalk.cyan(' 2. npm run dev'));
|
|
220
|
+
} else {
|
|
221
|
+
console.log(chalk.cyan(` 2. ${pkgManager} dev`));
|
|
222
|
+
}
|
|
223
|
+
UI.spacer();
|
|
224
|
+
UI.divider();
|
|
225
|
+
console.log(chalk.dim(' Selamat Berkarya! – Tim FTS'));
|
|
226
|
+
UI.spacer();
|
|
227
|
+
|
|
228
|
+
} catch (err) {
|
|
229
|
+
// Penanganan error saat download atau inisialisasi awal
|
|
230
|
+
spinner.fail(chalk.red(' Gagal menyiapkan project.'));
|
|
231
|
+
UI.spacer();
|
|
232
|
+
console.log(chalk.bgRed.white(' DETAIL ERROR '));
|
|
233
|
+
console.error(chalk.red(err.message));
|
|
234
|
+
UI.spacer();
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
program.parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nlfts-cli",
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "CLI Premium untuk scaffolding project starter kit dengan cepat dan cerdas.",
|
|
5
|
+
"main": "./bin/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"fts": "./bin/index.js"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"engines": {
|
|
11
|
+
"node": ">=18.0.0"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"cli",
|
|
18
|
+
"scaffolding",
|
|
19
|
+
"starter-kit",
|
|
20
|
+
"nuxt",
|
|
21
|
+
"nextjs",
|
|
22
|
+
"express",
|
|
23
|
+
"fts",
|
|
24
|
+
"automation"
|
|
25
|
+
],
|
|
26
|
+
"author": "davingm",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"chalk": "^5.6.2",
|
|
30
|
+
"commander": "^14.0.3",
|
|
31
|
+
"degit": "^2.8.4",
|
|
32
|
+
"ora": "^9.3.0"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"bin",
|
|
36
|
+
"README.md"
|
|
37
|
+
],
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
}
|
|
41
|
+
}
|