tsoft-cli 1.2.0 → 1.2.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/CHANGELOG.md CHANGED
@@ -13,3 +13,35 @@
13
13
 
14
14
  ### Fixed
15
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ü.
31
+
32
+ # Changelog
33
+
34
+ ## [1.2.2] - 2024-06-14
35
+ ### Added
36
+ - Kurtarma anahtarı ile tema senkronizasyonu yapan `syncTheme` fonksiyonu eklendi.
37
+ - `syncTheme` fonksiyonu zip dosyasını indirip açma işlemi gerçekleştiriyor.
38
+ - Tema bilgilerini içeren `.theme` dosyası oluşturma ve `theme.env` dosyası yaratma işlemleri eklendi.
39
+ - Kullanıcı komut satırı etkileşimleri için `enquirer` kütüphanesi kullanıldı.
40
+
41
+ ### Changed
42
+ - `unzipFile` fonksiyonu eklendi, zip dosyalarını açmak için kullanılıyor.
43
+ - `sync.js` dosyasında kullanıcıdan kurtarma anahtarı alınarak gerekli işlemlerin yapılması sağlandı.
44
+
45
+ ### Fixed
46
+ - Zip dosyasının indirildikten sonra otomatik olarak silinmesi sağlandı.
47
+ - `sync.js` dosyasında oluşan hatalar giderildi ve kod kalitesi iyileştirildi.
package/README.md CHANGED
@@ -1,10 +1,106 @@
1
- # T-Soft CLI
1
+ T-Soft CLI Kullanım Kılavuzu
2
+ ============================
2
3
 
3
- ## Özet
4
- T-Soft CLI, T-Soft tarafından geliştirilen bir komut satırı aracıdır. Bu araç ile T-Soft ön yüz geliştirme süreçlerinde kullanılan bazı işlemler otomatize edilmiştir. Bu sayede geliştirme süreçleri hızlandırılmış ve daha verimli hale getirilmiştir.
4
+ Açıklama
5
+ --------
5
6
 
6
- ## Kurulum
7
- ```bash
8
- npm install -g tsoft-cli
9
- ```
7
+ 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.
10
8
 
9
+ Kurulum
10
+ -------
11
+
12
+ CLI aracını kullanmaya başlamadan önce, aşağıdaki adımları izleyerek T-Soft CLI'yı kurmanız gerekmektedir:
13
+
14
+ ### NPM ile Kurulum
15
+
16
+ T-Soft CLI'yı global olarak kurmak için aşağıdaki komutu çalıştırın:
17
+
18
+ npm install -g tsoft-cli
19
+
20
+ Kullanım
21
+ --------
22
+
23
+ CLI arayüzünü çalıştırmak için terminale `tsoft-cli` yazmanız yeterlidir:
24
+
25
+ tsoft-cli
26
+
27
+ ### Ana Menü
28
+
29
+ CLI başlatıldığında aşağıdaki seçeneklerle ana menü görünür:
30
+
31
+ * Yeni bir tema oluştur
32
+ * Geliştirme ortamını başlat
33
+ * Çıkış
34
+
35
+ ### Yeni Bir Tema Oluşturma
36
+
37
+ Yeni bir tema oluşturmak için aşağıdaki adımları izleyin:
38
+
39
+ 1. **Yeni Tema Oluşturma Seçeneğini Seçin**: Ana menüden `Yeni bir tema oluştur` seçeneğini seçin.
40
+ 2. **Site Adı Seçimi**:
41
+ * Mevcut sitelerden birini seçin veya `Yeni bir site oluştur` seçeneğini seçin.
42
+ * Yeni bir site oluşturmak istiyorsanız, site adını girin. Bu ad, geçerliliği kontrol edilecektir.
43
+ 3. **Tema Detayları**:
44
+ * Tema adı, yazar adı (isteğe bağlı) ve versiyon numarasını girin.
45
+ 4. **Tema Oluşturma**: Tema başarıyla oluşturulduktan sonra otomatik olarak geliştirme ortamına geçilir.
46
+
47
+ ### Geliştirme Ortamını Başlatma
48
+
49
+ Mevcut bir temayı düzenlemek veya geliştirmek için geliştirme ortamını başlatabilirsiniz:
50
+
51
+ 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.
52
+ 2. **Site ve Tema Seçimi**:
53
+ * Mevcut sitelerden birini seçin.
54
+ * Seçilen sitedeki temalardan birini seçin.
55
+ 3. **Geliştirme Ortamı**: Seçilen tema için geliştirme ortamı başlatılır ve dosya değişiklikleri izlenir.
56
+
57
+ ### Geliştirme Ortamında Kullanılabilir Komutlar
58
+
59
+ Geliştirme ortamında aşağıdaki komutları kullanabilirsiniz:
60
+
61
+ * `q`: Dosya izlemeyi sonlandırır.
62
+ * `u`: Temayı günceller.
63
+ * `s`: Tüm dosyaları kaydeder.
64
+ * `e`: `.theme` dosyasını düzenler.
65
+ * `o`: Tema dizinini açar.
66
+
67
+ Proje Yapısı
68
+ ------------
69
+
70
+ Projenizin dosya yapısı şu şekildedir:
71
+
72
+
73
+ tsoft-cli/
74
+ ├── bin/
75
+ │ └── index.js
76
+ ├── src/
77
+ │ ├── commands/
78
+ │ │ ├── create.js
79
+ │ │ └── start.js
80
+ │ ├── tsoft/
81
+ │ │ └── themeManager.js
82
+ │ ├── utils.js
83
+ │ └── constants.js
84
+ ├── CHANGELOG.md
85
+ ├── package.json
86
+ └── README.md
87
+
88
+
89
+ ### Dosya ve Klasör Açıklamaları
90
+
91
+ * `bin/index.js`: Ana CLI giriş noktasıdır. Kullanıcı komutları burada işlenir ve ilgili komut dosyaları çalıştırılır.
92
+ * `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.
93
+ * `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.
94
+ * `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.
95
+ * `src/utils.js`: Yardımcı fonksiyonlar içerir.
96
+ * `src/constants.js`: Sabit değerleri içerir.
97
+
98
+ Katkıda Bulunma
99
+ ---------------
100
+
101
+ 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.
102
+
103
+ Lisans
104
+ ------
105
+
106
+ Bu proje ISC lisansı altında lisanslanmıştır. Daha fazla bilgi için `LICENSE` dosyasına bakabilirsiniz.
package/bin/index.js CHANGED
@@ -1,74 +1,74 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { Select, Input } = require('enquirer');
4
- const { start } = require('../src/commands/start');
5
- const { createTheme } = require('../src/commands/create');
6
- const { clearScreen, displayAsciiArt } = require('../src/utils');
3
+ const {Select} = require('enquirer');
4
+ const {start} = require('../src/commands/start');
5
+ const {syncTheme} = require('../src/commands/sync'); // Yeni komut dosyasını ekle
6
+ const {createTheme} = require('../src/commands/create');
7
+ const {clearScreen, displayAsciiArt} = require('../src/utils');
7
8
  const fs = require('fs');
8
9
  const path = require('path');
9
10
 
11
+ async function getDirectories(source) {
12
+ return fs.readdirSync(source).filter(file => {
13
+ return file.charAt(0) !== '.' && !['node_modules', 'build', 'dist'].includes(file);
14
+ }).filter(file => fs.statSync(path.join(source, file)).isDirectory());
15
+ }
16
+
17
+ async function selectFromChoices(message, choices) {
18
+ const prompt = new Select({
19
+ name: 'selection',
20
+ message: message,
21
+ choices: choices
22
+ });
23
+
24
+ return await prompt.run();
25
+ }
26
+
10
27
  async function selectSiteAndTheme() {
11
28
  const cwd = process.cwd();
12
- const sites = fs.readdirSync(cwd).filter(file => {
13
- return file.charAt(0) !== '.' && !['node_modules', 'build', 'dist'].includes(file);
14
- }).filter(file => fs.statSync(path.join(cwd, file)).isDirectory());
29
+ const sites = await getDirectories(cwd);
15
30
 
16
31
  if (sites.length === 0) {
17
32
  console.error('Mevcut dizinde site bulunamadı.');
18
33
  return null;
19
34
  }
20
35
 
21
- const sitePrompt = new Select({
22
- name: 'site',
23
- message: 'Bir site seçin:',
24
- choices: sites
25
- });
26
-
27
- const selectedSite = await sitePrompt.run();
28
-
29
- const themes = fs.readdirSync(path.join(cwd, selectedSite)).filter(file => {
30
- return fs.statSync(path.join(cwd, selectedSite, file)).isDirectory();
31
- });
36
+ const selectedSite = await selectFromChoices('Bir site seçin:', sites);
37
+ const themes = await getDirectories(path.join(cwd, selectedSite));
32
38
 
33
39
  if (themes.length === 0) {
34
40
  console.error('Seçilen site dizininde tema bulunamadı.');
35
41
  return null;
36
42
  }
37
43
 
38
- const themePrompt = new Select({
39
- name: 'theme',
40
- message: 'Bir tema seçin:',
41
- choices: themes
42
- });
43
-
44
- const selectedTheme = await themePrompt.run();
44
+ const selectedTheme = await selectFromChoices('Bir tema seçin:', themes);
45
45
 
46
- return { siteName: selectedSite, themeName: selectedTheme };
46
+ return {siteName: selectedSite, themeName: selectedTheme};
47
47
  }
48
48
 
49
49
  async function showMainMenu() {
50
50
  clearScreen();
51
-
52
51
  await displayAsciiArt();
53
52
 
54
- const prompt = new Select({
55
- name: 'command',
56
- message: 'Bir komut seçin',
57
- choices: ['Yeni bir tema oluştur', 'Geliştirme ortamını başlat', 'Çıkış']
58
- });
59
-
60
- const answer = await prompt.run();
61
-
62
- if (answer === 'Yeni bir tema oluştur') {
63
- await createTheme();
64
- } else if (answer === 'Geliştirme ortamını başlat') {
65
- const selection = await selectSiteAndTheme();
66
- if (selection) {
67
- await start(selection.siteName, selection.themeName);
68
- }
69
- } else {
70
- console.log('Programdan çıkılıyor. Hoşça kalın!');
71
- process.exit(0);
53
+ const commandChoices = ['Yeni bir tema oluştur', 'Geliştirme ortamını başlat', 'Uzak sunucudan dosyaları indir', 'Çıkış'];
54
+ const selectedCommand = await selectFromChoices('Bir komut seçin', commandChoices);
55
+
56
+ switch (selectedCommand) {
57
+ case 'Yeni bir tema oluştur':
58
+ await createTheme();
59
+ break;
60
+ case 'Geliştirme ortamını başlat':
61
+ const selection = await selectSiteAndTheme();
62
+ if (selection) {
63
+ await start(selection.siteName, selection.themeName);
64
+ }
65
+ break;
66
+ case 'Uzak sunucudan dosyaları indir':
67
+ await syncTheme();
68
+ break;
69
+ case 'Çıkış':
70
+ console.log('Programdan çıkılıyor. Hoşça kalın!');
71
+ process.exit(0);
72
72
  }
73
73
  }
74
74
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsoft-cli",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
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": {
@@ -18,7 +18,8 @@
18
18
  "commander": "^12.1.0",
19
19
  "enquirer": "^2.4.1",
20
20
  "figlet": "^1.7.0",
21
- "fs": "^0.0.1-security"
21
+ "fs": "^0.0.1-security",
22
+ "unzipper": "^0.12.1"
22
23
  },
23
24
  "type": "commonjs",
24
25
  "devDependencies": {
@@ -1,4 +1,4 @@
1
- const buildPostRequest = require('./request');
1
+ const {buildPostRequest} = require('./request');
2
2
 
3
3
  class ClientCredentials {
4
4
  site;
@@ -29,6 +29,11 @@ class ClientCredentials {
29
29
  return this;
30
30
  }
31
31
 
32
+ setClientId(clientId) {
33
+ this.clientId = clientId;
34
+ return this;
35
+ }
36
+
32
37
  async register(CLIENT_UUID, clientConfiguration = {}) {
33
38
 
34
39
  const uri = "api/v3/admin/auth/auth-application";
@@ -37,7 +42,7 @@ class ClientCredentials {
37
42
  'Content-Type': 'application/json', 'Accept': 'application/json',
38
43
  }, body: JSON.stringify({
39
44
  uuid: CLIENT_UUID, configuration: {
40
- theme: clientConfiguration.theme,
45
+ name: clientConfiguration.name,
41
46
  author: clientConfiguration.author,
42
47
  version: clientConfiguration.version
43
48
  }
@@ -55,14 +60,19 @@ class ClientCredentials {
55
60
 
56
61
  async authorize() {
57
62
  const uri = "api/v3/admin/auth/auth-application/authorize";
58
- await this.buildPostRequest(uri, {
63
+ return await this.buildPostRequest(uri, {
59
64
  body: JSON.stringify({
60
65
  public_key: this.clientId, secret: this.clientSecret
61
66
  })
62
67
  }).then((result) => {
63
68
  if (result.status === true) {
64
69
  this.bearer = result.data.token.plainTextToken
70
+ return result;
65
71
  }
72
+ return false;
73
+ }).catch((error) => {
74
+ console.error('Hata:', error.message);
75
+ return false;
66
76
  });
67
77
 
68
78
  }
@@ -83,6 +93,20 @@ class ClientCredentials {
83
93
  });
84
94
  return response.message === 'ok';
85
95
  }
96
+
97
+ async recovery(token) {
98
+ const uri = 'api/v3/admin/auth/auth-application/recovery/' + token;
99
+
100
+ const response = await buildPostRequest(this.site, uri);
101
+
102
+ if (response.status) {
103
+ return {
104
+ secret: response.data.secret,
105
+ public_key: response.data.public_key
106
+ }
107
+ }
108
+
109
+ }
86
110
  }
87
111
 
88
112
  module.exports = ClientCredentials;
@@ -1,16 +1,18 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
- const { Select, Input } = require('enquirer');
3
+ const {Select, Input} = require('enquirer');
4
4
  const {slugify} = require('../utils');
5
- const { start } = require('./start');
5
+ const {start} = require('./start');
6
6
  const ThemeManager = require('../theme-manager');
7
7
 
8
- async function createTheme() {
8
+ async function getSites() {
9
9
  const cwd = process.cwd();
10
- const sites = fs.readdirSync(cwd).filter(file => {
10
+ return fs.readdirSync(cwd).filter(file => {
11
11
  return file.charAt(0) !== '.' && !['node_modules', 'build', 'dist'].includes(file);
12
12
  }).filter(file => fs.statSync(path.join(cwd, file)).isDirectory());
13
+ }
13
14
 
15
+ async function selectSite(sites) {
14
16
  const siteChoices = [...sites, 'Yeni bir site oluştur'];
15
17
 
16
18
  const sitePrompt = new Select({
@@ -21,30 +23,42 @@ async function createTheme() {
21
23
 
22
24
  const selectedSite = await sitePrompt.run();
23
25
 
24
- let siteName;
25
26
  if (selectedSite === 'Yeni bir site oluştur') {
26
- const newSitePrompt = new Input({
27
- name: 'newSite',
28
- message: 'Yeni site adı:'
29
- });
30
- siteName = await newSitePrompt.run();
31
-
32
- const themeManager = new ThemeManager(siteName);
33
- try {
34
- const isValid = await themeManager.checkSiteValidity(siteName);
35
- if (!isValid) {
36
- console.error('Geçersiz site adı. Lütfen geçerli bir site adı girin.');
37
- return;
38
- }
39
- } catch (error) {
40
- console.error('Site doğrulaması sırasında hata oluştu:', error.message);
41
- return;
42
- }
43
-
27
+ return await createNewSite();
44
28
  } else {
45
- siteName = selectedSite;
29
+ return selectedSite;
30
+ }
31
+ }
32
+
33
+ async function createNewSite() {
34
+ const newSitePrompt = new Input({
35
+ name: 'newSite',
36
+ message: 'Yeni site adı:'
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;
46
58
  }
59
+ }
47
60
 
61
+ async function getThemeDetails() {
48
62
  const themeNamePrompt = new Input({
49
63
  name: 'themeName',
50
64
  message: 'Tema adı:'
@@ -65,29 +79,48 @@ async function createTheme() {
65
79
  const author = await authorPrompt.run();
66
80
  const version = await versionPrompt.run();
67
81
 
68
- const themeNameSlug = slugify(themeName);
82
+ return {themeName, author, version};
83
+ }
69
84
 
85
+ async function createThemeDirectory(siteName, themeNameSlug) {
86
+ const cwd = process.cwd();
70
87
  const themePath = path.join(cwd, siteName, themeNameSlug);
71
88
 
72
89
  if (!fs.existsSync(themePath)) {
73
- fs.mkdirSync(themePath, { recursive: true });
90
+ fs.mkdirSync(themePath, {recursive: true});
74
91
  }
75
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
+
76
110
  const themeData = {
77
111
  site: siteName,
78
- theme: themeName,
112
+ name: themeName,
79
113
  author: author,
80
114
  version: version
81
115
  };
82
116
 
83
- fs.writeFileSync(path.join(themePath, '.theme'), JSON.stringify(themeData, null, 2));
117
+ await saveThemeData(themePath, themeData);
84
118
 
85
119
  console.log(`Tema "${themeName}" başarıyla oluşturuldu.`);
86
120
 
87
- // Doğrudan start fonksiyonuna geçiş yap
88
121
  await start(siteName, themeNameSlug);
89
122
  }
90
123
 
91
124
  module.exports = {
92
- createTheme
125
+ createTheme, createThemeDirectory, selectSite
93
126
  };
@@ -7,14 +7,13 @@ const Tsoft = require('../tsoft');
7
7
  const constants = require('../constants');
8
8
  const cliProgress = require('cli-progress');
9
9
  const { Input } = require('enquirer');
10
- const { displayAsciiArt, clearScreen, info, slugify } = require('../utils');
10
+ const { displayAsciiArt, clearScreen, info } = require('../utils');
11
11
 
12
12
  async function showProgress(tsoft, theme) {
13
13
  const themePath = path.join(process.cwd(), tsoft.site, theme);
14
14
  const fileList = tsoft.fileManager.listFilesRecursive(themePath).filter(file => !file.includes('.env'));
15
15
  const totalFiles = fileList.length;
16
16
 
17
- // Yeni bir ilerleme çubuğu oluşturun ve shades_classic temasını kullanın
18
17
  const progressBar = new cliProgress.SingleBar({
19
18
  format: 'İlerleme |{bar}| {percentage}% || {value}/{total} Dosya Yüklendi',
20
19
  barCompleteChar: '\u2588',
@@ -43,16 +42,28 @@ async function showProgress(tsoft, theme) {
43
42
  return 'Tüm dosyalar ilerleme ile başarıyla yüklendi';
44
43
  }
45
44
 
46
- async function start(siteName, themeName) {
47
- await displayAsciiArt();
48
- console.log('Geliştirme ortamı aşağıdaki ayrıntılarla başlatılıyor:');
49
- console.log(`Site Adı: ${siteName}`);
50
- console.log(`Tema Adı: ${themeName}`);
45
+ async function initializeAndAuthorize(tsoft, themeName) {
46
+ await tsoft.initialize(themeName);
51
47
 
52
- const tsoft = new Tsoft(siteName);
53
- const themeEnvPath = path.join(process.cwd(), siteName, themeName, `${themeName}.env`);
48
+ const approvalPrompt = new Input({
49
+ name: 'approval',
50
+ message: 'Lütfen onay kodunu sağlayın:'
51
+ });
52
+
53
+ const approval = await approvalPrompt.run();
54
54
 
55
- // .env dosyasının var olup olmadığını ve geçerli bir JSON içerip içermediğini kontrol edin
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;
63
+ }
64
+ }
65
+
66
+ async function handleExistingEnvironment(tsoft, themeName, themeEnvPath) {
56
67
  let envData = {};
57
68
  if (fs.existsSync(themeEnvPath)) {
58
69
  try {
@@ -68,45 +79,17 @@ async function start(siteName, themeName) {
68
79
 
69
80
  if (bearerTokenValid) {
70
81
  console.info('Geçerli bir taşıyıcı jetonuna sahip mevcut ortam dosyası bulundu. Mevcut yapılandırma ile devam ediliyor...');
71
- // Dosya değişikliklerini izlemeye başlayın
72
- await startWatching(siteName, themeName, tsoft);
73
- return;
82
+ return true;
74
83
  } else {
75
84
  console.warn('Mevcut taşıyıcı jetonu geçersiz. Yeniden yetkilendirmeniz gerekecek.');
76
85
  fs.unlinkSync(themeEnvPath);
77
86
  }
78
87
  }
79
88
  }
80
-
81
- await tsoft.initialize(themeName);
82
-
83
- const approvalPrompt = new Input({
84
- name: 'approval',
85
- message: 'Lütfen onay kodunu sağlayın:'
86
- });
87
-
88
- const approval = await approvalPrompt.run();
89
-
90
- if (approval) {
91
- await constants.APPROVAL.handler(tsoft.clientCredentials.setClientSecret(approval));
92
- tsoft.buildEnvironment();
93
- console.info('Hazırsınız');
94
- // Dosya değişikliklerini izlemeye başlayın
95
- await startWatching(siteName, themeName, tsoft);
96
- } else {
97
- console.error('Onay kodu gerekli.');
98
- }
89
+ return false;
99
90
  }
100
91
 
101
- async function startWatching(site, theme, tsoft) {
102
- const themePath = path.join(process.cwd(), site, theme);
103
- const envPath = path.join(themePath, `${theme}.env`);
104
-
105
- if (!fs.existsSync(envPath)) {
106
- console.error('Ortam dosyası bulunamadı. Lütfen temayı önce başlatın.');
107
- return;
108
- }
109
-
92
+ async function startWatching(themePath, tsoft, theme) {
110
93
  const watcher = chokidar.watch(themePath, {
111
94
  ignored: /(^|[\/\\])(\.theme|(.*?)\.env)$/, // .theme ve .env dosyaları yoksayılır
112
95
  persistent: true
@@ -114,41 +97,13 @@ async function startWatching(site, theme, tsoft) {
114
97
 
115
98
  watcher.on('change', async (filePath) => {
116
99
  console.log(`Dosya değiştirildi ${filePath}`);
117
-
118
- const env = JSON.parse(fs.readFileSync(envPath, 'utf-8'));
119
- const fileName = filePath.replace(`${themePath}/`, '');
120
- const content = fs.readFileSync(filePath).toString();
121
-
122
- try {
123
- await tsoft.saveFile(theme, fileName, content, env.bearer);
124
- console.log(`Dosya başarıyla yüklendi ${fileName}`);
125
- } catch (error) {
126
- console.error(`Dosya yükleme hatası ${fileName}:`, error);
127
- }
100
+ await handleFileChange(filePath, tsoft, theme);
128
101
  }).on('unlink', async (filePath) => {
129
102
  console.log(`Dosya silindi ${filePath}`);
130
-
131
- const env = JSON.parse(fs.readFileSync(envPath, 'utf-8'));
132
- const fileName = filePath.replace(`${themePath}/`, '');
133
-
134
- try {
135
- await tsoft.deleteFile(theme, fileName, env.bearer);
136
- console.log(`Dosya başarıyla silindi ${fileName}`);
137
- } catch (error) {
138
- console.error(`Dosya silme hatası ${fileName}:`, error);
139
- }
103
+ await handleFileDeletion(filePath, tsoft, theme);
140
104
  }).on('unlinkDir', async (dirPath) => {
141
105
  console.log(`Dizin silindi ${dirPath}`);
142
-
143
- const env = JSON.parse(fs.readFileSync(envPath, 'utf-8'));
144
- const dirName = dirPath.replace(`${themePath}/`, '');
145
-
146
- try {
147
- await tsoft.deleteDirectory(theme, dirName, env.bearer);
148
- console.log(`Dizin başarıyla silindi ${dirName}`);
149
- } catch (error) {
150
- console.error(`Dizin silme hatası ${dirName}:`, error);
151
- }
106
+ await handleDirectoryDeletion(dirPath, tsoft, theme);
152
107
  });
153
108
 
154
109
  console.log(`${themePath} dizinindeki dosya değişiklikleri izleniyor`);
@@ -161,12 +116,56 @@ async function startWatching(site, theme, tsoft) {
161
116
  info();
162
117
 
163
118
  rl.on('line', async (input) => {
164
- if (input.trim() === 'q') {
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':
165
163
  console.log('Dosya izleme işlemi sonlandırılıyor...');
166
164
  watcher.close();
167
165
  rl.close();
168
166
  process.exit(0);
169
- } else if (input.trim() === 'u') {
167
+ break;
168
+ case 'u':
170
169
  console.log('Tema güncelleniyor...');
171
170
  try {
172
171
  const result = await updateTheme(tsoft, theme);
@@ -175,7 +174,8 @@ async function startWatching(site, theme, tsoft) {
175
174
  } catch (error) {
176
175
  console.error(`Tema güncelleme hatası:`, error);
177
176
  }
178
- } else if (input.trim() === 's') {
177
+ break;
178
+ case 's':
179
179
  clearScreen();
180
180
  console.log('Tüm dosyalar ilerleme ile yüklenmeye başlanıyor...');
181
181
  try {
@@ -185,25 +185,79 @@ async function startWatching(site, theme, tsoft) {
185
185
  } catch (error) {
186
186
  console.error(`İlerleme gösterim hatası:`, error);
187
187
  }
188
- } else if (input.trim() === 'e') {
188
+ break;
189
+ case 'e':
189
190
  console.log('.theme dosyası düzenleniyor...');
190
191
  try {
191
192
  await editThemeFile(tsoft.themeManager, theme);
192
193
  } catch (error) {
193
194
  console.error(`.theme dosyası düzenleme hatası:`, error);
194
195
  }
195
- } else if (input.trim() === 'o') {
196
+ break;
197
+ case 'o':
196
198
  console.log('Tema dizini açılıyor...');
197
199
  const openCommand = process.platform === 'win32' ? 'start' :
198
200
  process.platform === 'darwin' ? 'open' :
199
201
  'xdg-open';
200
- exec(`${openCommand} ${themePath}`, (err) => {
202
+ exec(`${openCommand} ${path.join(process.cwd(), tsoft.site, theme)}`, (err) => {
201
203
  if (err) {
202
204
  console.error('Tema dizini açılamadı:', err);
203
205
  } else {
204
206
  console.log('Tema dizini başarıyla açıldı.');
205
207
  }
206
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
+ }
232
+ }
233
+
234
+ async function updateTheme(tsoft, theme) {
235
+ const directoryName = path.basename(path.join(process.cwd(), tsoft.site, theme));
236
+ const response = await tsoft.updateTheme(directoryName);
237
+ if (response.status === true) {
238
+ return 'Successfully updated';
239
+ } else {
240
+ throw new Error('Update failed');
241
+ }
242
+ }
243
+ async function editThemeFile(themeManager, directoryName) {
244
+ const themePath = path.join(process.cwd(), themeManager.site, directoryName, '.theme');
245
+
246
+ if (!fs.existsSync(themePath)) {
247
+ console.error('.theme file not found.');
248
+ return;
249
+ }
250
+
251
+ console.log(`Opening .theme file: ${themePath}`);
252
+ const openCommand = process.platform === 'win32' ? 'start' :
253
+ process.platform === 'darwin' ? 'open' :
254
+ 'xdg-open';
255
+
256
+ exec(`${openCommand} ${themePath}`, (err) => {
257
+ if (err) {
258
+ console.error('Failed to open .theme file:', err);
259
+ } else {
260
+ console.log('.theme file opened successfully.');
207
261
  }
208
262
  });
209
263
  }
@@ -0,0 +1,80 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const {Input} = require('enquirer');
4
+ const {clearScreen} = require('../utils');
5
+ const {selectSite, createThemeDirectory} = require('./create');
6
+ const Tsoft = require("../tsoft");
7
+ const {slugify} = require('../utils');
8
+ const unzipper = require('unzipper');
9
+
10
+ function unzipFile(zipFilePath, extractToDir) {
11
+ return new Promise((resolve, reject) => {
12
+ fs.createReadStream(zipFilePath)
13
+ .pipe(unzipper.Extract({path: extractToDir}))
14
+ .on('close', resolve)
15
+ .on('error', reject);
16
+ });
17
+ }
18
+
19
+ async function syncTheme() {
20
+ const cwd = process.cwd();
21
+ const sites = fs.readdirSync(cwd).filter(file => {
22
+ return file.charAt(0) !== '.' && !['node_modules', 'build', 'dist'].includes(file);
23
+ }).filter(file => fs.statSync(path.join(cwd, file)).isDirectory());
24
+
25
+ const selectedSite = await selectSite(sites);
26
+
27
+ const tsoft = new Tsoft(selectedSite);
28
+
29
+ const codePrompt = new Input({
30
+ name: 'code',
31
+ message: 'Lütfen kurtarma anahtarını girin:'
32
+ });
33
+
34
+ const recoveryCode = await codePrompt.run();
35
+
36
+
37
+ const {secret, public_key} = await tsoft.startRecovery(recoveryCode);
38
+
39
+ tsoft.clientCredentials.setClientSecret(secret).setClientId(public_key)
40
+ const authorizeResponse = await tsoft.clientCredentials.authorize(true)
41
+ const themeInformation = authorizeResponse.data.tokenable;
42
+
43
+ const themeName = themeInformation.name;
44
+ const themeNameSlug = slugify(themeName);
45
+ const themePath = await createThemeDirectory(selectedSite, themeNameSlug);
46
+
47
+ const themeData = {
48
+ site: selectedSite,
49
+ name: themeName,
50
+ author: themeInformation.author,
51
+ version: themeInformation.version
52
+ };
53
+
54
+ fs.writeFileSync(path.join(themePath, '.theme'), JSON.stringify(themeData, null, 2));
55
+ tsoft.themeManager.setTheme(themeNameSlug)
56
+
57
+
58
+ if (!fs.existsSync(themePath)) {
59
+ fs.mkdirSync(themePath, {recursive: true});
60
+ }
61
+
62
+ clearScreen();
63
+
64
+ const zipFilePath = path.join(themePath, 'theme.zip');
65
+
66
+ console.log('Zip dosyası indiriliyor...');
67
+ await tsoft.fileManager.downloadAndSaveZip(themePath, zipFilePath, tsoft.clientCredentials.bearer);
68
+ console.log('İndirme tamamlandı.');
69
+
70
+ console.log('Dosyalar çıkarılıyor...');
71
+ await unzipFile(zipFilePath, themePath);
72
+ console.log('Çıkarma işlemi tamamlandı.');
73
+ fs.unlinkSync(zipFilePath);
74
+
75
+ tsoft.buildEnvironment();
76
+ }
77
+
78
+ module.exports = {
79
+ syncTheme
80
+ };
@@ -1,6 +1,8 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
  const utils = require('./utils');
4
+ const { exec } = require('child_process');
5
+ const {buildDownloadZipRequest} = require('./request');
4
6
 
5
7
  class FileManager {
6
8
  constructor(site) {
@@ -34,6 +36,35 @@ class FileManager {
34
36
  const ext = path.extname(file).substring(1);
35
37
  return utils.allowedExtensions.includes(ext);
36
38
  }
39
+
40
+ async downloadAndSaveZip(saveToDir, zipFilePath, bearerToken) {
41
+ // Fetch the zip file and save it
42
+ const response = await buildDownloadZipRequest(this.site, `api/v3/admin/online-store-2/theme/download-theme`, {
43
+ headers: {
44
+ 'Content-Type': 'application/zip',
45
+ 'Accept': 'application/zip',
46
+ 'Authorization': `Bearer ${bearerToken}`
47
+ }
48
+ });
49
+
50
+
51
+ fs.writeFileSync(zipFilePath, Buffer.from(response));
52
+
53
+ console.log(`Zip dosyası ${zipFilePath} konumuna kaydedildi.`);
54
+
55
+ // Open the directory in file explorer
56
+ const openCommand = process.platform === 'win32' ? 'start' :
57
+ process.platform === 'darwin' ? 'open' :
58
+ 'xdg-open';
59
+ exec(`${openCommand} ${saveToDir}`, (err) => {
60
+ if (err) {
61
+ console.error('Dizin açılamadı:', err);
62
+ } else {
63
+ console.log(`Dizin açıldı: ${saveToDir}`);
64
+ console.log('Lütfen zip dosyasını bu dizine çıkartın.');
65
+ }
66
+ });
67
+ }
37
68
  }
38
69
 
39
70
  module.exports = FileManager;
package/src/request.js CHANGED
@@ -1,4 +1,4 @@
1
- module.exports = (site, uri, options = {}) => {
1
+ buildPostRequest = (site, uri, options = {}) => {
2
2
  return fetch("https://" + site + '/' + uri, {
3
3
  method: 'POST',
4
4
  headers: {
@@ -14,3 +14,24 @@ module.exports = (site, uri, options = {}) => {
14
14
  })
15
15
  .catch((error) => console.error(error));
16
16
  }
17
+ buildDownloadZipRequest = (site, uri, options = {}) => {
18
+ return fetch("https://" + site + '/' + uri, {
19
+ method: 'POST',
20
+ headers: {
21
+ 'Content-Type': 'application/zip',
22
+ 'Accept': 'application/zip',
23
+ ...options.headers ?? {}
24
+ },
25
+ body: options.body
26
+ })
27
+ .then((response) => response.arrayBuffer())
28
+ .then((result) => {
29
+ return result
30
+ })
31
+ .catch((error) => console.error(error));
32
+ }
33
+
34
+ module.exports = {
35
+ buildPostRequest,
36
+ buildDownloadZipRequest
37
+ }
@@ -54,6 +54,9 @@ class ThemeManager {
54
54
  return true;
55
55
  }
56
56
 
57
+ setTheme(theme) {
58
+ this.theme = slugify(theme)
59
+ }
57
60
  isRegistered() {
58
61
  return this.registered;
59
62
  }
package/src/tsoft.js CHANGED
@@ -3,7 +3,7 @@ const constants = require('./constants');
3
3
  const FileManager = require('./file-manager');
4
4
  const ThemeManager = require('./theme-manager');
5
5
  const path = require("path");
6
- const buildPostRequest = require('./request');
6
+ const {buildPostRequest} = require('./request');
7
7
 
8
8
  class Tsoft {
9
9
  static TSOFT_CLI_UUID = '7583a318-8542-4ec8-980c-48ea67031be3';
@@ -49,7 +49,7 @@ class Tsoft {
49
49
  const fileName = this.fileManager.getRelativePath(theme, file);
50
50
  const content = this.fileManager.readFile(file);
51
51
  const env = this.themeManager.getEnvironment(theme);
52
- const result = await buildPostRequest(this.site, Tsoft.ONLINESTORE_SAVE_URI, {
52
+ await buildPostRequest(this.site, Tsoft.ONLINESTORE_SAVE_URI, {
53
53
  headers: {
54
54
  Authorization: `Bearer ${env.bearer}`
55
55
  },
@@ -133,6 +133,10 @@ class Tsoft {
133
133
  });
134
134
  }
135
135
 
136
+ async startRecovery(token) {
137
+ return await this.clientCredentials.recovery(token);
138
+ }
139
+
136
140
  }
137
141
 
138
142
  module.exports = Tsoft;