tsoft-cli 1.4.3 → 2.0.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/.editorconfig +11 -0
- package/.github/workflows/node.js.yml +25 -0
- package/.nvmrc +1 -0
- package/.prettierrc.json +8 -0
- package/.vscode/extensions.json +3 -0
- package/.vscode/settings.json +4 -0
- package/CHANGELOG.md +29 -4
- package/package.json +14 -25
- package/packages/cli/README.md +53 -0
- package/packages/cli/bin/dev.js +5 -0
- package/packages/cli/bin/run.cmd +3 -0
- package/packages/cli/bin/run.js +5 -0
- package/packages/cli/enums.ts +4 -0
- package/packages/cli/index.ts +11 -0
- package/packages/cli/package.json +59 -0
- package/packages/cli/tsconfig.json +9 -0
- package/packages/shared/index.ts +6 -0
- package/packages/shared/package.json +45 -0
- package/packages/shared/src/cli-progress.ts +3 -0
- package/packages/shared/src/commands/cli-all-commands.ts +6 -0
- package/packages/shared/src/commands/version-command.ts +12 -0
- package/packages/shared/src/consola.ts +1 -0
- package/packages/shared/src/open.ts +3 -0
- package/packages/shared/src/unzip.ts +15 -0
- package/packages/shared/tsconfig.json +9 -0
- package/packages/theme/bin/dev.js +5 -0
- package/packages/theme/bin/run.cmd +3 -0
- package/packages/theme/bin/run.js +5 -0
- package/packages/theme/index.ts +21 -0
- package/packages/theme/jest.config.ts +3 -0
- package/packages/theme/package.json +66 -0
- package/packages/theme/src/commands/theme/create.ts +51 -0
- package/packages/theme/src/commands/theme/delete-site.ts +30 -0
- package/packages/theme/src/commands/theme/delete-theme.ts +39 -0
- package/packages/theme/src/commands/theme/dev.ts +47 -0
- package/packages/theme/src/commands/theme/pull.ts +26 -0
- package/packages/theme/src/enums.ts +55 -0
- package/packages/theme/src/services/ClientCredentials.ts +127 -0
- package/packages/theme/src/services/Constants.ts +19 -0
- package/packages/theme/src/services/CreateTheme.ts +88 -0
- package/packages/theme/src/services/DeleteSite.ts +30 -0
- package/packages/theme/src/services/DeleteTheme.ts +46 -0
- package/packages/theme/src/services/FileManager.ts +62 -0
- package/packages/theme/src/services/Request.ts +18 -0
- package/packages/theme/src/services/StartTheme.ts +363 -0
- package/packages/theme/src/services/SyncTheme.ts +108 -0
- package/packages/theme/src/services/ThemeManager.ts +118 -0
- package/packages/theme/src/services/Tsoft.ts +151 -0
- package/packages/theme/src/services/types.ts +90 -0
- package/packages/theme/src/types.ts +20 -0
- package/packages/theme/src/utils/screen.ts +28 -0
- package/packages/theme/src/utils/utils.ts +83 -0
- package/packages/theme/tests/FileManager.test.js +90 -0
- package/packages/theme/tsconfig.json +9 -0
- package/pnpm-workspace.yaml +2 -0
- package/pull_request_template.md +5 -0
- package/scripts/prebuild.js +45 -0
- package/scripts/versions.js +70 -0
- package/tsconfig.build.json +21 -0
- package/bin/index.js +0 -77
- package/jest.config.js +0 -3
- package/src/Tsoft.js +0 -137
- package/src/commands/CreateCommand.js +0 -102
- package/src/commands/StartCommand.js +0 -281
- package/src/commands/SyncCommand.js +0 -97
- package/src/core/ClientCredentials.js +0 -107
- package/src/core/Constants.js +0 -19
- package/src/core/FileManager.js +0 -53
- package/src/core/Request.js +0 -41
- package/src/core/ThemeManager.js +0 -113
- package/src/core/Utils.js +0 -104
- package/tests/FileManager.test.js +0 -90
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
import { consola } from '@tsoft-cli/shared'
|
|
3
|
+
import { ClientCredentials } from './ClientCredentials.js'
|
|
4
|
+
import { Constants } from './Constants.js'
|
|
5
|
+
import { FileManager } from './FileManager.js'
|
|
6
|
+
import { ThemeManager } from './ThemeManager.js'
|
|
7
|
+
import { Request } from './Request.js'
|
|
8
|
+
import type { TUpdateThemeResponse } from '../types.js'
|
|
9
|
+
import type { TClientCredentialsRecoveryData } from './types.js'
|
|
10
|
+
import { themeFileNames } from '../enums.js'
|
|
11
|
+
|
|
12
|
+
export class Tsoft {
|
|
13
|
+
public site: string
|
|
14
|
+
public themeManager: ThemeManager
|
|
15
|
+
public fileManager: FileManager
|
|
16
|
+
public clientCredentials: ClientCredentials
|
|
17
|
+
private TSOFT_CLI_UUID = '7583a318-8542-4ec8-980c-48ea67031be3'
|
|
18
|
+
private ONLINESTORE_SAVE_URI = 'api/v3/admin/online-store-2/theme/file-manager?q=save'
|
|
19
|
+
private ONLINESTORE_DELETE_URI = 'api/v3/admin/online-store-2/theme/file-manager?q=delete'
|
|
20
|
+
private UPDATE_THEME_URI = 'api/v3/admin/online-store-2/theme/update-theme'
|
|
21
|
+
|
|
22
|
+
constructor(site: string) {
|
|
23
|
+
this.site = site
|
|
24
|
+
this.themeManager = new ThemeManager(site)
|
|
25
|
+
this.fileManager = new FileManager(site)
|
|
26
|
+
this.clientCredentials = new ClientCredentials(site)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async initialize(theme: string, reInit: boolean = false) {
|
|
30
|
+
await this.themeManager.initializeTheme(theme, reInit)
|
|
31
|
+
if (!this.themeManager.isRegistered()) {
|
|
32
|
+
return this.register(this.TSOFT_CLI_UUID, this.themeManager.getThemeInfo(theme))
|
|
33
|
+
} else {
|
|
34
|
+
consola.warn('You are already registered')
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
buildEnvironment() {
|
|
39
|
+
this.themeManager.buildEnvironment(this.clientCredentials.getEnvironment())
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async authorize() {
|
|
43
|
+
await this.clientCredentials.authorize()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async register(CLIENT_UUID: string, clientConfiguration = {}) {
|
|
47
|
+
const response = await this.clientCredentials.register(CLIENT_UUID, clientConfiguration)
|
|
48
|
+
return response === true ? Constants.APPROVAL : null
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async saveOnlineStore(theme: string) {
|
|
52
|
+
const fileList = this.fileManager.listFilesRecursive(path.join(process.cwd(), this.site, theme))
|
|
53
|
+
|
|
54
|
+
await Promise.all(
|
|
55
|
+
fileList
|
|
56
|
+
.filter((file) => !file.includes(themeFileNames.env))
|
|
57
|
+
.map(async (file) => {
|
|
58
|
+
const fileName = this.fileManager.getRelativePath(theme, file)
|
|
59
|
+
const content = this.fileManager.readFile(file)
|
|
60
|
+
const env = this.themeManager.getEnvironment(theme)
|
|
61
|
+
|
|
62
|
+
await Request.request(this.site, this.ONLINESTORE_SAVE_URI, {
|
|
63
|
+
method: 'POST',
|
|
64
|
+
headers: {
|
|
65
|
+
Authorization: `Bearer ${env.bearer}`,
|
|
66
|
+
Accept: 'application/json',
|
|
67
|
+
'Content-Type': 'application/json',
|
|
68
|
+
},
|
|
69
|
+
data: {
|
|
70
|
+
theme: theme,
|
|
71
|
+
path: fileName,
|
|
72
|
+
content: content,
|
|
73
|
+
},
|
|
74
|
+
})
|
|
75
|
+
}),
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async saveFile(theme: string, fileName: string, content: string, bearerToken: string) {
|
|
80
|
+
return Request.request(this.site, this.ONLINESTORE_SAVE_URI, {
|
|
81
|
+
method: 'POST',
|
|
82
|
+
headers: {
|
|
83
|
+
Authorization: `Bearer ${bearerToken}`,
|
|
84
|
+
Accept: 'application/json',
|
|
85
|
+
'Content-Type': 'application/json',
|
|
86
|
+
},
|
|
87
|
+
data: {
|
|
88
|
+
theme: theme,
|
|
89
|
+
path: fileName,
|
|
90
|
+
content: content,
|
|
91
|
+
},
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async deleteFile(theme: string, fileName: string, bearerToken: string) {
|
|
96
|
+
return Request.request(this.site, this.ONLINESTORE_DELETE_URI, {
|
|
97
|
+
method: 'POST',
|
|
98
|
+
headers: {
|
|
99
|
+
Authorization: `Bearer ${bearerToken}`,
|
|
100
|
+
Accept: 'application/json',
|
|
101
|
+
'Content-Type': 'application/json',
|
|
102
|
+
},
|
|
103
|
+
data: {
|
|
104
|
+
theme: theme,
|
|
105
|
+
items: [{ type: 'file', path: fileName }],
|
|
106
|
+
},
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async deleteDirectory(theme: string, folderName: string, bearerToken: string) {
|
|
111
|
+
return Request.request(this.site, this.ONLINESTORE_DELETE_URI, {
|
|
112
|
+
method: 'POST',
|
|
113
|
+
headers: {
|
|
114
|
+
Authorization: `Bearer ${bearerToken}`,
|
|
115
|
+
Accept: 'application/json',
|
|
116
|
+
'Content-Type': 'application/json',
|
|
117
|
+
},
|
|
118
|
+
data: {
|
|
119
|
+
theme: theme,
|
|
120
|
+
items: [{ type: 'dir', path: folderName }],
|
|
121
|
+
},
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async isTokenValid(theme: string) {
|
|
126
|
+
const env = this.themeManager.getEnvironment(theme)
|
|
127
|
+
return this.clientCredentials.validateToken(env.bearer)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async updateTheme(directoryName: string) {
|
|
131
|
+
const env = this.themeManager.getEnvironment(directoryName)
|
|
132
|
+
const themeInfo = this.themeManager.getThemeInfo(directoryName) // .theme bilgisi alınıyor
|
|
133
|
+
|
|
134
|
+
return Request.request<TUpdateThemeResponse>(this.site, this.UPDATE_THEME_URI, {
|
|
135
|
+
method: 'POST',
|
|
136
|
+
headers: {
|
|
137
|
+
Authorization: `Bearer ${env.bearer}`,
|
|
138
|
+
Accept: 'application/json',
|
|
139
|
+
'Content-Type': 'application/json',
|
|
140
|
+
},
|
|
141
|
+
data: {
|
|
142
|
+
theme: directoryName,
|
|
143
|
+
themeInfo: themeInfo,
|
|
144
|
+
},
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async startRecovery(token: string): Promise<TClientCredentialsRecoveryData> {
|
|
149
|
+
return this.clientCredentials.recovery(token)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
export type TClientCredentialsGetEnvironment = {
|
|
2
|
+
site: string
|
|
3
|
+
clientId: string
|
|
4
|
+
clientSecret: string
|
|
5
|
+
bearer: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type TThemeFile = {
|
|
9
|
+
site: string
|
|
10
|
+
name: string
|
|
11
|
+
author: string
|
|
12
|
+
version: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type TAuthorizeResponse = {
|
|
16
|
+
status: boolean
|
|
17
|
+
message: string
|
|
18
|
+
data: {
|
|
19
|
+
token: {
|
|
20
|
+
accessToken: {
|
|
21
|
+
name: string
|
|
22
|
+
abilities: string[]
|
|
23
|
+
expires_at: null
|
|
24
|
+
tokenable_id: number
|
|
25
|
+
tokenable_type: string
|
|
26
|
+
ip_address: string
|
|
27
|
+
updated_at: string
|
|
28
|
+
created_at: string
|
|
29
|
+
id: number
|
|
30
|
+
}
|
|
31
|
+
plainTextToken: string
|
|
32
|
+
}
|
|
33
|
+
tokenable?: {
|
|
34
|
+
name: string
|
|
35
|
+
author: string
|
|
36
|
+
version: string
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
attributes: {
|
|
40
|
+
'system.status': {
|
|
41
|
+
event: string
|
|
42
|
+
message: string
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export type TAuthMeResponse = {
|
|
48
|
+
status: boolean
|
|
49
|
+
message: string
|
|
50
|
+
data: {
|
|
51
|
+
id: number
|
|
52
|
+
name: string
|
|
53
|
+
is_active: number
|
|
54
|
+
}
|
|
55
|
+
attributes: {
|
|
56
|
+
'system.status': {
|
|
57
|
+
event: string
|
|
58
|
+
message: string
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export type TAuthApplication = {
|
|
64
|
+
status: boolean
|
|
65
|
+
message: string
|
|
66
|
+
data: {
|
|
67
|
+
public_key: string
|
|
68
|
+
}
|
|
69
|
+
attributes: {
|
|
70
|
+
'system.status': {
|
|
71
|
+
event: string
|
|
72
|
+
message: string
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export type TClientCredentialsRecoveryResponse = {
|
|
78
|
+
status: boolean
|
|
79
|
+
data: {
|
|
80
|
+
secret: string
|
|
81
|
+
public_key: string
|
|
82
|
+
}
|
|
83
|
+
throttle?: {
|
|
84
|
+
limit: string
|
|
85
|
+
retryAfter: string
|
|
86
|
+
resetDate: string
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export type TClientCredentialsRecoveryData = Pick<TClientCredentialsRecoveryResponse['data'], 'public_key' | 'secret'>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { allowedExtensions, menuSelections, themeTypes } from './enums.js'
|
|
2
|
+
|
|
3
|
+
export type ValueOf<T> = T[keyof T]
|
|
4
|
+
|
|
5
|
+
export type TMainMenuSelections = ValueOf<typeof menuSelections>
|
|
6
|
+
|
|
7
|
+
export type TUpdateThemeResponse = {
|
|
8
|
+
status: boolean
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type TThemeEnviroments = {
|
|
12
|
+
site: string
|
|
13
|
+
clientId: string
|
|
14
|
+
clientSecret: string
|
|
15
|
+
bearer: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type TThemeTypes = ValueOf<typeof themeTypes>
|
|
19
|
+
|
|
20
|
+
export type TAllowedExtensions = (typeof allowedExtensions)[number]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import figlet from 'figlet'
|
|
2
|
+
import { consola } from '@tsoft-cli/shared'
|
|
3
|
+
import { packageJson } from '../enums.js'
|
|
4
|
+
|
|
5
|
+
export async function displayAsciiArt(): Promise<void> {
|
|
6
|
+
return new Promise<void>((resolve, reject) => {
|
|
7
|
+
figlet(
|
|
8
|
+
'T-SOFT CLI',
|
|
9
|
+
{
|
|
10
|
+
font: 'Standard',
|
|
11
|
+
},
|
|
12
|
+
(err, data) => {
|
|
13
|
+
if (err) {
|
|
14
|
+
consola.error(err)
|
|
15
|
+
return reject(err)
|
|
16
|
+
}
|
|
17
|
+
consola.log(data)
|
|
18
|
+
return resolve()
|
|
19
|
+
},
|
|
20
|
+
)
|
|
21
|
+
}).then(() => {
|
|
22
|
+
consola.info('Versiyon: ' + packageJson.version)
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function clearScreen(): void {
|
|
27
|
+
process.stdout.write('\x1B[2J\x1B[0f')
|
|
28
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { themeFileNames } from '../enums.js'
|
|
4
|
+
import type { TThemeFile } from '../services/types.js'
|
|
5
|
+
|
|
6
|
+
export function getNonThemeFolders(): string[] {
|
|
7
|
+
return ['node_modules', 'build', 'dist']
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function checkThemeSiteFolder(value: string): boolean {
|
|
11
|
+
return new RegExp(/\b\w+\.com(\.tr)?\b/g).test(value)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function getLocalSites(opt: { cwd?: string } = {}): string[] {
|
|
15
|
+
const cwd = opt.cwd ?? process.cwd()
|
|
16
|
+
|
|
17
|
+
return fs
|
|
18
|
+
.readdirSync(cwd)
|
|
19
|
+
.filter((file) => {
|
|
20
|
+
const filePath = path.join(cwd, file)
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
checkThemeSiteFolder(file) &&
|
|
24
|
+
fs.statSync(filePath).isDirectory() &&
|
|
25
|
+
fs.existsSync(path.join(filePath, themeFileNames.tsoft))
|
|
26
|
+
)
|
|
27
|
+
})
|
|
28
|
+
.filter((file) => fs.statSync(path.join(cwd, file)).isDirectory())
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function slugify(text: string): string {
|
|
32
|
+
return text
|
|
33
|
+
.toString()
|
|
34
|
+
.toLowerCase()
|
|
35
|
+
.replace(/\s+/g, '-')
|
|
36
|
+
.replace(/[^\w\-]+/g, '')
|
|
37
|
+
.replace(/\-\-+/g, '-')
|
|
38
|
+
.replace(/^-+/, '')
|
|
39
|
+
.replace(/-+$/, '')
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function getPlatform(): NodeJS.Platform {
|
|
43
|
+
return process.platform
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function getFolderFromCWD(...paths: string[]): string {
|
|
47
|
+
return path.join(process.cwd(), ...paths)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function getDirectories(source: string): string[] {
|
|
51
|
+
return fs
|
|
52
|
+
.readdirSync(source)
|
|
53
|
+
.filter((file) => checkThemeSiteFolder(file))
|
|
54
|
+
.filter((file) => fs.statSync(path.join(source, file)).isDirectory())
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function getThemesFromFolder(source: string): string[] {
|
|
58
|
+
return fs
|
|
59
|
+
.readdirSync(source)
|
|
60
|
+
.filter((file) => file.charAt(0) !== '.' && !getNonThemeFolders().includes(file))
|
|
61
|
+
.filter((file) => fs.statSync(path.join(source, file)).isDirectory())
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function getOpenFilePlatformCode() {
|
|
65
|
+
return getPlatform() == 'win32' ? 'start' : getPlatform() == 'darwin' ? 'open' : 'xdg-open'
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* İşlemlerin düzgün çalışması için ters slash(\) yerine düz slash yapmamız lazım gerekiyor.
|
|
70
|
+
* @param {string} path
|
|
71
|
+
* @returns {string}
|
|
72
|
+
*/
|
|
73
|
+
export function setPathForWebhookOperations(path: string): string {
|
|
74
|
+
return path.replace(/\\/g, '/')
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function saveThemeData(themePath: string, themeData: TThemeFile): void {
|
|
78
|
+
fs.writeFileSync(path.join(themePath, themeFileNames.theme), JSON.stringify(themeData, null, 2))
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function saveThemeTxt(themePath: string, themeData: TThemeFile): void {
|
|
82
|
+
fs.writeFileSync(path.join(themePath, themeFileNames.themeTxt), JSON.stringify(themeData, null, 2))
|
|
83
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
const path = require('node: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
|
+
})
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Her build alma işleminden önce paketlerin içindeki build klasörlerini siler.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import fs from 'node:fs'
|
|
6
|
+
import path from 'node:path'
|
|
7
|
+
|
|
8
|
+
const cwd = process.cwd()
|
|
9
|
+
const packages = 'packages'
|
|
10
|
+
const build = 'build'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Packages içindeki klasör isimlerini alır.
|
|
14
|
+
* @param {string} source
|
|
15
|
+
* @returns {string[]} cli, shared, ...
|
|
16
|
+
*/
|
|
17
|
+
function getPackagesFolder(source) {
|
|
18
|
+
return fs.readdirSync(source).filter((file) => fs.statSync(path.join(source, file)).isDirectory())
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Packages klasörü içindeki paketlerin build dosyalarını siler.
|
|
23
|
+
* @param {string} pkgName
|
|
24
|
+
*/
|
|
25
|
+
function removeBuildFiles(pkgName) {
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
fs.rm(path.join(cwd, packages, pkgName, build), { recursive: true, force: true }, (err) => {
|
|
28
|
+
if (err) {
|
|
29
|
+
return reject(err)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return resolve()
|
|
33
|
+
})
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function start() {
|
|
38
|
+
const packagesFolderNames = getPackagesFolder(path.join(cwd, packages))
|
|
39
|
+
|
|
40
|
+
for (const pkgName of packagesFolderNames) {
|
|
41
|
+
removeBuildFiles(pkgName)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
start()
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Her build alma işleminden sonra package.json içindeki bağımlılıklardan versiyonu workspace:* olanların gerçek versiyonlarını yerine yazar.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import fs from 'node:fs'
|
|
6
|
+
import path from 'node:path'
|
|
7
|
+
|
|
8
|
+
const cwd = process.cwd()
|
|
9
|
+
const packages = 'packages'
|
|
10
|
+
const packageJSON = 'package.json'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Packages içindeki klasör isimlerini alır.
|
|
14
|
+
* @param {string} source
|
|
15
|
+
* @returns {string[]} cli, shared, ...
|
|
16
|
+
*/
|
|
17
|
+
function getPackagesFolder(source) {
|
|
18
|
+
return fs.readdirSync(source).filter((file) => fs.statSync(path.join(source, file)).isDirectory())
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Packages klasörü içindeki package.json dosyalarını alır.
|
|
23
|
+
* @param {string} pkgName
|
|
24
|
+
* @returns {string}
|
|
25
|
+
*/
|
|
26
|
+
function getPackagesPackageJsons(pkgName) {
|
|
27
|
+
return fs.readFileSync(path.join(cwd, packages, pkgName, packageJSON)).toString()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Packages klasörü içindeki paketlerin package.json dosyalarını değiştirir.
|
|
32
|
+
* @param {string} pkgName
|
|
33
|
+
* @param {string} data
|
|
34
|
+
*/
|
|
35
|
+
function setPackagesPackageJsons(pkgName, data) {
|
|
36
|
+
return fs.writeFileSync(path.join(cwd, packages, pkgName, packageJSON), JSON.stringify(data, null, 2))
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let packageStore = []
|
|
40
|
+
|
|
41
|
+
function start() {
|
|
42
|
+
const packagesFolderNames = getPackagesFolder(path.join(cwd, packages))
|
|
43
|
+
|
|
44
|
+
//Packages içindeki paketlerin isimlerini ve versiyonları aldık.
|
|
45
|
+
for (const pkgName of packagesFolderNames) {
|
|
46
|
+
const parsedPackageJSON = JSON.parse(getPackagesPackageJsons(pkgName))
|
|
47
|
+
packageStore.push({
|
|
48
|
+
name: parsedPackageJSON.name,
|
|
49
|
+
version: parsedPackageJSON.version,
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
//Packages içindeki paketlerin gerçek versiyonlarını bağımlılıklarda düzenledik.
|
|
54
|
+
for (const pkgName of packagesFolderNames) {
|
|
55
|
+
const parsedPackageJSON = JSON.parse(getPackagesPackageJsons(pkgName))
|
|
56
|
+
|
|
57
|
+
for (const pkg of packageStore) {
|
|
58
|
+
if (parsedPackageJSON.dependencies && parsedPackageJSON.dependencies[pkg.name]) {
|
|
59
|
+
parsedPackageJSON.dependencies[pkg.name] = pkg.version
|
|
60
|
+
}
|
|
61
|
+
if (parsedPackageJSON.devDependencies && parsedPackageJSON.devDependencies[pkg.name]) {
|
|
62
|
+
parsedPackageJSON.devDependencies[pkg.name] = pkg.version
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
setPackagesPackageJsons(pkgName, parsedPackageJSON)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
start()
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"esModuleInterop": true,
|
|
7
|
+
"allowSyntheticDefaultImports": true,
|
|
8
|
+
"sourceMap": true,
|
|
9
|
+
"outDir": "build",
|
|
10
|
+
"resolveJsonModule": true,
|
|
11
|
+
"declaration": true,
|
|
12
|
+
"noImplicitAny": true,
|
|
13
|
+
"strictNullChecks": false,
|
|
14
|
+
"skipLibCheck": true,
|
|
15
|
+
"forceConsistentCasingInFileNames": true,
|
|
16
|
+
"lib": [ "ESNext" ],
|
|
17
|
+
},
|
|
18
|
+
"ts-node": {
|
|
19
|
+
"esm": true
|
|
20
|
+
}
|
|
21
|
+
}
|
package/bin/index.js
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const { Select } = require('enquirer');
|
|
4
|
-
const StartCommand = require('../src/commands/StartCommand');
|
|
5
|
-
const SyncCommand = require('../src/commands/SyncCommand');
|
|
6
|
-
const CreateCommand = require('../src/commands/CreateCommand');
|
|
7
|
-
const { clearScreen, displayAsciiArt, getSites } = require('../src/core/Utils');
|
|
8
|
-
const fs = require('fs');
|
|
9
|
-
const path = require('path');
|
|
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
|
-
|
|
27
|
-
async function selectSiteAndTheme() {
|
|
28
|
-
const cwd = process.cwd();
|
|
29
|
-
const sites = await getSites({
|
|
30
|
-
cwd: cwd
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
if (sites.length === 0) {
|
|
34
|
-
console.error('Mevcut dizinde site bulunamadı.');
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const selectedSite = await selectFromChoices('Bir site seçin:', sites);
|
|
39
|
-
const themes = await getDirectories(path.join(cwd, selectedSite));
|
|
40
|
-
|
|
41
|
-
if (themes.length === 0) {
|
|
42
|
-
console.error('Seçilen site dizininde tema bulunamadı.');
|
|
43
|
-
return null;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const selectedTheme = await selectFromChoices('Bir tema seçin:', themes);
|
|
47
|
-
|
|
48
|
-
return { siteName: selectedSite, themeName: selectedTheme };
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async function showMainMenu() {
|
|
52
|
-
clearScreen();
|
|
53
|
-
await displayAsciiArt();
|
|
54
|
-
|
|
55
|
-
const commandChoices = ['Yeni bir tema oluştur', 'Geliştirme ortamını başlat', 'Uzak sunucudan dosyaları indir', 'Çıkış'];
|
|
56
|
-
const selectedCommand = await selectFromChoices('Bir komut seçin:', commandChoices);
|
|
57
|
-
|
|
58
|
-
switch (selectedCommand) {
|
|
59
|
-
case 'Yeni bir tema oluştur':
|
|
60
|
-
await CreateCommand.createTheme();
|
|
61
|
-
break;
|
|
62
|
-
case 'Geliştirme ortamını başlat':
|
|
63
|
-
const selection = await selectSiteAndTheme();
|
|
64
|
-
if (selection) {
|
|
65
|
-
await StartCommand.start(selection.siteName, selection.themeName);
|
|
66
|
-
}
|
|
67
|
-
break;
|
|
68
|
-
case 'Uzak sunucudan dosyaları indir':
|
|
69
|
-
await SyncCommand.syncTheme();
|
|
70
|
-
break;
|
|
71
|
-
case 'Çıkış':
|
|
72
|
-
console.log('Programdan çıkılıyor. Hoşça kalın!');
|
|
73
|
-
process.exit(0);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
showMainMenu();
|