tsoft-cli 1.1.1 → 1.2.1
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/CHANGELOG.md +30 -0
- package/README.md +111 -0
- package/bin/index.js +62 -20
- package/jest.config.js +3 -0
- package/package.json +7 -3
- package/src/client-credentials.js +13 -12
- package/src/commands/create.js +86 -20
- package/src/commands/start.js +137 -175
- package/src/file-manager.js +7 -1
- package/src/theme-manager.js +42 -7
- package/src/tsoft.js +41 -13
- package/src/utils.js +45 -0
- package/tests/FileManager.test.js +90 -0
- package/src/commands/save.js +0 -17
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [1.2.0] - 2024-06-12
|
|
4
|
+
### Added
|
|
5
|
+
- Yeni site ismi girildiğinde geçerli olup olmadığını kontrol eden özellik eklendi.
|
|
6
|
+
- Kullanıcı komut satırı etkileşimleri için `enquirer` kütüphanesi kullanımı güncellendi.
|
|
7
|
+
- Dosya izleme ve tema güncelleme özellikleri geliştirildi.
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
- `ThemeManager` sınıfı geliştirildi ve yeni yöntemler eklendi.
|
|
11
|
+
- `start.js` dosyasında önemli iyileştirmeler yapıldı.
|
|
12
|
+
- `create.js` dosyasında kullanıcı girişleri doğrulandı ve daha kullanıcı dostu hale getirildi.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
- Birkaç hata düzeltildi ve genel kod kalitesi iyileştirildi.
|
|
16
|
+
|
|
17
|
+
# Changelog
|
|
18
|
+
|
|
19
|
+
## [1.2.1] - 2024-06-13
|
|
20
|
+
### Added
|
|
21
|
+
- T-Soft CLI'de yeni bir site oluşturma ve geçerliliğini kontrol etme özelliği eklendi.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
- `start.js` ve `create.js` dosyalarında refaktörizasyon yapıldı.
|
|
25
|
+
- T-Soft CLI ana menüsü, site ve tema seçimlerinin interaktif hale getirilmesi amacıyla güncellendi.
|
|
26
|
+
- Tüm metinler Türkçeleştirildi ve kullanıcıya daha açıklayıcı mesajlar sağlandı.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
- Geliştirme ortamı başlatıldığında programın beklenmedik şekilde kapanmasına sebep olan hata giderildi.
|
|
30
|
+
- T-Soft CLI'nın `start.js` dosyasında initialize fonksiyonunun doğru şekilde çalışmaması sorunu çözüldü.
|
package/README.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<style>
|
|
2
|
+
.container { max-width: 800px; margin: 0 auto; padding: 20px; box-shadow: 0 0 10px rgba(0,0,0,0.1); }
|
|
3
|
+
</style>
|
|
4
|
+
T-Soft CLI Kullanım Kılavuzu
|
|
5
|
+
|
|
6
|
+
T-Soft CLI Kullanım Kılavuzu
|
|
7
|
+
============================
|
|
8
|
+
|
|
9
|
+
Açıklama
|
|
10
|
+
--------
|
|
11
|
+
|
|
12
|
+
T-Soft CLI, T-Soft için tema geliştirmek isteyen geliştiriciler için özel olarak hazırlanmış bir komut satırı arayüzüdür. Bu araç ile yeni temalar oluşturabilir, mevcut temaları düzenleyebilir ve geliştirme ortamınızı kolaylıkla yönetebilirsiniz.
|
|
13
|
+
|
|
14
|
+
Kurulum
|
|
15
|
+
-------
|
|
16
|
+
|
|
17
|
+
CLI aracını kullanmaya başlamadan önce, aşağıdaki adımları izleyerek T-Soft CLI'yı kurmanız gerekmektedir:
|
|
18
|
+
|
|
19
|
+
### NPM ile Kurulum
|
|
20
|
+
|
|
21
|
+
T-Soft CLI'yı global olarak kurmak için aşağıdaki komutu çalıştırın:
|
|
22
|
+
|
|
23
|
+
npm install -g tsoft-cli
|
|
24
|
+
|
|
25
|
+
Kullanım
|
|
26
|
+
--------
|
|
27
|
+
|
|
28
|
+
CLI arayüzünü çalıştırmak için terminale `tsoft-cli` yazmanız yeterlidir:
|
|
29
|
+
|
|
30
|
+
tsoft-cli
|
|
31
|
+
|
|
32
|
+
### Ana Menü
|
|
33
|
+
|
|
34
|
+
CLI başlatıldığında aşağıdaki seçeneklerle ana menü görünür:
|
|
35
|
+
|
|
36
|
+
* Yeni bir tema oluştur
|
|
37
|
+
* Geliştirme ortamını başlat
|
|
38
|
+
* Çıkış
|
|
39
|
+
|
|
40
|
+
### Yeni Bir Tema Oluşturma
|
|
41
|
+
|
|
42
|
+
Yeni bir tema oluşturmak için aşağıdaki adımları izleyin:
|
|
43
|
+
|
|
44
|
+
1. **Yeni Tema Oluşturma Seçeneğini Seçin**: Ana menüden `Yeni bir tema oluştur` seçeneğini seçin.
|
|
45
|
+
2. **Site Adı Seçimi**:
|
|
46
|
+
* Mevcut sitelerden birini seçin veya `Yeni bir site oluştur` seçeneğini seçin.
|
|
47
|
+
* Yeni bir site oluşturmak istiyorsanız, site adını girin. Bu ad, geçerliliği kontrol edilecektir.
|
|
48
|
+
3. **Tema Detayları**:
|
|
49
|
+
* Tema adı, yazar adı (isteğe bağlı) ve versiyon numarasını girin.
|
|
50
|
+
4. **Tema Oluşturma**: Tema başarıyla oluşturulduktan sonra otomatik olarak geliştirme ortamına geçilir.
|
|
51
|
+
|
|
52
|
+
### Geliştirme Ortamını Başlatma
|
|
53
|
+
|
|
54
|
+
Mevcut bir temayı düzenlemek veya geliştirmek için geliştirme ortamını başlatabilirsiniz:
|
|
55
|
+
|
|
56
|
+
1. **Geliştirme Ortamını Başlatma Seçeneğini Seçin**: Ana menüden `Geliştirme ortamını başlat` seçeneğini seçin.
|
|
57
|
+
2. **Site ve Tema Seçimi**:
|
|
58
|
+
* Mevcut sitelerden birini seçin.
|
|
59
|
+
* Seçilen sitedeki temalardan birini seçin.
|
|
60
|
+
3. **Geliştirme Ortamı**: Seçilen tema için geliştirme ortamı başlatılır ve dosya değişiklikleri izlenir.
|
|
61
|
+
|
|
62
|
+
### Geliştirme Ortamında Kullanılabilir Komutlar
|
|
63
|
+
|
|
64
|
+
Geliştirme ortamında aşağıdaki komutları kullanabilirsiniz:
|
|
65
|
+
|
|
66
|
+
* `q`: Dosya izlemeyi sonlandırır.
|
|
67
|
+
* `u`: Temayı günceller.
|
|
68
|
+
* `s`: Tüm dosyaları kaydeder.
|
|
69
|
+
* `e`: `.theme` dosyasını düzenler.
|
|
70
|
+
* `o`: Tema dizinini açar.
|
|
71
|
+
|
|
72
|
+
Proje Yapısı
|
|
73
|
+
------------
|
|
74
|
+
|
|
75
|
+
Projenizin dosya yapısı şu şekildedir:
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
tsoft-cli/
|
|
79
|
+
├── bin/
|
|
80
|
+
│ └── index.js
|
|
81
|
+
├── src/
|
|
82
|
+
│ ├── commands/
|
|
83
|
+
│ │ ├── create.js
|
|
84
|
+
│ │ └── start.js
|
|
85
|
+
│ ├── tsoft/
|
|
86
|
+
│ │ └── themeManager.js
|
|
87
|
+
│ ├── utils.js
|
|
88
|
+
│ └── constants.js
|
|
89
|
+
├── CHANGELOG.md
|
|
90
|
+
├── package.json
|
|
91
|
+
└── README.md
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
### Dosya ve Klasör Açıklamaları
|
|
95
|
+
|
|
96
|
+
* `bin/index.js`: Ana CLI giriş noktasıdır. Kullanıcı komutları burada işlenir ve ilgili komut dosyaları çalıştırılır.
|
|
97
|
+
* `src/commands/create.js`: Yeni bir tema oluşturmak için kullanılan komut dosyasıdır. Kullanıcıdan site ve tema adı alır ve temayı oluşturur.
|
|
98
|
+
* `src/commands/start.js`: Geliştirme ortamını başlatmak için kullanılan komut dosyasıdır. Dosya değişikliklerini izler ve temayı günceller.
|
|
99
|
+
* `src/tsoft/themeManager.js`: Tema yönetimi işlemlerini gerçekleştiren sınıftır. Temanın başlatılması, geçerliliğinin kontrol edilmesi ve ortamın oluşturulması işlemlerini yapar.
|
|
100
|
+
* `src/utils.js`: Yardımcı fonksiyonlar içerir.
|
|
101
|
+
* `src/constants.js`: Sabit değerleri içerir.
|
|
102
|
+
|
|
103
|
+
Katkıda Bulunma
|
|
104
|
+
---------------
|
|
105
|
+
|
|
106
|
+
Proje açık kaynaklıdır ve katkılara açıktır. Katkıda bulunmak isterseniz, lütfen bir pull request gönderin veya bir issue açın.
|
|
107
|
+
|
|
108
|
+
Lisans
|
|
109
|
+
------
|
|
110
|
+
|
|
111
|
+
Bu proje ISC lisansı altında lisanslanmıştır. Daha fazla bilgi için `LICENSE` dosyasına bakabilirsiniz.
|
package/bin/index.js
CHANGED
|
@@ -1,29 +1,71 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const { Select } = require('enquirer');
|
|
4
4
|
const { start } = require('../src/commands/start');
|
|
5
|
-
const { save } = require('../src/commands/save');
|
|
6
5
|
const { createTheme } = require('../src/commands/create');
|
|
6
|
+
const { clearScreen, displayAsciiArt } = require('../src/utils');
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
.
|
|
10
|
-
|
|
11
|
-
.
|
|
12
|
-
|
|
13
|
-
});
|
|
10
|
+
async function getDirectories(source) {
|
|
11
|
+
return fs.readdirSync(source).filter(file => {
|
|
12
|
+
return file.charAt(0) !== '.' && !['node_modules', 'build', 'dist'].includes(file);
|
|
13
|
+
}).filter(file => fs.statSync(path.join(source, file)).isDirectory());
|
|
14
|
+
}
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
async function selectFromChoices(message, choices) {
|
|
17
|
+
const prompt = new Select({
|
|
18
|
+
name: 'selection',
|
|
19
|
+
message: message,
|
|
20
|
+
choices: choices
|
|
20
21
|
});
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
return await prompt.run();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function selectSiteAndTheme() {
|
|
27
|
+
const cwd = process.cwd();
|
|
28
|
+
const sites = await getDirectories(cwd);
|
|
29
|
+
|
|
30
|
+
if (sites.length === 0) {
|
|
31
|
+
console.error('Mevcut dizinde site bulunamadı.');
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const selectedSite = await selectFromChoices('Bir site seçin:', sites);
|
|
36
|
+
const themes = await getDirectories(path.join(cwd, selectedSite));
|
|
37
|
+
|
|
38
|
+
if (themes.length === 0) {
|
|
39
|
+
console.error('Seçilen site dizininde tema bulunamadı.');
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const selectedTheme = await selectFromChoices('Bir tema seçin:', themes);
|
|
44
|
+
|
|
45
|
+
return { siteName: selectedSite, themeName: selectedTheme };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function showMainMenu() {
|
|
49
|
+
clearScreen();
|
|
50
|
+
await displayAsciiArt();
|
|
51
|
+
|
|
52
|
+
const commandChoices = ['Yeni bir tema oluştur', 'Geliştirme ortamını başlat', 'Çıkış'];
|
|
53
|
+
const selectedCommand = await selectFromChoices('Bir komut seçin', commandChoices);
|
|
54
|
+
|
|
55
|
+
switch (selectedCommand) {
|
|
56
|
+
case 'Yeni bir tema oluştur':
|
|
57
|
+
await createTheme();
|
|
58
|
+
break;
|
|
59
|
+
case 'Geliştirme ortamını başlat':
|
|
60
|
+
const selection = await selectSiteAndTheme();
|
|
61
|
+
if (selection) {
|
|
62
|
+
await start(selection.siteName, selection.themeName);
|
|
63
|
+
}
|
|
64
|
+
break;
|
|
65
|
+
case 'Çıkış':
|
|
66
|
+
console.log('Programdan çıkılıyor. Hoşça kalın!');
|
|
67
|
+
process.exit(0);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
28
70
|
|
|
29
|
-
|
|
71
|
+
showMainMenu();
|
package/jest.config.js
ADDED
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tsoft-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "A theme development cli for developers who want to create themes for T-Soft.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "
|
|
7
|
+
"test": "jest"
|
|
8
8
|
},
|
|
9
9
|
"keywords": [],
|
|
10
10
|
"author": "",
|
|
@@ -20,5 +20,9 @@
|
|
|
20
20
|
"figlet": "^1.7.0",
|
|
21
21
|
"fs": "^0.0.1-security"
|
|
22
22
|
},
|
|
23
|
-
"type": "commonjs"
|
|
23
|
+
"type": "commonjs",
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"jest": "^29.7.0",
|
|
26
|
+
"mock-fs": "^5.2.0"
|
|
27
|
+
}
|
|
24
28
|
}
|
|
@@ -12,10 +12,7 @@ class ClientCredentials {
|
|
|
12
12
|
|
|
13
13
|
getEnvironment() {
|
|
14
14
|
return {
|
|
15
|
-
site: this.site,
|
|
16
|
-
clientId: this.clientId,
|
|
17
|
-
clientSecret: this.clientSecret,
|
|
18
|
-
bearer: this.bearer
|
|
15
|
+
site: this.site, clientId: this.clientId, clientSecret: this.clientSecret, bearer: this.bearer
|
|
19
16
|
}
|
|
20
17
|
}
|
|
21
18
|
|
|
@@ -32,12 +29,18 @@ class ClientCredentials {
|
|
|
32
29
|
return this;
|
|
33
30
|
}
|
|
34
31
|
|
|
35
|
-
async register(CLIENT_UUID) {
|
|
32
|
+
async register(CLIENT_UUID, clientConfiguration = {}) {
|
|
36
33
|
|
|
37
34
|
const uri = "api/v3/admin/auth/auth-application";
|
|
38
35
|
const result = await this.buildPostRequest(uri, {
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
header: {
|
|
37
|
+
'Content-Type': 'application/json', 'Accept': 'application/json',
|
|
38
|
+
}, body: JSON.stringify({
|
|
39
|
+
uuid: CLIENT_UUID, configuration: {
|
|
40
|
+
theme: clientConfiguration.theme,
|
|
41
|
+
author: clientConfiguration.author,
|
|
42
|
+
version: clientConfiguration.version
|
|
43
|
+
}
|
|
41
44
|
})
|
|
42
45
|
});
|
|
43
46
|
|
|
@@ -54,8 +57,7 @@ class ClientCredentials {
|
|
|
54
57
|
const uri = "api/v3/admin/auth/auth-application/authorize";
|
|
55
58
|
await this.buildPostRequest(uri, {
|
|
56
59
|
body: JSON.stringify({
|
|
57
|
-
public_key: this.clientId,
|
|
58
|
-
secret: this.clientSecret
|
|
60
|
+
public_key: this.clientId, secret: this.clientSecret
|
|
59
61
|
})
|
|
60
62
|
}).then((result) => {
|
|
61
63
|
if (result.status === true) {
|
|
@@ -75,12 +77,11 @@ class ClientCredentials {
|
|
|
75
77
|
const response = await buildPostRequest(this.site, uri, {
|
|
76
78
|
body: JSON.stringify({
|
|
77
79
|
_method: 'GET'
|
|
78
|
-
}),
|
|
79
|
-
headers: {
|
|
80
|
+
}), headers: {
|
|
80
81
|
Authorization: `Bearer ${token}`
|
|
81
82
|
}
|
|
82
83
|
});
|
|
83
|
-
return response.message === 'ok';
|
|
84
|
+
return response.message === 'ok';
|
|
84
85
|
}
|
|
85
86
|
}
|
|
86
87
|
|
package/src/commands/create.js
CHANGED
|
@@ -1,24 +1,69 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const { Input } = require('enquirer');
|
|
3
|
+
const { Select, Input } = require('enquirer');
|
|
4
|
+
const { slugify } = require('../utils');
|
|
5
|
+
const { start } = require('./start');
|
|
6
|
+
const ThemeManager = require('../theme-manager');
|
|
4
7
|
|
|
5
|
-
async function
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
async function getSites() {
|
|
9
|
+
const cwd = process.cwd();
|
|
10
|
+
return fs.readdirSync(cwd).filter(file => {
|
|
11
|
+
return file.charAt(0) !== '.' && !['node_modules', 'build', 'dist'].includes(file);
|
|
12
|
+
}).filter(file => fs.statSync(path.join(cwd, file)).isDirectory());
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async function selectSite(sites) {
|
|
16
|
+
const siteChoices = [...sites, 'Yeni bir site oluştur'];
|
|
17
|
+
|
|
18
|
+
const sitePrompt = new Select({
|
|
19
|
+
name: 'site',
|
|
20
|
+
message: 'Çalışmak istediğiniz sitenin adı:',
|
|
21
|
+
choices: siteChoices
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const selectedSite = await sitePrompt.run();
|
|
25
|
+
|
|
26
|
+
if (selectedSite === 'Yeni bir site oluştur') {
|
|
27
|
+
return await createNewSite();
|
|
28
|
+
} else {
|
|
29
|
+
return selectedSite;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function createNewSite() {
|
|
34
|
+
const newSitePrompt = new Input({
|
|
35
|
+
name: 'newSite',
|
|
36
|
+
message: 'Yeni site adı:'
|
|
9
37
|
});
|
|
38
|
+
const siteName = await newSitePrompt.run();
|
|
39
|
+
|
|
40
|
+
const themeManager = new ThemeManager(siteName);
|
|
41
|
+
const isValid = await validateSiteName(themeManager, siteName);
|
|
42
|
+
if (!isValid) return null;
|
|
43
|
+
|
|
44
|
+
return siteName;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function validateSiteName(themeManager, siteName) {
|
|
48
|
+
try {
|
|
49
|
+
const isValid = await themeManager.checkSiteValidity(siteName);
|
|
50
|
+
if (!isValid) {
|
|
51
|
+
console.error('Geçersiz site adı. Lütfen geçerli bir site adı girin.');
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
return true;
|
|
55
|
+
} catch (error) {
|
|
56
|
+
console.error('Site doğrulaması sırasında hata oluştu:', error.message);
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
10
60
|
|
|
61
|
+
async function getThemeDetails() {
|
|
11
62
|
const themeNamePrompt = new Input({
|
|
12
63
|
name: 'themeName',
|
|
13
64
|
message: 'Tema adı:'
|
|
14
65
|
});
|
|
15
66
|
|
|
16
|
-
const directoryNamePrompt = new Input({
|
|
17
|
-
name: 'directoryName',
|
|
18
|
-
message: 'Tema dizin ismi (a-z yalnızca İngilizce karakterler):',
|
|
19
|
-
validate: input => /^[a-z]+$/.test(input) ? true : 'Yalnızca küçük İngilizce harfler kullanabilirsiniz.'
|
|
20
|
-
});
|
|
21
|
-
|
|
22
67
|
const authorPrompt = new Input({
|
|
23
68
|
name: 'author',
|
|
24
69
|
message: 'Author (isteğe bağlı):'
|
|
@@ -30,30 +75,51 @@ async function createTheme() {
|
|
|
30
75
|
initial: '1.0.0'
|
|
31
76
|
});
|
|
32
77
|
|
|
33
|
-
const siteName = await sitePrompt.run();
|
|
34
78
|
const themeName = await themeNamePrompt.run();
|
|
35
|
-
const directoryName = await directoryNamePrompt.run();
|
|
36
79
|
const author = await authorPrompt.run();
|
|
37
80
|
const version = await versionPrompt.run();
|
|
38
81
|
|
|
82
|
+
return { themeName, author, version };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function createThemeDirectory(siteName, themeNameSlug) {
|
|
39
86
|
const cwd = process.cwd();
|
|
40
|
-
const themePath = path.join(cwd, siteName,
|
|
87
|
+
const themePath = path.join(cwd, siteName, themeNameSlug);
|
|
41
88
|
|
|
42
89
|
if (!fs.existsSync(themePath)) {
|
|
43
90
|
fs.mkdirSync(themePath, { recursive: true });
|
|
44
91
|
}
|
|
45
92
|
|
|
93
|
+
return themePath;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function saveThemeData(themePath, themeData) {
|
|
97
|
+
fs.writeFileSync(path.join(themePath, '.theme'), JSON.stringify(themeData, null, 2));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async function createTheme() {
|
|
101
|
+
const sites = await getSites();
|
|
102
|
+
const siteName = await selectSite(sites);
|
|
103
|
+
|
|
104
|
+
if (!siteName) return;
|
|
105
|
+
|
|
106
|
+
const { themeName, author, version } = await getThemeDetails();
|
|
107
|
+
const themeNameSlug = slugify(themeName);
|
|
108
|
+
const themePath = await createThemeDirectory(siteName, themeNameSlug);
|
|
109
|
+
|
|
46
110
|
const themeData = {
|
|
47
|
-
siteName,
|
|
48
|
-
themeName,
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
version
|
|
111
|
+
site: siteName,
|
|
112
|
+
theme: themeName,
|
|
113
|
+
author: author,
|
|
114
|
+
version: version
|
|
52
115
|
};
|
|
53
116
|
|
|
54
|
-
|
|
117
|
+
await saveThemeData(themePath, themeData);
|
|
55
118
|
|
|
56
119
|
console.log(`Tema "${themeName}" başarıyla oluşturuldu.`);
|
|
120
|
+
|
|
121
|
+
// Doğrudan start fonksiyonuna geçiş yap
|
|
122
|
+
await start(siteName, themeNameSlug);
|
|
57
123
|
}
|
|
58
124
|
|
|
59
125
|
module.exports = {
|
package/src/commands/start.js
CHANGED
|
@@ -1,43 +1,25 @@
|
|
|
1
|
-
const Tsoft = require('../tsoft');
|
|
2
|
-
const constants = require('../constants');
|
|
3
1
|
const fs = require('fs');
|
|
4
2
|
const path = require('path');
|
|
5
|
-
const {Input, Select, Confirm, prompt} = require('enquirer');
|
|
6
3
|
const chokidar = require('chokidar');
|
|
7
|
-
const figlet = require('figlet');
|
|
8
4
|
const readline = require('readline');
|
|
5
|
+
const { exec } = require('child_process');
|
|
6
|
+
const Tsoft = require('../tsoft');
|
|
7
|
+
const constants = require('../constants');
|
|
9
8
|
const cliProgress = require('cli-progress');
|
|
10
|
-
const {
|
|
11
|
-
|
|
12
|
-
async function displayAsciiArt() {
|
|
13
|
-
return new Promise((resolve, reject) => {
|
|
14
|
-
figlet('T-SOFT', {
|
|
15
|
-
font: 'Standard',
|
|
16
|
-
}, (err, data) => {
|
|
17
|
-
if (err) {
|
|
18
|
-
console.log('Something went wrong...');
|
|
19
|
-
console.dir(err);
|
|
20
|
-
reject(err);
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
console.log(data);
|
|
24
|
-
resolve();
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
}
|
|
9
|
+
const { Input } = require('enquirer');
|
|
10
|
+
const { displayAsciiArt, clearScreen, info } = require('../utils');
|
|
28
11
|
|
|
29
12
|
async function showProgress(tsoft, theme) {
|
|
30
13
|
const themePath = path.join(process.cwd(), tsoft.site, theme);
|
|
31
14
|
const fileList = tsoft.fileManager.listFilesRecursive(themePath).filter(file => !file.includes('.env'));
|
|
32
15
|
const totalFiles = fileList.length;
|
|
33
16
|
|
|
34
|
-
// Create a new progress bar instance and use shades_classic theme
|
|
35
17
|
const progressBar = new cliProgress.SingleBar({
|
|
36
|
-
format: '
|
|
18
|
+
format: 'İlerleme |{bar}| {percentage}% || {value}/{total} Dosya Yüklendi',
|
|
37
19
|
barCompleteChar: '\u2588',
|
|
38
20
|
barIncompleteChar: '\u2591',
|
|
39
21
|
hideCursor: true,
|
|
40
|
-
clearOnComplete:
|
|
22
|
+
clearOnComplete: true
|
|
41
23
|
});
|
|
42
24
|
progressBar.start(totalFiles, 0);
|
|
43
25
|
|
|
@@ -47,182 +29,84 @@ async function showProgress(tsoft, theme) {
|
|
|
47
29
|
const content = tsoft.fileManager.readFile(file);
|
|
48
30
|
const env = tsoft.themeManager.getEnvironment(theme);
|
|
49
31
|
|
|
50
|
-
|
|
51
32
|
try {
|
|
52
33
|
await tsoft.saveFile(theme, fileName, content, env.bearer);
|
|
53
34
|
} catch (error) {
|
|
54
|
-
console.error(`
|
|
35
|
+
console.error(`Dosya yükleme hatası ${fileName}:`, error);
|
|
55
36
|
}
|
|
56
37
|
progressBar.update(i + 1);
|
|
57
38
|
}
|
|
58
39
|
|
|
59
40
|
progressBar.stop();
|
|
60
41
|
|
|
61
|
-
return '
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
async function updateTheme(tsoft, theme) {
|
|
65
|
-
const directoryName = path.basename(path.join(process.cwd(), tsoft.site, theme));
|
|
66
|
-
const response = await tsoft.updateTheme(directoryName);
|
|
67
|
-
if (response.status === true) {
|
|
68
|
-
return 'Successfully updated';
|
|
69
|
-
} else {
|
|
70
|
-
throw new Error('Update failed');
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function clearScreen() {
|
|
75
|
-
process.stdout.write('\x1B[2J\x1B[0f');
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async function editThemeFile(themeManager, directoryName) {
|
|
79
|
-
const themePath = path.join(process.cwd(), themeManager.site, directoryName, '.theme');
|
|
80
|
-
|
|
81
|
-
if (!fs.existsSync(themePath)) {
|
|
82
|
-
console.error('.theme file not found.');
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
console.log(`Opening .theme file: ${themePath}`);
|
|
87
|
-
const openCommand = process.platform === 'win32' ? 'start' :
|
|
88
|
-
process.platform === 'darwin' ? 'open' :
|
|
89
|
-
'xdg-open';
|
|
90
|
-
|
|
91
|
-
exec(`${openCommand} ${themePath}`, (err) => {
|
|
92
|
-
if (err) {
|
|
93
|
-
console.error('Failed to open .theme file:', err);
|
|
94
|
-
} else {
|
|
95
|
-
console.log('.theme file opened successfully.');
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function info() {
|
|
101
|
-
console.log('\n' +
|
|
102
|
-
'********************************************************\n' +
|
|
103
|
-
'* *\n' +
|
|
104
|
-
'* Press "q" to quit watching, "u" to update theme, *\n' +
|
|
105
|
-
'* "s" to save the theme, "e" to edit .theme file. *\n' +
|
|
106
|
-
'* *\n' +
|
|
107
|
-
'********************************************************\n'
|
|
108
|
-
);
|
|
42
|
+
return 'Tüm dosyalar ilerleme ile başarıyla yüklendi';
|
|
109
43
|
}
|
|
110
44
|
|
|
111
|
-
async function
|
|
112
|
-
|
|
113
|
-
await displayAsciiArt();
|
|
114
|
-
const cwd = process.cwd();
|
|
115
|
-
const sites = fs.readdirSync(cwd).filter(file => {
|
|
116
|
-
return file.charAt(0) !== '.' && !['node_modules', 'build', 'dist'].includes(file);
|
|
117
|
-
}).filter(file => fs.statSync(path.join(cwd, file)).isDirectory());
|
|
45
|
+
async function initializeAndAuthorize(tsoft, themeName) {
|
|
46
|
+
await tsoft.initialize(themeName);
|
|
118
47
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const sitePrompt = new Select({
|
|
125
|
-
name: 'selectedSite',
|
|
126
|
-
message: 'Please select a site:',
|
|
127
|
-
choices: sites
|
|
48
|
+
const approvalPrompt = new Input({
|
|
49
|
+
name: 'approval',
|
|
50
|
+
message: 'Lütfen onay kodunu sağlayın:'
|
|
128
51
|
});
|
|
129
52
|
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
const sitePath = path.join(cwd, selectedSite);
|
|
133
|
-
const themes = fs.readdirSync(sitePath).filter(file => fs.statSync(path.join(sitePath, file)).isDirectory());
|
|
53
|
+
const approval = await approvalPrompt.run();
|
|
134
54
|
|
|
135
|
-
if (
|
|
136
|
-
|
|
137
|
-
|
|
55
|
+
if (approval) {
|
|
56
|
+
await constants.APPROVAL.handler(tsoft.clientCredentials.setClientSecret(approval));
|
|
57
|
+
tsoft.buildEnvironment();
|
|
58
|
+
console.info('Hazırsınız');
|
|
59
|
+
return true;
|
|
60
|
+
} else {
|
|
61
|
+
console.error('Onay kodu gerekli.');
|
|
62
|
+
return false;
|
|
138
63
|
}
|
|
64
|
+
}
|
|
139
65
|
|
|
140
|
-
|
|
141
|
-
name: 'selectedTheme',
|
|
142
|
-
message: 'Please select a theme:',
|
|
143
|
-
choices: themes
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
const selectedTheme = await themePrompt.run();
|
|
147
|
-
const themeEnvPath = path.join(sitePath, selectedTheme, `${selectedTheme}.env`);
|
|
148
|
-
|
|
149
|
-
// Check if .env file exists and contains a valid JSON with a bearer attribute
|
|
66
|
+
async function handleExistingEnvironment(tsoft, themeName, themeEnvPath) {
|
|
150
67
|
let envData = {};
|
|
151
68
|
if (fs.existsSync(themeEnvPath)) {
|
|
152
69
|
try {
|
|
153
70
|
envData = JSON.parse(fs.readFileSync(themeEnvPath, 'utf-8'));
|
|
154
71
|
} catch (error) {
|
|
155
|
-
console.warn(
|
|
72
|
+
console.warn(`${themeEnvPath} dosyasında geçersiz JSON formatı. Bu dosya silinecek ve yeniden yetkilendirmeniz gerekecek.`);
|
|
156
73
|
fs.unlinkSync(themeEnvPath);
|
|
157
|
-
console.info('
|
|
74
|
+
console.info('Geçersiz ortam dosyası silindi. Başlatma işlemine devam ediliyor...');
|
|
158
75
|
}
|
|
159
76
|
|
|
160
77
|
if (envData.bearer) {
|
|
161
|
-
const
|
|
162
|
-
const bearerTokenValid = await tsoft.isTokenValid(selectedTheme);
|
|
78
|
+
const bearerTokenValid = await tsoft.isTokenValid(themeName);
|
|
163
79
|
|
|
164
80
|
if (bearerTokenValid) {
|
|
165
|
-
console.info('
|
|
166
|
-
|
|
167
|
-
await startWatching(selectedSite, selectedTheme, tsoft);
|
|
168
|
-
return;
|
|
81
|
+
console.info('Geçerli bir taşıyıcı jetonuna sahip mevcut ortam dosyası bulundu. Mevcut yapılandırma ile devam ediliyor...');
|
|
82
|
+
return true;
|
|
169
83
|
} else {
|
|
170
|
-
console.warn('
|
|
84
|
+
console.warn('Mevcut taşıyıcı jetonu geçersiz. Yeniden yetkilendirmeniz gerekecek.');
|
|
171
85
|
fs.unlinkSync(themeEnvPath);
|
|
172
86
|
}
|
|
173
87
|
}
|
|
174
88
|
}
|
|
175
|
-
|
|
176
|
-
let t = new Tsoft(selectedSite);
|
|
177
|
-
const initializeResult = await t.initialize(selectedTheme, {reset: false});
|
|
178
|
-
|
|
179
|
-
const approvalPrompt = new Input({
|
|
180
|
-
name: 'approval',
|
|
181
|
-
message: 'Please provide the approval code:'
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
const approval = await approvalPrompt.run();
|
|
185
|
-
|
|
186
|
-
if (approval) {
|
|
187
|
-
await constants.APPROVAL.handler(t.clientCredentials.setClientSecret(approval));
|
|
188
|
-
t.buildEnvironment();
|
|
189
|
-
console.info('You are ready to go');
|
|
190
|
-
|
|
191
|
-
// Start watching for file changes
|
|
192
|
-
await startWatching(selectedSite, selectedTheme, t);
|
|
193
|
-
}
|
|
89
|
+
return false;
|
|
194
90
|
}
|
|
195
91
|
|
|
196
|
-
async function startWatching(
|
|
197
|
-
const themePath = path.join(process.cwd(), site, theme);
|
|
198
|
-
const envPath = path.join(themePath, `${theme}.env`);
|
|
199
|
-
|
|
200
|
-
if (!fs.existsSync(envPath)) {
|
|
201
|
-
console.error('Environment file not found. Please initialize the theme first.');
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
|
|
92
|
+
async function startWatching(themePath, tsoft, theme) {
|
|
205
93
|
const watcher = chokidar.watch(themePath, {
|
|
206
|
-
ignored: /(^|[\/\\])
|
|
94
|
+
ignored: /(^|[\/\\])(\.theme|(.*?)\.env)$/, // .theme ve .env dosyaları yoksayılır
|
|
207
95
|
persistent: true
|
|
208
96
|
});
|
|
209
97
|
|
|
210
98
|
watcher.on('change', async (filePath) => {
|
|
211
|
-
console.log(`
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
console.log(`File ${fileName} uploaded successfully`);
|
|
220
|
-
} catch (error) {
|
|
221
|
-
console.error(`Error uploading file ${fileName}:`, error);
|
|
222
|
-
}
|
|
99
|
+
console.log(`Dosya değiştirildi ${filePath}`);
|
|
100
|
+
await handleFileChange(filePath, tsoft, theme);
|
|
101
|
+
}).on('unlink', async (filePath) => {
|
|
102
|
+
console.log(`Dosya silindi ${filePath}`);
|
|
103
|
+
await handleFileDeletion(filePath, tsoft, theme);
|
|
104
|
+
}).on('unlinkDir', async (dirPath) => {
|
|
105
|
+
console.log(`Dizin silindi ${dirPath}`);
|
|
106
|
+
await handleDirectoryDeletion(dirPath, tsoft, theme);
|
|
223
107
|
});
|
|
224
108
|
|
|
225
|
-
console.log(
|
|
109
|
+
console.log(`${themePath} dizinindeki dosya değişiklikleri izleniyor`);
|
|
226
110
|
|
|
227
111
|
const rl = readline.createInterface({
|
|
228
112
|
input: process.stdin,
|
|
@@ -232,41 +116,119 @@ async function startWatching(site, theme, tsoft) {
|
|
|
232
116
|
info();
|
|
233
117
|
|
|
234
118
|
rl.on('line', async (input) => {
|
|
235
|
-
|
|
236
|
-
|
|
119
|
+
await handleUserInput(input, tsoft, theme, watcher, rl);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function handleFileChange(filePath, tsoft, theme) {
|
|
124
|
+
const env = JSON.parse(fs.readFileSync(path.join(process.cwd(), tsoft.site, theme, `${theme}.env`), 'utf-8'));
|
|
125
|
+
const fileName = filePath.replace(`${path.join(process.cwd(), tsoft.site, theme)}/`, '');
|
|
126
|
+
const content = fs.readFileSync(filePath).toString();
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
await tsoft.saveFile(theme, fileName, content, env.bearer);
|
|
130
|
+
console.log(`Dosya başarıyla yüklendi ${fileName}`);
|
|
131
|
+
} catch (error) {
|
|
132
|
+
console.error(`Dosya yükleme hatası ${fileName}:`, error);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async function handleFileDeletion(filePath, tsoft, theme) {
|
|
137
|
+
const env = JSON.parse(fs.readFileSync(path.join(process.cwd(), tsoft.site, theme, `${theme}.env`), 'utf-8'));
|
|
138
|
+
const fileName = filePath.replace(`${path.join(process.cwd(), tsoft.site, theme)}/`, '');
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
await tsoft.deleteFile(theme, fileName, env.bearer);
|
|
142
|
+
console.log(`Dosya başarıyla silindi ${fileName}`);
|
|
143
|
+
} catch (error) {
|
|
144
|
+
console.error(`Dosya silme hatası ${fileName}:`, error);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async function handleDirectoryDeletion(dirPath, tsoft, theme) {
|
|
149
|
+
const env = JSON.parse(fs.readFileSync(path.join(process.cwd(), tsoft.site, theme, `${theme}.env`), 'utf-8'));
|
|
150
|
+
const dirName = dirPath.replace(`${path.join(process.cwd(), tsoft.site, theme)}/`, '');
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
await tsoft.deleteDirectory(theme, dirName, env.bearer);
|
|
154
|
+
console.log(`Dizin başarıyla silindi ${dirName}`);
|
|
155
|
+
} catch (error) {
|
|
156
|
+
console.error(`Dizin silme hatası ${dirName}:`, error);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async function handleUserInput(input, tsoft, theme, watcher, rl) {
|
|
161
|
+
switch (input.trim()) {
|
|
162
|
+
case 'q':
|
|
163
|
+
console.log('Dosya izleme işlemi sonlandırılıyor...');
|
|
237
164
|
watcher.close();
|
|
238
165
|
rl.close();
|
|
239
166
|
process.exit(0);
|
|
240
|
-
|
|
241
|
-
|
|
167
|
+
break;
|
|
168
|
+
case 'u':
|
|
169
|
+
console.log('Tema güncelleniyor...');
|
|
242
170
|
try {
|
|
243
171
|
const result = await updateTheme(tsoft, theme);
|
|
244
172
|
console.log(result);
|
|
245
173
|
info();
|
|
246
174
|
} catch (error) {
|
|
247
|
-
console.error(`
|
|
175
|
+
console.error(`Tema güncelleme hatası:`, error);
|
|
248
176
|
}
|
|
249
|
-
|
|
177
|
+
break;
|
|
178
|
+
case 's':
|
|
250
179
|
clearScreen();
|
|
251
|
-
console.log('
|
|
180
|
+
console.log('Tüm dosyalar ilerleme ile yüklenmeye başlanıyor...');
|
|
252
181
|
try {
|
|
253
182
|
const result = await showProgress(tsoft, theme);
|
|
254
183
|
console.log(result);
|
|
255
184
|
info();
|
|
256
185
|
} catch (error) {
|
|
257
|
-
console.error(
|
|
186
|
+
console.error(`İlerleme gösterim hatası:`, error);
|
|
258
187
|
}
|
|
259
|
-
|
|
260
|
-
|
|
188
|
+
break;
|
|
189
|
+
case 'e':
|
|
190
|
+
console.log('.theme dosyası düzenleniyor...');
|
|
261
191
|
try {
|
|
262
192
|
await editThemeFile(tsoft.themeManager, theme);
|
|
263
193
|
} catch (error) {
|
|
264
|
-
console.error(
|
|
194
|
+
console.error(`.theme dosyası düzenleme hatası:`, error);
|
|
265
195
|
}
|
|
266
|
-
|
|
267
|
-
|
|
196
|
+
break;
|
|
197
|
+
case 'o':
|
|
198
|
+
console.log('Tema dizini açılıyor...');
|
|
199
|
+
const openCommand = process.platform === 'win32' ? 'start' :
|
|
200
|
+
process.platform === 'darwin' ? 'open' :
|
|
201
|
+
'xdg-open';
|
|
202
|
+
exec(`${openCommand} ${path.join(process.cwd(), tsoft.site, theme)}`, (err) => {
|
|
203
|
+
if (err) {
|
|
204
|
+
console.error('Tema dizini açılamadı:', err);
|
|
205
|
+
} else {
|
|
206
|
+
console.log('Tema dizini başarıyla açıldı.');
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async function start(siteName, themeName) {
|
|
214
|
+
await displayAsciiArt();
|
|
215
|
+
console.log('Geliştirme ortamı aşağıdaki ayrıntılarla başlatılıyor:');
|
|
216
|
+
console.log(`Site Adı: ${siteName}`);
|
|
217
|
+
console.log(`Tema Adı: ${themeName}`);
|
|
218
|
+
|
|
219
|
+
const tsoft = new Tsoft(siteName);
|
|
220
|
+
const themeEnvPath = path.join(process.cwd(), siteName, themeName, `${themeName}.env`);
|
|
221
|
+
|
|
222
|
+
const existingEnvValid = await handleExistingEnvironment(tsoft, themeName, themeEnvPath);
|
|
223
|
+
if (existingEnvValid) {
|
|
224
|
+
await startWatching(path.join(process.cwd(), siteName, themeName), tsoft, themeName);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const initializedAndAuthorized = await initializeAndAuthorize(tsoft, themeName);
|
|
229
|
+
if (initializedAndAuthorized) {
|
|
230
|
+
await startWatching(path.join(process.cwd(), siteName, themeName), tsoft, themeName);
|
|
231
|
+
}
|
|
268
232
|
}
|
|
269
233
|
|
|
270
|
-
module.exports = {
|
|
271
|
-
start
|
|
272
|
-
};
|
|
234
|
+
module.exports = { start };
|
package/src/file-manager.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
+
const utils = require('./utils');
|
|
3
4
|
|
|
4
5
|
class FileManager {
|
|
5
6
|
constructor(site) {
|
|
@@ -14,7 +15,7 @@ class FileManager {
|
|
|
14
15
|
if (fs.statSync(fullPath).isDirectory()) {
|
|
15
16
|
this.listFilesRecursive(fullPath, fileList);
|
|
16
17
|
} else {
|
|
17
|
-
fileList.push(fullPath);
|
|
18
|
+
this.isAllowedExtension(fullPath) && fileList.push(fullPath);
|
|
18
19
|
}
|
|
19
20
|
});
|
|
20
21
|
return fileList;
|
|
@@ -28,6 +29,11 @@ class FileManager {
|
|
|
28
29
|
readFile(file) {
|
|
29
30
|
return fs.readFileSync(file).toString();
|
|
30
31
|
}
|
|
32
|
+
|
|
33
|
+
isAllowedExtension(file) {
|
|
34
|
+
const ext = path.extname(file).substring(1);
|
|
35
|
+
return utils.allowedExtensions.includes(ext);
|
|
36
|
+
}
|
|
31
37
|
}
|
|
32
38
|
|
|
33
39
|
module.exports = FileManager;
|
package/src/theme-manager.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
+
const {slugify} = require('./utils');
|
|
4
|
+
const http = require('http');
|
|
5
|
+
const https = require('https');
|
|
3
6
|
|
|
4
7
|
class ThemeManager {
|
|
5
8
|
constructor(site) {
|
|
@@ -10,14 +13,12 @@ class ThemeManager {
|
|
|
10
13
|
}
|
|
11
14
|
|
|
12
15
|
async initializeTheme(theme, reInit = false) {
|
|
13
|
-
|
|
14
16
|
this.theme = theme;
|
|
15
17
|
const themePath = path.join(this.cwd, this.site, theme);
|
|
16
18
|
const themeEnvPath = path.join(themePath, `${theme}.env`);
|
|
17
19
|
|
|
18
|
-
|
|
19
20
|
if (reInit) {
|
|
20
|
-
|
|
21
|
+
// await fs.rm(themePath, {recursive: true, force: true}, (err, file) => {});
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
if (!fs.existsSync(path.join(this.cwd, this.site))) {
|
|
@@ -38,6 +39,19 @@ class ThemeManager {
|
|
|
38
39
|
this.registered = false;
|
|
39
40
|
}
|
|
40
41
|
}
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
const isValid = await this.checkSiteValidity();
|
|
45
|
+
if (!isValid) {
|
|
46
|
+
console.error('Geçersiz site: Siteye ulaşılamıyor.');
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.error('Geçersiz site: Siteye ulaşılamıyor.', error.message);
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return true;
|
|
41
55
|
}
|
|
42
56
|
|
|
43
57
|
isRegistered() {
|
|
@@ -50,25 +64,46 @@ class ThemeManager {
|
|
|
50
64
|
}
|
|
51
65
|
|
|
52
66
|
getEnvironment(theme) {
|
|
53
|
-
const themeEnvPath = path.join(this.cwd, this.site, theme, `${theme}.env`);
|
|
67
|
+
const themeEnvPath = path.join(this.cwd, this.site, slugify(theme), `${slugify(theme)}.env`);
|
|
54
68
|
return JSON.parse(fs.readFileSync(themeEnvPath));
|
|
55
69
|
}
|
|
56
70
|
|
|
57
71
|
getThemeInfo(directoryName) {
|
|
58
|
-
const themePath = path.join(process.cwd(), this.site, directoryName, '.theme');
|
|
72
|
+
const themePath = path.join(process.cwd(), this.site, slugify(directoryName), '.theme');
|
|
59
73
|
if (fs.existsSync(themePath)) {
|
|
60
74
|
const themeInfo = fs.readFileSync(themePath, 'utf-8');
|
|
61
75
|
try {
|
|
62
76
|
return JSON.parse(themeInfo);
|
|
63
77
|
} catch (error) {
|
|
64
|
-
console.error('
|
|
78
|
+
console.error('.theme dosyasını ayrıştırma hatası:', error);
|
|
65
79
|
return null;
|
|
66
80
|
}
|
|
67
81
|
} else {
|
|
68
|
-
console.error('.theme
|
|
82
|
+
console.error('.theme dosyası bulunamadı:', themePath);
|
|
69
83
|
return null;
|
|
70
84
|
}
|
|
71
85
|
}
|
|
86
|
+
|
|
87
|
+
checkSiteValidity() {
|
|
88
|
+
return new Promise((resolve, reject) => {
|
|
89
|
+
const url = new URL(`https://${this.site}/Y/R`);
|
|
90
|
+
const request = url.protocol === 'https:' ? https : http;
|
|
91
|
+
|
|
92
|
+
const req = request.get(url, (res) => {
|
|
93
|
+
if (res.statusCode === 200) {
|
|
94
|
+
resolve(true);
|
|
95
|
+
} else {
|
|
96
|
+
resolve(false);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
req.on('error', (err) => {
|
|
101
|
+
reject(err);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
req.end();
|
|
105
|
+
});
|
|
106
|
+
}
|
|
72
107
|
}
|
|
73
108
|
|
|
74
109
|
module.exports = ThemeManager;
|
package/src/tsoft.js
CHANGED
|
@@ -8,6 +8,7 @@ const buildPostRequest = require('./request');
|
|
|
8
8
|
class Tsoft {
|
|
9
9
|
static TSOFT_CLI_UUID = '7583a318-8542-4ec8-980c-48ea67031be3';
|
|
10
10
|
static ONLINESTORE_SAVE_URI = 'api/v3/admin/online-store-2/theme/file-manager?q=save';
|
|
11
|
+
static ONLINESTORE_DELETE_URI = 'api/v3/admin/online-store-2/theme/file-manager?q=delete';
|
|
11
12
|
static UPDATE_THEME_URI = 'api/v3/admin/online-store-2/theme/update-theme';
|
|
12
13
|
|
|
13
14
|
|
|
@@ -21,7 +22,7 @@ class Tsoft {
|
|
|
21
22
|
async initialize(theme, reInit = false) {
|
|
22
23
|
await this.themeManager.initializeTheme(theme, reInit);
|
|
23
24
|
if (!this.themeManager.isRegistered()) {
|
|
24
|
-
return await this.register(Tsoft.TSOFT_CLI_UUID);
|
|
25
|
+
return await this.register(Tsoft.TSOFT_CLI_UUID, this.themeManager.getThemeInfo(theme));
|
|
25
26
|
} else {
|
|
26
27
|
console.warn('You are already registered');
|
|
27
28
|
}
|
|
@@ -35,8 +36,8 @@ class Tsoft {
|
|
|
35
36
|
await this.clientCredentials.authorize();
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
async register(CLIENT_UUID) {
|
|
39
|
-
const response = await this.clientCredentials.register(CLIENT_UUID);
|
|
39
|
+
async register(CLIENT_UUID, clientConfiguration = {}) {
|
|
40
|
+
const response = await this.clientCredentials.register(CLIENT_UUID, clientConfiguration);
|
|
40
41
|
return response === true ? constants.APPROVAL : null;
|
|
41
42
|
}
|
|
42
43
|
|
|
@@ -58,16 +59,14 @@ class Tsoft {
|
|
|
58
59
|
content: content
|
|
59
60
|
})
|
|
60
61
|
});
|
|
61
|
-
console.log({
|
|
62
|
-
result: result
|
|
63
|
-
})
|
|
64
62
|
}));
|
|
65
63
|
}
|
|
66
64
|
|
|
67
65
|
async saveFile(theme, fileName, content, bearerToken) {
|
|
68
|
-
|
|
66
|
+
return await buildPostRequest(this.site, Tsoft.ONLINESTORE_SAVE_URI, {
|
|
69
67
|
headers: {
|
|
70
68
|
Authorization: `Bearer ${bearerToken}`,
|
|
69
|
+
Accept: 'application/json',
|
|
71
70
|
'Content-Type': 'application/json'
|
|
72
71
|
},
|
|
73
72
|
body: JSON.stringify({
|
|
@@ -76,8 +75,39 @@ class Tsoft {
|
|
|
76
75
|
content: content
|
|
77
76
|
})
|
|
78
77
|
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async deleteFile(theme, fileName, bearerToken) {
|
|
81
|
+
|
|
82
|
+
return await buildPostRequest(this.site, Tsoft.ONLINESTORE_DELETE_URI, {
|
|
83
|
+
headers: {
|
|
84
|
+
Authorization: `Bearer ${bearerToken}`,
|
|
85
|
+
'Content-Type': 'application/json'
|
|
86
|
+
},
|
|
87
|
+
body: JSON.stringify({
|
|
88
|
+
theme: theme,
|
|
89
|
+
items: [
|
|
90
|
+
{type: 'file', path: fileName}
|
|
91
|
+
]
|
|
92
|
+
})
|
|
93
|
+
});
|
|
79
94
|
|
|
80
|
-
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async deleteDirectory(theme, folderName, bearerToken) {
|
|
98
|
+
return await buildPostRequest(this.site, Tsoft.ONLINESTORE_DELETE_URI, {
|
|
99
|
+
headers: {
|
|
100
|
+
Authorization: `Bearer ${bearerToken}`,
|
|
101
|
+
Accept: 'application/json',
|
|
102
|
+
'Content-Type': 'application/json'
|
|
103
|
+
},
|
|
104
|
+
body: JSON.stringify({
|
|
105
|
+
theme: theme,
|
|
106
|
+
items: [
|
|
107
|
+
{type: 'dir', path: folderName}
|
|
108
|
+
]
|
|
109
|
+
})
|
|
110
|
+
});
|
|
81
111
|
}
|
|
82
112
|
|
|
83
113
|
|
|
@@ -90,19 +120,17 @@ class Tsoft {
|
|
|
90
120
|
const env = this.themeManager.getEnvironment(directoryName);
|
|
91
121
|
const themeInfo = this.themeManager.getThemeInfo(directoryName); // .theme bilgisi alınıyor
|
|
92
122
|
|
|
93
|
-
|
|
123
|
+
return await buildPostRequest(this.site, Tsoft.UPDATE_THEME_URI, {
|
|
94
124
|
headers: {
|
|
95
125
|
Authorization: `Bearer ${env.bearer}`,
|
|
96
|
-
'
|
|
97
|
-
'
|
|
126
|
+
'Accept': 'application/json',
|
|
127
|
+
'Content-Type': 'application/json'
|
|
98
128
|
},
|
|
99
129
|
body: JSON.stringify({
|
|
100
130
|
theme: directoryName,
|
|
101
131
|
themeInfo: themeInfo
|
|
102
132
|
})
|
|
103
133
|
});
|
|
104
|
-
|
|
105
|
-
return response;
|
|
106
134
|
}
|
|
107
135
|
|
|
108
136
|
}
|
package/src/utils.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const figlet = require("figlet");
|
|
2
|
+
module.exports = {
|
|
3
|
+
slugify: function (text) {
|
|
4
|
+
return text.toString().toLowerCase()
|
|
5
|
+
.replace(/\s+/g, '-')
|
|
6
|
+
.replace(/[^\w\-]+/g, '')
|
|
7
|
+
.replace(/\-\-+/g, '-')
|
|
8
|
+
.replace(/^-+/, '')
|
|
9
|
+
.replace(/-+$/, '');
|
|
10
|
+
},
|
|
11
|
+
allowedExtensions: ['theme', 'twig', 'css', 'js', 'md', 'json', 'svg', 'jpeg', 'jpg', 'png', 'gif', 'webp'],
|
|
12
|
+
clearScreen: function () {
|
|
13
|
+
process.stdout.write('\x1B[2J\x1B[0f');
|
|
14
|
+
},
|
|
15
|
+
displayAsciiArt: async function () {
|
|
16
|
+
return new Promise((resolve, reject) => {
|
|
17
|
+
figlet('T-SOFT CLI', {
|
|
18
|
+
font: 'Standard',
|
|
19
|
+
}, (err, data) => {
|
|
20
|
+
if (err) {
|
|
21
|
+
console.log('Something went wrong...');
|
|
22
|
+
console.dir(err);
|
|
23
|
+
reject(err);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
console.log(data);
|
|
27
|
+
resolve();
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
},
|
|
31
|
+
info: function () {
|
|
32
|
+
console.log('\n' +
|
|
33
|
+
'********************************************************\n' +
|
|
34
|
+
'* *\n' +
|
|
35
|
+
'* Dosya izlemeyi sonlandırmak için "q" tuşuna basın, *\n' +
|
|
36
|
+
'* Temayı güncellemek için "u" tuşuna basın, *\n' +
|
|
37
|
+
'* Temayı kaydetmek için "s" tuşuna basın, *\n' +
|
|
38
|
+
'* .theme dosyasını düzenlemek için "e" tuşuna basın, *\n' +
|
|
39
|
+
'* Tema dizinini açmak için "o" tuşuna basın. *\n' +
|
|
40
|
+
'* *\n' +
|
|
41
|
+
'********************************************************\n'
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const mockFs = require('mock-fs');
|
|
3
|
+
const FileManager = require('../src/file-manager');
|
|
4
|
+
|
|
5
|
+
describe('FileManager', () => {
|
|
6
|
+
const site = 'testSite';
|
|
7
|
+
const fileManager = new FileManager(site);
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
mockFs({
|
|
11
|
+
'/testDir': {
|
|
12
|
+
'file1.js': 'console.log("file1");',
|
|
13
|
+
'file2.css': 'body { margin: 0; }',
|
|
14
|
+
'subdir': {
|
|
15
|
+
'file3.jpg': '',
|
|
16
|
+
'file4.png': ''
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
[`${process.cwd()}/${site}`]: {
|
|
20
|
+
'myTheme': {
|
|
21
|
+
'file.js': 'console.log("test");'
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
mockFs.restore();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('listFilesRecursive', () => {
|
|
32
|
+
it('should list all files recursively', () => {
|
|
33
|
+
// Act
|
|
34
|
+
const result = fileManager.listFilesRecursive('/testDir');
|
|
35
|
+
|
|
36
|
+
// Assert
|
|
37
|
+
expect(result).toEqual([
|
|
38
|
+
'/testDir/file1.js',
|
|
39
|
+
'/testDir/file2.css',
|
|
40
|
+
'/testDir/subdir/file3.jpg',
|
|
41
|
+
'/testDir/subdir/file4.png'
|
|
42
|
+
]);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe('getRelativePath', () => {
|
|
47
|
+
it('should get the relative path of a file', () => {
|
|
48
|
+
// Arrange
|
|
49
|
+
const theme = 'myTheme';
|
|
50
|
+
const file = path.join(process.cwd(), site, theme, 'file.js');
|
|
51
|
+
const expectedRelativePath = 'file.js';
|
|
52
|
+
|
|
53
|
+
// Act
|
|
54
|
+
const result = fileManager.getRelativePath(theme, file);
|
|
55
|
+
|
|
56
|
+
// Assert
|
|
57
|
+
expect(result).toBe(expectedRelativePath);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe('readFile', () => {
|
|
62
|
+
it('should read the contents of a file', () => {
|
|
63
|
+
// Arrange
|
|
64
|
+
const file = '/testDir/file1.js';
|
|
65
|
+
const fileContents = 'console.log("file1");';
|
|
66
|
+
|
|
67
|
+
// Act
|
|
68
|
+
const result = fileManager.readFile(file);
|
|
69
|
+
|
|
70
|
+
// Assert
|
|
71
|
+
expect(result).toBe(fileContents);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe('isAllowedExtension', () => {
|
|
76
|
+
it('should return true for allowed extensions', () => {
|
|
77
|
+
// Arrange
|
|
78
|
+
const allowedFile = 'file.js';
|
|
79
|
+
const notAllowedFile = 'file.exe';
|
|
80
|
+
|
|
81
|
+
// Act
|
|
82
|
+
const isAllowedFileResult = fileManager.isAllowedExtension(allowedFile);
|
|
83
|
+
const isNotAllowedFileResult = fileManager.isAllowedExtension(notAllowedFile);
|
|
84
|
+
|
|
85
|
+
// Assert
|
|
86
|
+
expect(isAllowedFileResult).toBe(true);
|
|
87
|
+
expect(isNotAllowedFileResult).toBe(false);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
});
|
package/src/commands/save.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
const Tsoft = require('../tsoft');
|
|
2
|
-
|
|
3
|
-
async function save(site, theme) {
|
|
4
|
-
const t = new Tsoft(site);
|
|
5
|
-
const isValid = await t.isTokenValid(theme);
|
|
6
|
-
|
|
7
|
-
if (isValid) {
|
|
8
|
-
await t.saveOnlineStore(theme);
|
|
9
|
-
console.log('Online store saved successfully.');
|
|
10
|
-
} else {
|
|
11
|
-
console.log('Invalid Bearer token. Please re-authenticate.');
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
module.exports = {
|
|
16
|
-
save
|
|
17
|
-
};
|