tsoft-cli 1.0.2 → 1.2.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/CHANGELOG.md +15 -0
- package/README.md +10 -0
- package/bin/index.js +75 -0
- package/jest.config.js +3 -0
- package/package.json +13 -9
- package/src/client-credentials.js +88 -0
- package/src/commands/create.js +93 -0
- package/src/commands/start.js +211 -0
- package/src/constants.js +16 -0
- package/src/file-manager.js +39 -0
- package/src/request.js +16 -0
- package/src/theme-manager.js +109 -0
- package/src/tsoft.js +138 -0
- package/src/utils.js +45 -0
- package/tests/FileManager.test.js +90 -0
- package/bin/tsoft-cli.js +0 -107
- package/src/common.js +0 -117
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# T-Soft CLI
|
|
2
|
+
|
|
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.
|
|
5
|
+
|
|
6
|
+
## Kurulum
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g tsoft-cli
|
|
9
|
+
```
|
|
10
|
+
|
package/bin/index.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
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');
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
async function selectSiteAndTheme() {
|
|
11
|
+
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());
|
|
15
|
+
|
|
16
|
+
if (sites.length === 0) {
|
|
17
|
+
console.error('Mevcut dizinde site bulunamadı.');
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
|
|
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
|
+
});
|
|
32
|
+
|
|
33
|
+
if (themes.length === 0) {
|
|
34
|
+
console.error('Seçilen site dizininde tema bulunamadı.');
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
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();
|
|
45
|
+
|
|
46
|
+
return { siteName: selectedSite, themeName: selectedTheme };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function showMainMenu() {
|
|
50
|
+
clearScreen();
|
|
51
|
+
|
|
52
|
+
await displayAsciiArt();
|
|
53
|
+
|
|
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);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
showMainMenu();
|
package/jest.config.js
ADDED
package/package.json
CHANGED
|
@@ -1,24 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tsoft-cli",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "",
|
|
3
|
+
"version": "1.2.0",
|
|
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": "",
|
|
11
11
|
"license": "ISC",
|
|
12
12
|
"bin": {
|
|
13
|
-
"tsoft-cli": "./bin/
|
|
13
|
+
"tsoft-cli": "./bin/index.js"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"axios": "^1.7.2",
|
|
17
16
|
"chokidar": "^3.6.0",
|
|
17
|
+
"cli-progress": "^3.12.0",
|
|
18
18
|
"commander": "^12.1.0",
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
19
|
+
"enquirer": "^2.4.1",
|
|
20
|
+
"figlet": "^1.7.0",
|
|
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
|
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
const buildPostRequest = require('./request');
|
|
2
|
+
|
|
3
|
+
class ClientCredentials {
|
|
4
|
+
site;
|
|
5
|
+
clientId;
|
|
6
|
+
clientSecret;
|
|
7
|
+
bearer;
|
|
8
|
+
|
|
9
|
+
constructor(site) {
|
|
10
|
+
this.site = site;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
getEnvironment() {
|
|
14
|
+
return {
|
|
15
|
+
site: this.site, clientId: this.clientId, clientSecret: this.clientSecret, bearer: this.bearer
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
set clientId(clientId) {
|
|
20
|
+
this.clientId = clientId;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
get clientId() {
|
|
24
|
+
return this.clientId;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
setClientSecret(clientSecret) {
|
|
28
|
+
this.clientSecret = clientSecret;
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async register(CLIENT_UUID, clientConfiguration = {}) {
|
|
33
|
+
|
|
34
|
+
const uri = "api/v3/admin/auth/auth-application";
|
|
35
|
+
const result = await this.buildPostRequest(uri, {
|
|
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
|
+
}
|
|
44
|
+
})
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
if (result.status === true) {
|
|
48
|
+
this.clientId = result.data.public_key;
|
|
49
|
+
} else {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async authorize() {
|
|
57
|
+
const uri = "api/v3/admin/auth/auth-application/authorize";
|
|
58
|
+
await this.buildPostRequest(uri, {
|
|
59
|
+
body: JSON.stringify({
|
|
60
|
+
public_key: this.clientId, secret: this.clientSecret
|
|
61
|
+
})
|
|
62
|
+
}).then((result) => {
|
|
63
|
+
if (result.status === true) {
|
|
64
|
+
this.bearer = result.data.token.plainTextToken
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
async buildPostRequest(uri, options = {}) {
|
|
72
|
+
return buildPostRequest(this.site, uri, options);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async validateToken(token) {
|
|
76
|
+
const uri = 'api/v3/admin/auth/me';
|
|
77
|
+
const response = await buildPostRequest(this.site, uri, {
|
|
78
|
+
body: JSON.stringify({
|
|
79
|
+
_method: 'GET'
|
|
80
|
+
}), headers: {
|
|
81
|
+
Authorization: `Bearer ${token}`
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
return response.message === 'ok';
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
module.exports = ClientCredentials;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { Select, Input } = require('enquirer');
|
|
4
|
+
const {slugify} = require('../utils');
|
|
5
|
+
const { start } = require('./start');
|
|
6
|
+
const ThemeManager = require('../theme-manager');
|
|
7
|
+
|
|
8
|
+
async function createTheme() {
|
|
9
|
+
const cwd = process.cwd();
|
|
10
|
+
const sites = 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
|
+
const siteChoices = [...sites, 'Yeni bir site oluştur'];
|
|
15
|
+
|
|
16
|
+
const sitePrompt = new Select({
|
|
17
|
+
name: 'site',
|
|
18
|
+
message: 'Çalışmak istediğiniz sitenin adı:',
|
|
19
|
+
choices: siteChoices
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const selectedSite = await sitePrompt.run();
|
|
23
|
+
|
|
24
|
+
let siteName;
|
|
25
|
+
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
|
+
|
|
44
|
+
} else {
|
|
45
|
+
siteName = selectedSite;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const themeNamePrompt = new Input({
|
|
49
|
+
name: 'themeName',
|
|
50
|
+
message: 'Tema adı:'
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const authorPrompt = new Input({
|
|
54
|
+
name: 'author',
|
|
55
|
+
message: 'Author (isteğe bağlı):'
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const versionPrompt = new Input({
|
|
59
|
+
name: 'version',
|
|
60
|
+
message: 'Version (isteğe bağlı, varsayılan 1.0.0):',
|
|
61
|
+
initial: '1.0.0'
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const themeName = await themeNamePrompt.run();
|
|
65
|
+
const author = await authorPrompt.run();
|
|
66
|
+
const version = await versionPrompt.run();
|
|
67
|
+
|
|
68
|
+
const themeNameSlug = slugify(themeName);
|
|
69
|
+
|
|
70
|
+
const themePath = path.join(cwd, siteName, themeNameSlug);
|
|
71
|
+
|
|
72
|
+
if (!fs.existsSync(themePath)) {
|
|
73
|
+
fs.mkdirSync(themePath, { recursive: true });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const themeData = {
|
|
77
|
+
site: siteName,
|
|
78
|
+
theme: themeName,
|
|
79
|
+
author: author,
|
|
80
|
+
version: version
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
fs.writeFileSync(path.join(themePath, '.theme'), JSON.stringify(themeData, null, 2));
|
|
84
|
+
|
|
85
|
+
console.log(`Tema "${themeName}" başarıyla oluşturuldu.`);
|
|
86
|
+
|
|
87
|
+
// Doğrudan start fonksiyonuna geçiş yap
|
|
88
|
+
await start(siteName, themeNameSlug);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
module.exports = {
|
|
92
|
+
createTheme
|
|
93
|
+
};
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const chokidar = require('chokidar');
|
|
4
|
+
const readline = require('readline');
|
|
5
|
+
const { exec } = require('child_process');
|
|
6
|
+
const Tsoft = require('../tsoft');
|
|
7
|
+
const constants = require('../constants');
|
|
8
|
+
const cliProgress = require('cli-progress');
|
|
9
|
+
const { Input } = require('enquirer');
|
|
10
|
+
const { displayAsciiArt, clearScreen, info, slugify } = require('../utils');
|
|
11
|
+
|
|
12
|
+
async function showProgress(tsoft, theme) {
|
|
13
|
+
const themePath = path.join(process.cwd(), tsoft.site, theme);
|
|
14
|
+
const fileList = tsoft.fileManager.listFilesRecursive(themePath).filter(file => !file.includes('.env'));
|
|
15
|
+
const totalFiles = fileList.length;
|
|
16
|
+
|
|
17
|
+
// Yeni bir ilerleme çubuğu oluşturun ve shades_classic temasını kullanın
|
|
18
|
+
const progressBar = new cliProgress.SingleBar({
|
|
19
|
+
format: 'İlerleme |{bar}| {percentage}% || {value}/{total} Dosya Yüklendi',
|
|
20
|
+
barCompleteChar: '\u2588',
|
|
21
|
+
barIncompleteChar: '\u2591',
|
|
22
|
+
hideCursor: true,
|
|
23
|
+
clearOnComplete: true
|
|
24
|
+
});
|
|
25
|
+
progressBar.start(totalFiles, 0);
|
|
26
|
+
|
|
27
|
+
for (let i = 0; i < totalFiles; i++) {
|
|
28
|
+
const file = fileList[i];
|
|
29
|
+
const fileName = tsoft.fileManager.getRelativePath(theme, file);
|
|
30
|
+
const content = tsoft.fileManager.readFile(file);
|
|
31
|
+
const env = tsoft.themeManager.getEnvironment(theme);
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
await tsoft.saveFile(theme, fileName, content, env.bearer);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.error(`Dosya yükleme hatası ${fileName}:`, error);
|
|
37
|
+
}
|
|
38
|
+
progressBar.update(i + 1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
progressBar.stop();
|
|
42
|
+
|
|
43
|
+
return 'Tüm dosyalar ilerleme ile başarıyla yüklendi';
|
|
44
|
+
}
|
|
45
|
+
|
|
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}`);
|
|
51
|
+
|
|
52
|
+
const tsoft = new Tsoft(siteName);
|
|
53
|
+
const themeEnvPath = path.join(process.cwd(), siteName, themeName, `${themeName}.env`);
|
|
54
|
+
|
|
55
|
+
// .env dosyasının var olup olmadığını ve geçerli bir JSON içerip içermediğini kontrol edin
|
|
56
|
+
let envData = {};
|
|
57
|
+
if (fs.existsSync(themeEnvPath)) {
|
|
58
|
+
try {
|
|
59
|
+
envData = JSON.parse(fs.readFileSync(themeEnvPath, 'utf-8'));
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.warn(`${themeEnvPath} dosyasında geçersiz JSON formatı. Bu dosya silinecek ve yeniden yetkilendirmeniz gerekecek.`);
|
|
62
|
+
fs.unlinkSync(themeEnvPath);
|
|
63
|
+
console.info('Geçersiz ortam dosyası silindi. Başlatma işlemine devam ediliyor...');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (envData.bearer) {
|
|
67
|
+
const bearerTokenValid = await tsoft.isTokenValid(themeName);
|
|
68
|
+
|
|
69
|
+
if (bearerTokenValid) {
|
|
70
|
+
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;
|
|
74
|
+
} else {
|
|
75
|
+
console.warn('Mevcut taşıyıcı jetonu geçersiz. Yeniden yetkilendirmeniz gerekecek.');
|
|
76
|
+
fs.unlinkSync(themeEnvPath);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
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
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
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
|
+
|
|
110
|
+
const watcher = chokidar.watch(themePath, {
|
|
111
|
+
ignored: /(^|[\/\\])(\.theme|(.*?)\.env)$/, // .theme ve .env dosyaları yoksayılır
|
|
112
|
+
persistent: true
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
watcher.on('change', async (filePath) => {
|
|
116
|
+
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
|
+
}
|
|
128
|
+
}).on('unlink', async (filePath) => {
|
|
129
|
+
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
|
+
}
|
|
140
|
+
}).on('unlinkDir', async (dirPath) => {
|
|
141
|
+
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
|
+
}
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
console.log(`${themePath} dizinindeki dosya değişiklikleri izleniyor`);
|
|
155
|
+
|
|
156
|
+
const rl = readline.createInterface({
|
|
157
|
+
input: process.stdin,
|
|
158
|
+
output: process.stdout
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
info();
|
|
162
|
+
|
|
163
|
+
rl.on('line', async (input) => {
|
|
164
|
+
if (input.trim() === 'q') {
|
|
165
|
+
console.log('Dosya izleme işlemi sonlandırılıyor...');
|
|
166
|
+
watcher.close();
|
|
167
|
+
rl.close();
|
|
168
|
+
process.exit(0);
|
|
169
|
+
} else if (input.trim() === 'u') {
|
|
170
|
+
console.log('Tema güncelleniyor...');
|
|
171
|
+
try {
|
|
172
|
+
const result = await updateTheme(tsoft, theme);
|
|
173
|
+
console.log(result);
|
|
174
|
+
info();
|
|
175
|
+
} catch (error) {
|
|
176
|
+
console.error(`Tema güncelleme hatası:`, error);
|
|
177
|
+
}
|
|
178
|
+
} else if (input.trim() === 's') {
|
|
179
|
+
clearScreen();
|
|
180
|
+
console.log('Tüm dosyalar ilerleme ile yüklenmeye başlanıyor...');
|
|
181
|
+
try {
|
|
182
|
+
const result = await showProgress(tsoft, theme);
|
|
183
|
+
console.log(result);
|
|
184
|
+
info();
|
|
185
|
+
} catch (error) {
|
|
186
|
+
console.error(`İlerleme gösterim hatası:`, error);
|
|
187
|
+
}
|
|
188
|
+
} else if (input.trim() === 'e') {
|
|
189
|
+
console.log('.theme dosyası düzenleniyor...');
|
|
190
|
+
try {
|
|
191
|
+
await editThemeFile(tsoft.themeManager, theme);
|
|
192
|
+
} catch (error) {
|
|
193
|
+
console.error(`.theme dosyası düzenleme hatası:`, error);
|
|
194
|
+
}
|
|
195
|
+
} else if (input.trim() === 'o') {
|
|
196
|
+
console.log('Tema dizini açılıyor...');
|
|
197
|
+
const openCommand = process.platform === 'win32' ? 'start' :
|
|
198
|
+
process.platform === 'darwin' ? 'open' :
|
|
199
|
+
'xdg-open';
|
|
200
|
+
exec(`${openCommand} ${themePath}`, (err) => {
|
|
201
|
+
if (err) {
|
|
202
|
+
console.error('Tema dizini açılamadı:', err);
|
|
203
|
+
} else {
|
|
204
|
+
console.log('Tema dizini başarıyla açıldı.');
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
module.exports = { start };
|
package/src/constants.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const handleAuthorization = async (credentialHandler) => {
|
|
2
|
+
await credentialHandler.authorize();
|
|
3
|
+
};
|
|
4
|
+
module.exports = Object.freeze({
|
|
5
|
+
INITIALIZE: {
|
|
6
|
+
type: 'input',
|
|
7
|
+
name: 'site',
|
|
8
|
+
message: 'Lütfen site adresini giriniz (örnek: https://tsoft.com.tr):'
|
|
9
|
+
},
|
|
10
|
+
APPROVAL: {
|
|
11
|
+
type: 'input',
|
|
12
|
+
name: 'approval',
|
|
13
|
+
message: 'Parolanızı giriniz (Lütfen panelden onaylayınız):',
|
|
14
|
+
handler: handleAuthorization
|
|
15
|
+
}
|
|
16
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const utils = require('./utils');
|
|
4
|
+
|
|
5
|
+
class FileManager {
|
|
6
|
+
constructor(site) {
|
|
7
|
+
this.site = site;
|
|
8
|
+
this.cwd = process.cwd();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
listFilesRecursive(directory, fileList = []) {
|
|
12
|
+
const files = fs.readdirSync(directory);
|
|
13
|
+
files.forEach(file => {
|
|
14
|
+
const fullPath = path.join(directory, file);
|
|
15
|
+
if (fs.statSync(fullPath).isDirectory()) {
|
|
16
|
+
this.listFilesRecursive(fullPath, fileList);
|
|
17
|
+
} else {
|
|
18
|
+
this.isAllowedExtension(fullPath) && fileList.push(fullPath);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
return fileList;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
getRelativePath(theme, file) {
|
|
25
|
+
const themePath = path.join(this.cwd, this.site, theme);
|
|
26
|
+
return file.replace(`${themePath}/`, '');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
readFile(file) {
|
|
30
|
+
return fs.readFileSync(file).toString();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
isAllowedExtension(file) {
|
|
34
|
+
const ext = path.extname(file).substring(1);
|
|
35
|
+
return utils.allowedExtensions.includes(ext);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = FileManager;
|
package/src/request.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module.exports = (site, uri, options = {}) => {
|
|
2
|
+
return fetch("https://" + site + '/' + uri, {
|
|
3
|
+
method: 'POST',
|
|
4
|
+
headers: {
|
|
5
|
+
'Content-Type': 'application/json',
|
|
6
|
+
'Accept': 'application/json',
|
|
7
|
+
...options.headers ?? {}
|
|
8
|
+
},
|
|
9
|
+
body: options.body
|
|
10
|
+
})
|
|
11
|
+
.then((response) => response.json())
|
|
12
|
+
.then((result) => {
|
|
13
|
+
return result
|
|
14
|
+
})
|
|
15
|
+
.catch((error) => console.error(error));
|
|
16
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const {slugify} = require('./utils');
|
|
4
|
+
const http = require('http');
|
|
5
|
+
const https = require('https');
|
|
6
|
+
|
|
7
|
+
class ThemeManager {
|
|
8
|
+
constructor(site) {
|
|
9
|
+
this.site = site;
|
|
10
|
+
this.cwd = process.cwd();
|
|
11
|
+
this.theme = null;
|
|
12
|
+
this.registered = false;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async initializeTheme(theme, reInit = false) {
|
|
16
|
+
this.theme = theme;
|
|
17
|
+
const themePath = path.join(this.cwd, this.site, theme);
|
|
18
|
+
const themeEnvPath = path.join(themePath, `${theme}.env`);
|
|
19
|
+
|
|
20
|
+
if (reInit) {
|
|
21
|
+
// await fs.rm(themePath, {recursive: true, force: true}, (err, file) => {});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (!fs.existsSync(path.join(this.cwd, this.site))) {
|
|
25
|
+
fs.mkdirSync(path.join(this.cwd, this.site));
|
|
26
|
+
}
|
|
27
|
+
if (!fs.existsSync(themePath)) {
|
|
28
|
+
fs.mkdirSync(themePath);
|
|
29
|
+
}
|
|
30
|
+
if (reInit || !fs.existsSync(themeEnvPath)) {
|
|
31
|
+
fs.writeFileSync(themeEnvPath, '');
|
|
32
|
+
this.registered = false;
|
|
33
|
+
} else {
|
|
34
|
+
const data = fs.readFileSync(themeEnvPath);
|
|
35
|
+
try {
|
|
36
|
+
const environment = JSON.parse(data.toString());
|
|
37
|
+
this.registered = Boolean(environment.bearer);
|
|
38
|
+
} catch (e) {
|
|
39
|
+
this.registered = false;
|
|
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;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
isRegistered() {
|
|
58
|
+
return this.registered;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
buildEnvironment(environment) {
|
|
62
|
+
const envPath = path.join(this.cwd, this.site, this.theme, `${this.theme}.env`);
|
|
63
|
+
fs.writeFileSync(envPath, JSON.stringify(environment));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
getEnvironment(theme) {
|
|
67
|
+
const themeEnvPath = path.join(this.cwd, this.site, slugify(theme), `${slugify(theme)}.env`);
|
|
68
|
+
return JSON.parse(fs.readFileSync(themeEnvPath));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
getThemeInfo(directoryName) {
|
|
72
|
+
const themePath = path.join(process.cwd(), this.site, slugify(directoryName), '.theme');
|
|
73
|
+
if (fs.existsSync(themePath)) {
|
|
74
|
+
const themeInfo = fs.readFileSync(themePath, 'utf-8');
|
|
75
|
+
try {
|
|
76
|
+
return JSON.parse(themeInfo);
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.error('.theme dosyasını ayrıştırma hatası:', error);
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
} else {
|
|
82
|
+
console.error('.theme dosyası bulunamadı:', themePath);
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
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
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
module.exports = ThemeManager;
|
package/src/tsoft.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
const ClientCredentials = require('./client-credentials');
|
|
2
|
+
const constants = require('./constants');
|
|
3
|
+
const FileManager = require('./file-manager');
|
|
4
|
+
const ThemeManager = require('./theme-manager');
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const buildPostRequest = require('./request');
|
|
7
|
+
|
|
8
|
+
class Tsoft {
|
|
9
|
+
static TSOFT_CLI_UUID = '7583a318-8542-4ec8-980c-48ea67031be3';
|
|
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';
|
|
12
|
+
static UPDATE_THEME_URI = 'api/v3/admin/online-store-2/theme/update-theme';
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
constructor(site) {
|
|
16
|
+
this.site = site;
|
|
17
|
+
this.themeManager = new ThemeManager(site);
|
|
18
|
+
this.fileManager = new FileManager(site);
|
|
19
|
+
this.clientCredentials = new ClientCredentials(site);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async initialize(theme, reInit = false) {
|
|
23
|
+
await this.themeManager.initializeTheme(theme, reInit);
|
|
24
|
+
if (!this.themeManager.isRegistered()) {
|
|
25
|
+
return await this.register(Tsoft.TSOFT_CLI_UUID, this.themeManager.getThemeInfo(theme));
|
|
26
|
+
} else {
|
|
27
|
+
console.warn('You are already registered');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
buildEnvironment() {
|
|
32
|
+
this.themeManager.buildEnvironment(this.clientCredentials.getEnvironment());
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async authorize() {
|
|
36
|
+
await this.clientCredentials.authorize();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async register(CLIENT_UUID, clientConfiguration = {}) {
|
|
40
|
+
const response = await this.clientCredentials.register(CLIENT_UUID, clientConfiguration);
|
|
41
|
+
return response === true ? constants.APPROVAL : null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async saveOnlineStore(theme) {
|
|
45
|
+
const fileList = this.fileManager.listFilesRecursive(
|
|
46
|
+
path.join(process.cwd(), this.site, theme)
|
|
47
|
+
);
|
|
48
|
+
await Promise.all(fileList.filter(file => !file.includes('.env')).map(async file => {
|
|
49
|
+
const fileName = this.fileManager.getRelativePath(theme, file);
|
|
50
|
+
const content = this.fileManager.readFile(file);
|
|
51
|
+
const env = this.themeManager.getEnvironment(theme);
|
|
52
|
+
const result = await buildPostRequest(this.site, Tsoft.ONLINESTORE_SAVE_URI, {
|
|
53
|
+
headers: {
|
|
54
|
+
Authorization: `Bearer ${env.bearer}`
|
|
55
|
+
},
|
|
56
|
+
body: JSON.stringify({
|
|
57
|
+
theme: theme,
|
|
58
|
+
path: fileName,
|
|
59
|
+
content: content
|
|
60
|
+
})
|
|
61
|
+
});
|
|
62
|
+
}));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async saveFile(theme, fileName, content, bearerToken) {
|
|
66
|
+
return await buildPostRequest(this.site, Tsoft.ONLINESTORE_SAVE_URI, {
|
|
67
|
+
headers: {
|
|
68
|
+
Authorization: `Bearer ${bearerToken}`,
|
|
69
|
+
Accept: 'application/json',
|
|
70
|
+
'Content-Type': 'application/json'
|
|
71
|
+
},
|
|
72
|
+
body: JSON.stringify({
|
|
73
|
+
theme: theme,
|
|
74
|
+
path: fileName,
|
|
75
|
+
content: content
|
|
76
|
+
})
|
|
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
|
+
});
|
|
94
|
+
|
|
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
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
async isTokenValid(theme) {
|
|
115
|
+
const env = this.themeManager.getEnvironment(theme);
|
|
116
|
+
return await this.clientCredentials.validateToken(env.bearer);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async updateTheme(directoryName) {
|
|
120
|
+
const env = this.themeManager.getEnvironment(directoryName);
|
|
121
|
+
const themeInfo = this.themeManager.getThemeInfo(directoryName); // .theme bilgisi alınıyor
|
|
122
|
+
|
|
123
|
+
return await buildPostRequest(this.site, Tsoft.UPDATE_THEME_URI, {
|
|
124
|
+
headers: {
|
|
125
|
+
Authorization: `Bearer ${env.bearer}`,
|
|
126
|
+
'Accept': 'application/json',
|
|
127
|
+
'Content-Type': 'application/json'
|
|
128
|
+
},
|
|
129
|
+
body: JSON.stringify({
|
|
130
|
+
theme: directoryName,
|
|
131
|
+
themeInfo: themeInfo
|
|
132
|
+
})
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
module.exports = Tsoft;
|
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/bin/tsoft-cli.js
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
const Common = require('../src/common');
|
|
3
|
-
const { program } = require('commander');
|
|
4
|
-
const axios = require('axios');
|
|
5
|
-
const chokidar = require('chokidar');
|
|
6
|
-
const path = require('path');
|
|
7
|
-
const fs = require('fs');
|
|
8
|
-
const _ = require('lodash');
|
|
9
|
-
|
|
10
|
-
program
|
|
11
|
-
.command('init')
|
|
12
|
-
.description('Initialize the CLI')
|
|
13
|
-
.action(() => {
|
|
14
|
-
init();
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
program.parse(process.argv);
|
|
18
|
-
|
|
19
|
-
function init() {
|
|
20
|
-
(async () => {
|
|
21
|
-
const {default: inquirer} = await import('inquirer');
|
|
22
|
-
|
|
23
|
-
const tsoft = new Common();
|
|
24
|
-
|
|
25
|
-
if (Common.skip !== true) {
|
|
26
|
-
await tsoft.handleStep1(
|
|
27
|
-
(await inquirer.prompt(
|
|
28
|
-
[
|
|
29
|
-
{
|
|
30
|
-
type: 'input',
|
|
31
|
-
name: 'step1',
|
|
32
|
-
message: 'Site Adresi https://(tsoft.com.tr):'
|
|
33
|
-
},
|
|
34
|
-
]
|
|
35
|
-
))
|
|
36
|
-
)
|
|
37
|
-
|
|
38
|
-
await tsoft.handleStep2(
|
|
39
|
-
(await inquirer.prompt(
|
|
40
|
-
[
|
|
41
|
-
{
|
|
42
|
-
type: 'input',
|
|
43
|
-
name: 'step2',
|
|
44
|
-
message: 'Parola (Panelden Onaylayın):'
|
|
45
|
-
},
|
|
46
|
-
]
|
|
47
|
-
))
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
await tsoft.handleStep3(
|
|
51
|
-
(await inquirer.prompt(
|
|
52
|
-
[
|
|
53
|
-
{
|
|
54
|
-
type: 'input',
|
|
55
|
-
name: 'step3',
|
|
56
|
-
message: 'Tema Adı:'
|
|
57
|
-
},
|
|
58
|
-
]
|
|
59
|
-
))
|
|
60
|
-
)
|
|
61
|
-
} else {
|
|
62
|
-
|
|
63
|
-
const debouncedSendFileChange = _.debounce(async (data) => {
|
|
64
|
-
try {
|
|
65
|
-
const response = await axios.post('https://'+this.site+'/api', { data });
|
|
66
|
-
console.log('API response:', response.data);
|
|
67
|
-
} catch (error) {
|
|
68
|
-
console.error('Error sending API request:', error);
|
|
69
|
-
}
|
|
70
|
-
}, 1000);
|
|
71
|
-
|
|
72
|
-
const watchDirectory = path.join(__dirname, 'themes'); // İzlemek istediğiniz dizinin yolunu belirtin
|
|
73
|
-
const watcher = chokidar.watch(watchDirectory, {
|
|
74
|
-
persistent: true,
|
|
75
|
-
ignored: /(^|[\/\\])\../,
|
|
76
|
-
ignoreInitial: true,
|
|
77
|
-
followSymlinks: true,
|
|
78
|
-
depth: 99,
|
|
79
|
-
awaitWriteFinish: {
|
|
80
|
-
stabilityThreshold: 2000,
|
|
81
|
-
pollInterval: 100
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
watcher.on('all', (event, filePath) => {
|
|
86
|
-
if (event === 'change' || event === 'add' || event === 'unlink') {
|
|
87
|
-
console.log(`File ${filePath} has been ${event}`);
|
|
88
|
-
|
|
89
|
-
// Dosya değişikliğinde dosya içeriğini oku ve debounce edilmiş API'ye gönder
|
|
90
|
-
fs.readFile(filePath, 'utf8', (err, data) => {
|
|
91
|
-
if (err) {
|
|
92
|
-
console.error('Error reading file:', err);
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
debouncedSendFileChange(data);
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
})();
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
package/src/common.js
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
const path = require("path");
|
|
2
|
-
const fs = require("fs");
|
|
3
|
-
|
|
4
|
-
class Common {
|
|
5
|
-
static CLIENT_UUID = "7583a318-8542-4ec8-980c-48ea67031be3";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
site = null;
|
|
9
|
-
public_key = null;
|
|
10
|
-
secret = null;
|
|
11
|
-
|
|
12
|
-
theme = null;
|
|
13
|
-
|
|
14
|
-
bearer = null;
|
|
15
|
-
|
|
16
|
-
static skip = false;
|
|
17
|
-
|
|
18
|
-
constructor() {
|
|
19
|
-
try {
|
|
20
|
-
const environment = JSON.parse(fs.readFileSync(path.join(__dirname, '.environment'), 'utf8'))
|
|
21
|
-
|
|
22
|
-
this.site = environment.site;
|
|
23
|
-
this.public_key = environment.public_key;
|
|
24
|
-
this.secret = environment.secret;
|
|
25
|
-
this.theme = environment.theme;
|
|
26
|
-
this.bearer = environment.bearer;
|
|
27
|
-
|
|
28
|
-
Common.skip = true;
|
|
29
|
-
} catch (error) {
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
handleEnv(envObject) {
|
|
35
|
-
const filePath = path.join(__dirname, '.environment');
|
|
36
|
-
|
|
37
|
-
fs.writeFile(filePath, envObject, (err) => {
|
|
38
|
-
if (err) {
|
|
39
|
-
console.error('Error writing file:', err);
|
|
40
|
-
} else {
|
|
41
|
-
console.log('File written successfully');
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async handleStep1(message) {
|
|
47
|
-
this.site = message.step1;
|
|
48
|
-
await this.authorizationRequest();
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async handleStep2(message) {
|
|
52
|
-
this.secret = message.step2;
|
|
53
|
-
await this.login();
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
async handleStep3(message) {
|
|
57
|
-
this.theme = message.step3;
|
|
58
|
-
|
|
59
|
-
this.handleEnv(JSON.stringify({
|
|
60
|
-
site: this.site,
|
|
61
|
-
public_key: this.public_key,
|
|
62
|
-
secret: this.secret,
|
|
63
|
-
theme: this.theme,
|
|
64
|
-
bearer: this.bearer
|
|
65
|
-
}));
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
async authorizationRequest() {
|
|
70
|
-
const myHeaders = new Headers();
|
|
71
|
-
myHeaders.append("Content-Type", "application/json");
|
|
72
|
-
myHeaders.append("Accept", "application/json");
|
|
73
|
-
|
|
74
|
-
const raw = JSON.stringify({
|
|
75
|
-
"uuid": Common.CLIENT_UUID,
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
const requestOptions = {
|
|
79
|
-
method: "POST",
|
|
80
|
-
headers: myHeaders,
|
|
81
|
-
body: raw,
|
|
82
|
-
redirect: "follow"
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
fetch("https://" + this.site + "/api/v3/admin/auth/auth-application", requestOptions)
|
|
86
|
-
.then((response) => response.json())
|
|
87
|
-
.then((result) => {
|
|
88
|
-
this.public_key = result.public_key
|
|
89
|
-
})
|
|
90
|
-
.catch((error) => console.error(error));
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
async login() {
|
|
94
|
-
const myHeaders = new Headers();
|
|
95
|
-
const formdata = new FormData();
|
|
96
|
-
formdata.append("public_key", this.public_key);
|
|
97
|
-
formdata.append("secret", this.secret);
|
|
98
|
-
|
|
99
|
-
const requestOptions = {
|
|
100
|
-
method: "POST",
|
|
101
|
-
headers: myHeaders,
|
|
102
|
-
body: formdata,
|
|
103
|
-
redirect: "follow"
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
fetch("https://" + this.site + "/api/v3/admin/auth/auth-application/authorize", requestOptions)
|
|
107
|
-
.then((response) => response.json())
|
|
108
|
-
.then((result) => {
|
|
109
|
-
this.bearer = result?.token?.plainTextToken;
|
|
110
|
-
})
|
|
111
|
-
.catch((error) => console.error(error));
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
module.exports = Common;
|